TTSnapValues.cpp 95 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946
  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 "RuntimeDebugPch.h"
  6. #if ENABLE_TTD
  7. #include "ByteCode/ByteCodeSerializer.h"
  8. namespace TTD
  9. {
  10. namespace JsSupport
  11. {
  12. bool IsVarTaggedInline(Js::Var v)
  13. {
  14. return Js::TaggedNumber::Is(v);
  15. }
  16. bool IsVarPtrValued(Js::Var v)
  17. {
  18. return !Js::TaggedNumber::Is(v);
  19. }
  20. bool IsVarPrimitiveKind(Js::Var v)
  21. {
  22. if(Js::TaggedNumber::Is(v))
  23. {
  24. return false;
  25. }
  26. Js::TypeId tid = Js::RecyclableObject::FromVar(v)->GetTypeId();
  27. return tid <= Js::TypeIds_LastToPrimitiveType;
  28. }
  29. bool IsVarComplexKind(Js::Var v)
  30. {
  31. if(Js::TaggedNumber::Is(v))
  32. {
  33. return false;
  34. }
  35. Js::TypeId tid = Js::RecyclableObject::FromVar(v)->GetTypeId();
  36. return tid > Js::TypeIds_LastToPrimitiveType;
  37. }
  38. #if ENABLE_TTD_INTERNAL_DIAGNOSTICS
  39. bool AreInlineVarsEquiv(Js::Var v1, Js::Var v2)
  40. {
  41. if(v1 == v2)
  42. {
  43. return true; //same bit pattern so no problem
  44. }
  45. if(v1 == nullptr || v2 == nullptr)
  46. {
  47. return false; //then they should be the same per above
  48. }
  49. if(Js::TaggedNumber::Is(v1) != Js::TaggedNumber::Is(v2))
  50. {
  51. return false;
  52. }
  53. double v1val = Js::TaggedInt::Is(v1) ? Js::TaggedInt::ToInt32(v1) : Js::JavascriptNumber::GetValue(v1);
  54. double v2val = Js::TaggedInt::Is(v2) ? Js::TaggedInt::ToInt32(v2) : Js::JavascriptNumber::GetValue(v2);
  55. if(Js::JavascriptNumber::IsNan(v1val) != Js::JavascriptNumber::IsNan(v2val))
  56. {
  57. return false;
  58. }
  59. return v1val == v2val;
  60. }
  61. #endif
  62. Js::FunctionBody* ForceAndGetFunctionBody(Js::ParseableFunctionInfo* pfi)
  63. {
  64. Js::FunctionBody* fb = nullptr;
  65. if(pfi->IsDeferredDeserializeFunction())
  66. {
  67. Js::DeferDeserializeFunctionInfo* deferDeserializeInfo = pfi->GetDeferDeserializeFunctionInfo();
  68. fb = deferDeserializeInfo->Deserialize();
  69. }
  70. else
  71. {
  72. if(pfi->IsDeferredParseFunction())
  73. {
  74. fb = pfi->GetParseableFunctionInfo()->Parse();
  75. }
  76. else
  77. {
  78. fb = pfi->GetFunctionBody();
  79. }
  80. }
  81. TTDAssert(fb != nullptr, "I just want a function body!!!");
  82. fb->EnsureDeserialized();
  83. return fb;
  84. }
  85. void WriteCodeToFile(ThreadContext* threadContext, bool fromEvent, uint32 bodyId, bool isUtf8Source, byte* sourceBuffer, uint32 length)
  86. {
  87. char asciiResourceName[64];
  88. sprintf_s(asciiResourceName, 64, "src%s_%I32u.js", (fromEvent ? "_ld" : ""), bodyId);
  89. TTDataIOInfo& iofp = threadContext->TTDContext->TTDataIOInfo;
  90. JsTTDStreamHandle srcStream = iofp.pfOpenResourceStream(iofp.ActiveTTUriLength, iofp.ActiveTTUri, strlen(asciiResourceName), asciiResourceName, false, true);
  91. TTDAssert(srcStream != nullptr, "Failed to open code resource stream for writing.");
  92. if(isUtf8Source)
  93. {
  94. byte byteOrderArray[3] = { 0xEF, 0xBB, 0xBF };
  95. size_t byteOrderCount = 0;
  96. bool okBOC = iofp.pfWriteBytesToStream(srcStream, byteOrderArray, _countof(byteOrderArray), &byteOrderCount);
  97. TTDAssert(okBOC && byteOrderCount == _countof(byteOrderArray), "Write Failed!!!");
  98. }
  99. else
  100. {
  101. byte byteOrderArray[2] = { 0xFF, 0xFE };
  102. size_t byteOrderCount = 0;
  103. bool okBOC = iofp.pfWriteBytesToStream(srcStream, byteOrderArray, _countof(byteOrderArray), &byteOrderCount);
  104. TTDAssert(okBOC && byteOrderCount == _countof(byteOrderArray), "Write Failed!!!");
  105. }
  106. size_t writtenCount = 0;
  107. bool ok = iofp.pfWriteBytesToStream(srcStream, sourceBuffer, length, &writtenCount);
  108. TTDAssert(ok && writtenCount == length, "Write Failed!!!");
  109. iofp.pfFlushAndCloseStream(srcStream, false, true);
  110. }
  111. void ReadCodeFromFile(ThreadContext* threadContext, bool fromEvent, uint32 bodyId, bool isUtf8Source, byte* sourceBuffer, uint32 length)
  112. {
  113. char asciiResourceName[64];
  114. sprintf_s(asciiResourceName, 64, "src%s_%I32u.js", (fromEvent ? "_ld" : ""), bodyId);
  115. TTDataIOInfo& iofp = threadContext->TTDContext->TTDataIOInfo;
  116. JsTTDStreamHandle srcStream = iofp.pfOpenResourceStream(iofp.ActiveTTUriLength, iofp.ActiveTTUri, strlen(asciiResourceName), asciiResourceName, true, false);
  117. TTDAssert(srcStream != nullptr, "Failed to open code resource stream for reading.");
  118. if(isUtf8Source)
  119. {
  120. byte byteOrderArray[3] = { 0x0, 0x0, 0x0 };
  121. size_t byteOrderCount = 0;
  122. bool okBOC = iofp.pfReadBytesFromStream(srcStream, byteOrderArray, _countof(byteOrderArray), &byteOrderCount);
  123. TTDAssert(okBOC && byteOrderCount == _countof(byteOrderArray) && byteOrderArray[0] == 0xEF && byteOrderArray[1] == 0xBB && byteOrderArray[2] == 0xBF, "Read Failed!!!");
  124. }
  125. else
  126. {
  127. byte byteOrderArray[2] = { 0x0, 0x0 };
  128. size_t byteOrderCount = 0;
  129. bool okBOC = iofp.pfReadBytesFromStream(srcStream, byteOrderArray, _countof(byteOrderArray), &byteOrderCount);
  130. TTDAssert(okBOC && byteOrderCount == _countof(byteOrderArray) && byteOrderArray[0] == 0xFF && byteOrderArray[1] == 0xFE, "Read Failed!!!");
  131. }
  132. size_t readCount = 0;
  133. bool ok = iofp.pfReadBytesFromStream(srcStream, sourceBuffer, length, &readCount);
  134. TTDAssert(ok && readCount == length, "Read Failed!!!");
  135. iofp.pfFlushAndCloseStream(srcStream, true, false);
  136. }
  137. }
  138. namespace NSSnapValues
  139. {
  140. void EmitTTDVar(TTDVar var, FileWriter* writer, NSTokens::Separator separator)
  141. {
  142. writer->WriteRecordStart(separator);
  143. if(var == nullptr)
  144. {
  145. writer->WriteTag<TTDVarEmitTag>(NSTokens::Key::ttdVarTag, TTDVarEmitTag::TTDVarNull);
  146. writer->WriteNull(NSTokens::Key::nullVal, NSTokens::Separator::CommaSeparator);
  147. }
  148. else if(Js::TaggedNumber::Is(var))
  149. {
  150. #if FLOATVAR
  151. if(Js::TaggedInt::Is(var))
  152. {
  153. #endif
  154. writer->WriteTag<TTDVarEmitTag>(NSTokens::Key::ttdVarTag, TTDVarEmitTag::TTDVarInt);
  155. writer->WriteInt32(NSTokens::Key::i32Val, Js::TaggedInt::ToInt32(var), NSTokens::Separator::CommaSeparator);
  156. #if FLOATVAR
  157. }
  158. else
  159. {
  160. TTDAssert(Js::JavascriptNumber::Is_NoTaggedIntCheck(var), "Only other tagged value we support!!!");
  161. writer->WriteTag<TTDVarEmitTag>(NSTokens::Key::ttdVarTag, TTDVarEmitTag::TTDVarDouble);
  162. writer->WriteDouble(NSTokens::Key::doubleVal, Js::JavascriptNumber::GetValue(var), NSTokens::Separator::CommaSeparator);
  163. }
  164. #endif
  165. }
  166. else
  167. {
  168. writer->WriteTag<TTDVarEmitTag>(NSTokens::Key::ttdVarTag, TTDVarEmitTag::TTDVarAddr);
  169. writer->WriteAddr(NSTokens::Key::ptrIdVal, TTD_CONVERT_VAR_TO_PTR_ID(var), NSTokens::Separator::CommaSeparator);
  170. }
  171. writer->WriteRecordEnd();
  172. }
  173. TTDVar ParseTTDVar(bool readSeparator, FileReader* reader)
  174. {
  175. reader->ReadRecordStart(readSeparator);
  176. TTDVar res = nullptr;
  177. TTDVarEmitTag tag = reader->ReadTag<TTDVarEmitTag>(NSTokens::Key::ttdVarTag);
  178. if(tag == TTDVarEmitTag::TTDVarNull)
  179. {
  180. reader->ReadNull(NSTokens::Key::nullVal, true);
  181. res = nullptr;
  182. }
  183. else if(tag == TTDVarEmitTag::TTDVarInt)
  184. {
  185. int32 intVal = reader->ReadInt32(NSTokens::Key::i32Val, true);
  186. res = Js::TaggedInt::ToVarUnchecked(intVal);
  187. }
  188. #if FLOATVAR
  189. else if(tag == TTDVarEmitTag::TTDVarDouble)
  190. {
  191. double doubleVal = reader->ReadDouble(NSTokens::Key::doubleVal, true);
  192. res = Js::JavascriptNumber::NewInlined(doubleVal, nullptr);
  193. }
  194. #endif
  195. else
  196. {
  197. TTDAssert(tag == TTDVarEmitTag::TTDVarAddr, "Is there something else?");
  198. TTD_PTR_ID addrVal = reader->ReadAddr(NSTokens::Key::ptrIdVal, true);
  199. res = TTD_COERCE_PTR_ID_TO_VAR(addrVal);
  200. }
  201. reader->ReadRecordEnd();
  202. return res;
  203. }
  204. #if ENABLE_SNAPSHOT_COMPARE
  205. bool CheckSnapEquivTTDDouble(double d1, double d2)
  206. {
  207. if(Js::JavascriptNumber::IsNan(d1) || Js::JavascriptNumber::IsNan(d2))
  208. {
  209. return (Js::JavascriptNumber::IsNan(d1) && Js::JavascriptNumber::IsNan(d2));
  210. }
  211. else
  212. {
  213. return (d1 == d2);
  214. }
  215. }
  216. void AssertSnapEquivTTDVar_Helper(const TTDVar v1, const TTDVar v2, TTDCompareMap& compareMap, TTDComparePath::StepKind stepKind, const TTDComparePath::PathEntry& next)
  217. {
  218. if(v1 == nullptr || v2 == nullptr)
  219. {
  220. compareMap.DiagnosticAssert(v1 == v2);
  221. }
  222. else if(Js::TaggedNumber::Is(v1) || Js::TaggedNumber::Is(v2))
  223. {
  224. compareMap.DiagnosticAssert(JsSupport::AreInlineVarsEquiv(v1, v2));
  225. }
  226. else
  227. {
  228. compareMap.CheckConsistentAndAddPtrIdMapping_Helper(TTD_CONVERT_VAR_TO_PTR_ID(v1), TTD_CONVERT_VAR_TO_PTR_ID(v2), stepKind, next);
  229. }
  230. }
  231. void AssertSnapEquivTTDVar_Property(const TTDVar v1, const TTDVar v2, TTDCompareMap& compareMap, Js::PropertyId pid)
  232. {
  233. TTDComparePath::PathEntry next{ (uint32)pid, nullptr };
  234. AssertSnapEquivTTDVar_Helper(v1, v2, compareMap, TTDComparePath::StepKind::PropertyData, next);
  235. }
  236. void AssertSnapEquivTTDVar_PropertyGetter(const TTDVar v1, const TTDVar v2, TTDCompareMap& compareMap, Js::PropertyId pid)
  237. {
  238. TTDComparePath::PathEntry next{ (uint32)pid, nullptr };
  239. AssertSnapEquivTTDVar_Helper(v1, v2, compareMap, TTDComparePath::StepKind::PropertyGetter, next);
  240. }
  241. void AssertSnapEquivTTDVar_PropertySetter(const TTDVar v1, const TTDVar v2, TTDCompareMap& compareMap, Js::PropertyId pid)
  242. {
  243. TTDComparePath::PathEntry next{ (uint32)pid, nullptr };
  244. AssertSnapEquivTTDVar_Helper(v1, v2, compareMap, TTDComparePath::StepKind::PropertySetter, next);
  245. }
  246. void AssertSnapEquivTTDVar_Array(const TTDVar v1, const TTDVar v2, TTDCompareMap& compareMap, uint32 index)
  247. {
  248. TTDComparePath::PathEntry next{ index, nullptr };
  249. AssertSnapEquivTTDVar_Helper(v1, v2, compareMap, TTDComparePath::StepKind::Array, next);
  250. }
  251. void AssertSnapEquivTTDVar_SlotArray(const TTDVar v1, const TTDVar v2, TTDCompareMap& compareMap, uint32 index)
  252. {
  253. TTDComparePath::PathEntry next{ index, nullptr };
  254. AssertSnapEquivTTDVar_Helper(v1, v2, compareMap, TTDComparePath::StepKind::SlotArray, next);
  255. }
  256. void AssertSnapEquivTTDVar_Special(const TTDVar v1, const TTDVar v2, TTDCompareMap& compareMap, const char16* specialField)
  257. {
  258. TTDComparePath::PathEntry next{ -1, specialField };
  259. AssertSnapEquivTTDVar_Helper(v1, v2, compareMap, TTDComparePath::StepKind::Special, next);
  260. }
  261. void AssertSnapEquivTTDVar_SpecialArray(const TTDVar v1, const TTDVar v2, TTDCompareMap& compareMap, const char16* specialField, uint32 index)
  262. {
  263. TTDComparePath::PathEntry next{ index, specialField };
  264. AssertSnapEquivTTDVar_Helper(v1, v2, compareMap, TTDComparePath::StepKind::SpecialArray, next);
  265. }
  266. #endif
  267. //////////////////
  268. void ExtractSnapPrimitiveValue(SnapPrimitiveValue* snapValue, Js::RecyclableObject* jsValue, bool isWellKnown, const TTDIdentifierDictionary<TTD_PTR_ID, NSSnapType::SnapType*>& idToTypeMap, SlabAllocator& alloc)
  269. {
  270. snapValue->PrimitiveValueId = TTD_CONVERT_VAR_TO_PTR_ID(jsValue);
  271. Js::Type* objType = jsValue->GetType();
  272. snapValue->SnapType = idToTypeMap.LookupKnownItem(TTD_CONVERT_TYPEINFO_TO_PTR_ID(objType));
  273. TTD_WELLKNOWN_TOKEN lookupToken = isWellKnown ? jsValue->GetScriptContext()->TTDWellKnownInfo->ResolvePathForKnownObject(jsValue) : TTD_INVALID_WELLKNOWN_TOKEN;
  274. snapValue->OptWellKnownToken = alloc.CopyRawNullTerminatedStringInto(lookupToken);
  275. if(snapValue->OptWellKnownToken == TTD_INVALID_WELLKNOWN_TOKEN)
  276. {
  277. Js::JavascriptLibrary* jslib = jsValue->GetLibrary();
  278. switch(snapValue->SnapType->JsTypeId)
  279. {
  280. case Js::TypeIds_Undefined:
  281. case Js::TypeIds_Null:
  282. break;
  283. case Js::TypeIds_Boolean:
  284. snapValue->u_boolValue = Js::JavascriptBoolean::FromVar(jsValue)->GetValue();
  285. break;
  286. case Js::TypeIds_Number:
  287. snapValue->u_doubleValue = Js::JavascriptNumber::GetValue(jsValue);
  288. break;
  289. case Js::TypeIds_Int64Number:
  290. snapValue->u_int64Value = Js::JavascriptInt64Number::FromVar(jsValue)->GetValue();
  291. break;
  292. case Js::TypeIds_UInt64Number:
  293. snapValue->u_uint64Value = Js::JavascriptUInt64Number::FromVar(jsValue)->GetValue();
  294. break;
  295. case Js::TypeIds_String:
  296. snapValue->u_stringValue = alloc.SlabAllocateStruct<TTString>();
  297. alloc.CopyStringIntoWLength(Js::JavascriptString::FromVar(jsValue)->GetSz(), Js::JavascriptString::FromVar(jsValue)->GetLength(), *(snapValue->u_stringValue));
  298. break;
  299. case Js::TypeIds_Symbol:
  300. snapValue->u_propertyIdValue = jslib->ExtractPrimitveSymbolId_TTD(jsValue);
  301. break;
  302. default:
  303. TTDAssert(false, "These are supposed to be primitive values on the heap e.g., no pointers or properties.");
  304. break;
  305. }
  306. }
  307. }
  308. void InflateSnapPrimitiveValue(const SnapPrimitiveValue* snapValue, InflateMap* inflator)
  309. {
  310. Js::ScriptContext* ctx = inflator->LookupScriptContext(snapValue->SnapType->ScriptContextLogId);
  311. Js::JavascriptLibrary* jslib = ctx->GetLibrary();
  312. Js::Var res = nullptr;
  313. if(snapValue->OptWellKnownToken != TTD_INVALID_WELLKNOWN_TOKEN)
  314. {
  315. res = ctx->TTDWellKnownInfo->LookupKnownObjectFromPath(snapValue->OptWellKnownToken);
  316. }
  317. else
  318. {
  319. Js::RecyclableObject* rObj = inflator->FindReusableObjectIfExists(snapValue->PrimitiveValueId);
  320. if(rObj != nullptr)
  321. {
  322. res = rObj;
  323. }
  324. else
  325. {
  326. switch(snapValue->SnapType->JsTypeId)
  327. {
  328. case Js::TypeIds_Undefined:
  329. res = jslib->GetUndefined();
  330. break;
  331. case Js::TypeIds_Null:
  332. res = jslib->GetNull();
  333. break;
  334. case Js::TypeIds_Boolean:
  335. res = (snapValue->u_boolValue ? jslib->GetTrue() : jslib->GetFalse());
  336. break;
  337. case Js::TypeIds_Number:
  338. res = Js::JavascriptNumber::ToVarWithCheck(snapValue->u_doubleValue, ctx);
  339. break;
  340. case Js::TypeIds_Int64Number:
  341. res = Js::JavascriptInt64Number::ToVar(snapValue->u_int64Value, ctx);
  342. break;
  343. case Js::TypeIds_UInt64Number:
  344. res = Js::JavascriptUInt64Number::ToVar(snapValue->u_uint64Value, ctx);
  345. break;
  346. case Js::TypeIds_String:
  347. res = Js::JavascriptString::NewCopyBuffer(snapValue->u_stringValue->Contents, snapValue->u_stringValue->Length, ctx);
  348. break;
  349. case Js::TypeIds_Symbol:
  350. res = jslib->CreatePrimitveSymbol_TTD(snapValue->u_propertyIdValue);
  351. break;
  352. default:
  353. TTDAssert(false, "These are supposed to be primitive values e.g., no pointers or properties.");
  354. res = nullptr;
  355. }
  356. }
  357. }
  358. inflator->AddObject(snapValue->PrimitiveValueId, Js::RecyclableObject::FromVar(res));
  359. }
  360. void EmitSnapPrimitiveValue(const SnapPrimitiveValue* snapValue, FileWriter* writer, NSTokens::Separator separator)
  361. {
  362. writer->WriteRecordStart(separator);
  363. writer->WriteAddr(NSTokens::Key::primitiveId, snapValue->PrimitiveValueId);
  364. writer->WriteAddr(NSTokens::Key::typeId, snapValue->SnapType->TypePtrId, NSTokens::Separator::CommaSeparator);
  365. writer->WriteBool(NSTokens::Key::isWellKnownToken, snapValue->OptWellKnownToken != TTD_INVALID_WELLKNOWN_TOKEN, NSTokens::Separator::CommaSeparator);
  366. if(snapValue->OptWellKnownToken != TTD_INVALID_WELLKNOWN_TOKEN)
  367. {
  368. writer->WriteWellKnownToken(NSTokens::Key::wellKnownToken, snapValue->OptWellKnownToken, NSTokens::Separator::CommaSeparator);
  369. }
  370. else
  371. {
  372. switch(snapValue->SnapType->JsTypeId)
  373. {
  374. case Js::TypeIds_Undefined:
  375. case Js::TypeIds_Null:
  376. break;
  377. case Js::TypeIds_Boolean:
  378. writer->WriteBool(NSTokens::Key::boolVal, !!snapValue->u_boolValue, NSTokens::Separator::CommaSeparator);
  379. break;
  380. case Js::TypeIds_Number:
  381. writer->WriteDouble(NSTokens::Key::doubleVal, snapValue->u_doubleValue, NSTokens::Separator::CommaSeparator);
  382. break;
  383. case Js::TypeIds_Int64Number:
  384. writer->WriteInt64(NSTokens::Key::i64Val, snapValue->u_int64Value, NSTokens::Separator::CommaSeparator);
  385. break;
  386. case Js::TypeIds_UInt64Number:
  387. writer->WriteUInt64(NSTokens::Key::u64Val, snapValue->u_uint64Value, NSTokens::Separator::CommaSeparator);
  388. break;
  389. case Js::TypeIds_String:
  390. writer->WriteString(NSTokens::Key::stringVal, *(snapValue->u_stringValue), NSTokens::Separator::CommaSeparator);
  391. break;
  392. case Js::TypeIds_Symbol:
  393. writer->WriteInt32(NSTokens::Key::propertyId, snapValue->u_propertyIdValue, NSTokens::Separator::CommaSeparator);
  394. break;
  395. default:
  396. TTDAssert(false, "These are supposed to be primitive values e.g., no pointers or properties.");
  397. break;
  398. }
  399. }
  400. writer->WriteRecordEnd();
  401. }
  402. void ParseSnapPrimitiveValue(SnapPrimitiveValue* snapValue, bool readSeparator, FileReader* reader, SlabAllocator& alloc, const TTDIdentifierDictionary<TTD_PTR_ID, NSSnapType::SnapType*>& ptrIdToTypeMap)
  403. {
  404. reader->ReadRecordStart(readSeparator);
  405. snapValue->PrimitiveValueId = reader->ReadAddr(NSTokens::Key::primitiveId);
  406. TTD_PTR_ID snapTypeId = reader->ReadAddr(NSTokens::Key::typeId, true);
  407. snapValue->SnapType = ptrIdToTypeMap.LookupKnownItem(snapTypeId);
  408. bool isWellKnown = reader->ReadBool(NSTokens::Key::isWellKnownToken, true);
  409. if(isWellKnown)
  410. {
  411. snapValue->OptWellKnownToken = reader->ReadWellKnownToken(NSTokens::Key::wellKnownToken, alloc, true);
  412. //just clear it to help avoid any confusion later
  413. snapValue->u_uint64Value = 0;
  414. }
  415. else
  416. {
  417. snapValue->OptWellKnownToken = nullptr;
  418. switch(snapValue->SnapType->JsTypeId)
  419. {
  420. case Js::TypeIds_Undefined:
  421. case Js::TypeIds_Null:
  422. break;
  423. case Js::TypeIds_Boolean:
  424. snapValue->u_boolValue = reader->ReadBool(NSTokens::Key::boolVal, true);
  425. break;
  426. case Js::TypeIds_Number:
  427. snapValue->u_doubleValue = reader->ReadDouble(NSTokens::Key::doubleVal, true);
  428. break;
  429. case Js::TypeIds_Int64Number:
  430. snapValue->u_int64Value = reader->ReadInt64(NSTokens::Key::i64Val, true);
  431. break;
  432. case Js::TypeIds_UInt64Number:
  433. snapValue->u_uint64Value = reader->ReadUInt64(NSTokens::Key::u64Val, true);
  434. break;
  435. case Js::TypeIds_String:
  436. snapValue->u_stringValue = alloc.SlabAllocateStruct<TTString>();
  437. reader->ReadString(NSTokens::Key::stringVal, alloc, *(snapValue->u_stringValue), true);
  438. break;
  439. case Js::TypeIds_Symbol:
  440. snapValue->u_propertyIdValue = (Js::PropertyId)reader->ReadInt32(NSTokens::Key::propertyId, true);
  441. break;
  442. default:
  443. TTDAssert(false, "These are supposed to be primitive values e.g., no pointers or properties.");
  444. break;
  445. }
  446. }
  447. reader->ReadRecordEnd();
  448. }
  449. #if ENABLE_SNAPSHOT_COMPARE
  450. void AssertSnapEquiv(const SnapPrimitiveValue* v1, const SnapPrimitiveValue* v2, TTDCompareMap& compareMap)
  451. {
  452. compareMap.DiagnosticAssert(v1->SnapType->JsTypeId == v2->SnapType->JsTypeId);
  453. NSSnapType::AssertSnapEquiv(v1->SnapType, v2->SnapType, compareMap);
  454. if(v1->OptWellKnownToken != TTD_INVALID_WELLKNOWN_TOKEN || v2->OptWellKnownToken != TTD_INVALID_WELLKNOWN_TOKEN)
  455. {
  456. compareMap.DiagnosticAssert(v1->OptWellKnownToken != TTD_INVALID_WELLKNOWN_TOKEN && v2->OptWellKnownToken != TTD_INVALID_WELLKNOWN_TOKEN);
  457. compareMap.DiagnosticAssert(TTD_DIAGNOSTIC_COMPARE_WELLKNOWN_TOKENS(v1->OptWellKnownToken, v2->OptWellKnownToken));
  458. }
  459. else
  460. {
  461. switch(v1->SnapType->JsTypeId)
  462. {
  463. case Js::TypeIds_Undefined:
  464. case Js::TypeIds_Null:
  465. break;
  466. case Js::TypeIds_Boolean:
  467. compareMap.DiagnosticAssert((!!v1->u_boolValue) == (!!v2->u_boolValue));
  468. break;
  469. case Js::TypeIds_Number:
  470. compareMap.DiagnosticAssert(CheckSnapEquivTTDDouble(v1->u_doubleValue, v2->u_doubleValue));
  471. break;
  472. case Js::TypeIds_Int64Number:
  473. compareMap.DiagnosticAssert(v1->u_int64Value == v2->u_int64Value);
  474. break;
  475. case Js::TypeIds_UInt64Number:
  476. compareMap.DiagnosticAssert(v1->u_uint64Value == v2->u_uint64Value);
  477. break;
  478. case Js::TypeIds_String:
  479. compareMap.DiagnosticAssert(TTStringEQForDiagnostics(*(v1->u_stringValue), *(v2->u_stringValue)));
  480. break;
  481. case Js::TypeIds_Symbol:
  482. compareMap.DiagnosticAssert(v1->u_propertyIdValue == v2->u_propertyIdValue);
  483. break;
  484. default:
  485. TTDAssert(false, "These are supposed to be primitive values e.g., no pointers or properties.");
  486. break;
  487. }
  488. }
  489. }
  490. #endif
  491. //////////////////
  492. Field(Js::Var)* InflateSlotArrayInfo(const SlotArrayInfo* slotInfo, InflateMap* inflator)
  493. {
  494. Js::ScriptContext* ctx = inflator->LookupScriptContext(slotInfo->ScriptContextLogId);
  495. Field(Js::Var)* slotArray = RecyclerNewArray(ctx->GetRecycler(), Field(Js::Var), slotInfo->SlotCount + Js::ScopeSlots::FirstSlotIndex);
  496. Js::ScopeSlots scopeSlots(slotArray);
  497. scopeSlots.SetCount(slotInfo->SlotCount);
  498. Js::Var undef = ctx->GetLibrary()->GetUndefined();
  499. for(uint32 j = 0; j < slotInfo->SlotCount; j++)
  500. {
  501. scopeSlots.Set(j, undef);
  502. }
  503. if(slotInfo->isFunctionBodyMetaData)
  504. {
  505. Js::FunctionBody* fbody = inflator->LookupFunctionBody(slotInfo->OptFunctionBodyId);
  506. scopeSlots.SetScopeMetadata(fbody->GetFunctionInfo());
  507. //This is a doubly nested lookup so if the scope slot array is large this could be expensive
  508. Js::PropertyId* propertyIds = fbody->GetPropertyIdsForScopeSlotArray();
  509. for(uint32 j = 0; j < slotInfo->SlotCount; j++)
  510. {
  511. Js::PropertyId trgtPid = slotInfo->PIDArray[j];
  512. for(uint32 i = 0; i < fbody->GetScopeSlotArraySize(); i++)
  513. {
  514. if(trgtPid == propertyIds[i])
  515. {
  516. Js::Var sval = inflator->InflateTTDVar(slotInfo->Slots[j]);
  517. scopeSlots.Set(i, sval);
  518. break;
  519. }
  520. }
  521. }
  522. }
  523. else
  524. {
  525. Js::DebuggerScope* dbgScope = nullptr;
  526. if(slotInfo->OptWellKnownDbgScope != TTD_INVALID_WELLKNOWN_TOKEN)
  527. {
  528. dbgScope = ctx->TTDWellKnownInfo->LookupKnownDebuggerScopeFromPath(slotInfo->OptWellKnownDbgScope);
  529. }
  530. else
  531. {
  532. Js::FunctionBody* scopeBody = nullptr;
  533. int32 scopeIndex = -1;
  534. inflator->LookupInfoForDebugScope(slotInfo->OptDebugScopeId, &scopeBody, &scopeIndex);
  535. dbgScope = scopeBody->GetScopeObjectChain()->pScopeChain->Item(scopeIndex);
  536. }
  537. scopeSlots.SetScopeMetadata(dbgScope);
  538. //This is a doubly nested lookup so if the scope slot array is large this could be expensive
  539. for(uint32 j = 0; j < slotInfo->SlotCount; j++)
  540. {
  541. Js::PropertyId trgtPid = slotInfo->PIDArray[j];
  542. for(uint32 i = 0; i < slotInfo->SlotCount; i++)
  543. {
  544. if(trgtPid == dbgScope->GetPropertyIdForSlotIndex_TTD(i))
  545. {
  546. Js::Var sval = inflator->InflateTTDVar(slotInfo->Slots[j]);
  547. scopeSlots.Set(i, sval);
  548. break;
  549. }
  550. }
  551. }
  552. }
  553. return slotArray;
  554. }
  555. void EmitSlotArrayInfo(const SlotArrayInfo* slotInfo, FileWriter* writer, NSTokens::Separator separator)
  556. {
  557. writer->WriteRecordStart(separator);
  558. writer->AdjustIndent(1);
  559. writer->WriteAddr(NSTokens::Key::slotId, slotInfo->SlotId, NSTokens::Separator::BigSpaceSeparator);
  560. writer->WriteLogTag(NSTokens::Key::ctxTag, slotInfo->ScriptContextLogId, NSTokens::Separator::CommaSeparator);
  561. writer->WriteBool(NSTokens::Key::isFunctionMetaData, slotInfo->isFunctionBodyMetaData, NSTokens::Separator::CommaSeparator);
  562. if(slotInfo->isFunctionBodyMetaData)
  563. {
  564. writer->WriteAddr(NSTokens::Key::functionBodyId, slotInfo->OptFunctionBodyId, NSTokens::Separator::CommaSeparator);
  565. }
  566. else
  567. {
  568. writer->WriteBool(NSTokens::Key::isWellKnownToken, slotInfo->OptWellKnownDbgScope != TTD_INVALID_WELLKNOWN_TOKEN, NSTokens::Separator::CommaSeparator);
  569. if(slotInfo->OptWellKnownDbgScope != TTD_INVALID_WELLKNOWN_TOKEN)
  570. {
  571. writer->WriteWellKnownToken(NSTokens::Key::wellKnownToken, slotInfo->OptWellKnownDbgScope, NSTokens::Separator::CommaSeparator);
  572. }
  573. else
  574. {
  575. writer->WriteAddr(NSTokens::Key::debuggerScopeId, slotInfo->OptDebugScopeId, NSTokens::Separator::CommaSeparator);
  576. }
  577. }
  578. writer->WriteLengthValue(slotInfo->SlotCount, NSTokens::Separator::CommaAndBigSpaceSeparator);
  579. writer->WriteSequenceStart_DefaultKey(NSTokens::Separator::CommaAndBigSpaceSeparator);
  580. writer->AdjustIndent(1);
  581. for(uint32 i = 0; i < slotInfo->SlotCount; ++i)
  582. {
  583. writer->WriteRecordStart(i != 0 ? NSTokens::Separator::CommaAndBigSpaceSeparator : NSTokens::Separator::BigSpaceSeparator);
  584. writer->WriteUInt32(NSTokens::Key::pid, slotInfo->PIDArray[i], NSTokens::Separator::NoSeparator);
  585. writer->WriteKey(NSTokens::Key::entry, NSTokens::Separator::CommaSeparator);
  586. EmitTTDVar(slotInfo->Slots[i], writer, NSTokens::Separator::NoSeparator);
  587. writer->WriteRecordEnd();
  588. }
  589. writer->AdjustIndent(-1);
  590. writer->WriteSequenceEnd(NSTokens::Separator::BigSpaceSeparator);
  591. writer->AdjustIndent(-1);
  592. writer->WriteRecordEnd(NSTokens::Separator::BigSpaceSeparator);
  593. }
  594. void ParseSlotArrayInfo(SlotArrayInfo* slotInfo, bool readSeparator, FileReader* reader, SlabAllocator& alloc)
  595. {
  596. reader->ReadRecordStart(readSeparator);
  597. slotInfo->SlotId = reader->ReadAddr(NSTokens::Key::slotId);
  598. slotInfo->ScriptContextLogId = reader->ReadLogTag(NSTokens::Key::ctxTag, true);
  599. slotInfo->isFunctionBodyMetaData = reader->ReadBool(NSTokens::Key::isFunctionMetaData, true);
  600. slotInfo->OptFunctionBodyId = TTD_INVALID_PTR_ID;
  601. slotInfo->OptDebugScopeId = TTD_INVALID_PTR_ID;
  602. slotInfo->OptWellKnownDbgScope = TTD_INVALID_WELLKNOWN_TOKEN;
  603. if(slotInfo->isFunctionBodyMetaData)
  604. {
  605. slotInfo->OptFunctionBodyId = reader->ReadAddr(NSTokens::Key::functionBodyId, true);
  606. }
  607. else
  608. {
  609. bool isWellKnown = reader->ReadBool(NSTokens::Key::isWellKnownToken, true);
  610. if(isWellKnown)
  611. {
  612. slotInfo->OptWellKnownDbgScope = reader->ReadWellKnownToken(NSTokens::Key::wellKnownToken, alloc, true);
  613. }
  614. else
  615. {
  616. slotInfo->OptDebugScopeId = reader->ReadAddr(NSTokens::Key::debuggerScopeId, true);
  617. }
  618. }
  619. slotInfo->SlotCount = reader->ReadLengthValue(true);
  620. reader->ReadSequenceStart_WDefaultKey(true);
  621. slotInfo->Slots = alloc.SlabAllocateArray<TTDVar>(slotInfo->SlotCount);
  622. slotInfo->PIDArray = alloc.SlabAllocateArray<Js::PropertyId>(slotInfo->SlotCount);
  623. for(uint32 i = 0; i < slotInfo->SlotCount; ++i)
  624. {
  625. reader->ReadRecordStart(i != 0);
  626. slotInfo->PIDArray[i] = (Js::PropertyId)reader->ReadUInt32(NSTokens::Key::pid);
  627. reader->ReadKey(NSTokens::Key::entry, true);
  628. slotInfo->Slots[i] = ParseTTDVar(false, reader);
  629. reader->ReadRecordEnd();
  630. }
  631. reader->ReadSequenceEnd();
  632. reader->ReadRecordEnd();
  633. }
  634. #if ENABLE_SNAPSHOT_COMPARE
  635. void AssertSnapEquiv(const SlotArrayInfo* sai1, const SlotArrayInfo* sai2, TTDCompareMap& compareMap)
  636. {
  637. compareMap.DiagnosticAssert(sai1->ScriptContextLogId == sai2->ScriptContextLogId);
  638. compareMap.DiagnosticAssert(sai1->isFunctionBodyMetaData == sai2->isFunctionBodyMetaData);
  639. if(sai1->isFunctionBodyMetaData)
  640. {
  641. compareMap.CheckConsistentAndAddPtrIdMapping_FunctionBody(sai1->OptFunctionBodyId, sai2->OptFunctionBodyId);
  642. }
  643. else
  644. {
  645. //TODO: emit debugger scope metadata
  646. }
  647. compareMap.DiagnosticAssert(sai1->SlotCount == sai2->SlotCount);
  648. for(uint32 i = 0; i < sai1->SlotCount; ++i)
  649. {
  650. Js::PropertyId id1 = sai1->PIDArray[i];
  651. bool found = false;
  652. for(uint32 j = 0; j < sai1->SlotCount; ++j)
  653. {
  654. if(id1 == sai2->PIDArray[j])
  655. {
  656. AssertSnapEquivTTDVar_SlotArray(sai1->Slots[i], sai2->Slots[j], compareMap, i);
  657. found = true;
  658. break;
  659. }
  660. }
  661. //TODO: We see this hit in a case where record has all values in a slot array when replaying --replay-debug (but not --replay).
  662. // In the debug version the propertyId is in a Js::DebuggerScopeProperty instead. So this needs to be investigated in both extract and inflate.
  663. compareMap.DiagnosticAssert(found);
  664. }
  665. }
  666. #endif
  667. Js::FrameDisplay* InflateScriptFunctionScopeInfo(const ScriptFunctionScopeInfo* funcScopeInfo, InflateMap* inflator)
  668. {
  669. Js::ScriptContext* ctx = inflator->LookupScriptContext(funcScopeInfo->ScriptContextLogId);
  670. Js::FrameDisplay* environment = RecyclerNewPlus(ctx->GetRecycler(), funcScopeInfo->ScopeCount * sizeof(Js::Var), Js::FrameDisplay, funcScopeInfo->ScopeCount);
  671. for(uint16 i = 0; i < funcScopeInfo->ScopeCount; ++i)
  672. {
  673. const ScopeInfoEntry& scp = funcScopeInfo->ScopeArray[i];
  674. switch(scp.Tag)
  675. {
  676. case Js::ScopeType::ScopeType_ActivationObject:
  677. case Js::ScopeType::ScopeType_WithScope:
  678. {
  679. Js::Var sval = inflator->LookupObject(scp.IDValue);
  680. environment->SetItem(i, sval);
  681. break;
  682. }
  683. case Js::ScopeType::ScopeType_SlotArray:
  684. {
  685. Field(Js::Var)* saval = inflator->LookupSlotArray(scp.IDValue);
  686. environment->SetItem(i, saval);
  687. break;
  688. }
  689. default:
  690. TTDAssert(false, "Unknown scope kind");
  691. break;
  692. }
  693. }
  694. return environment;
  695. }
  696. void EmitScriptFunctionScopeInfo(const ScriptFunctionScopeInfo* funcScopeInfo, FileWriter* writer, NSTokens::Separator separator)
  697. {
  698. writer->WriteRecordStart(separator);
  699. writer->WriteAddr(NSTokens::Key::scopeId, funcScopeInfo->ScopeId);
  700. writer->WriteLogTag(NSTokens::Key::ctxTag, funcScopeInfo->ScriptContextLogId, NSTokens::Separator::CommaSeparator);
  701. writer->WriteUInt32(NSTokens::Key::count, funcScopeInfo->ScopeCount, NSTokens::Separator::CommaSeparator);
  702. writer->WriteSequenceStart_DefaultKey(NSTokens::Separator::CommaSeparator);
  703. for(uint32 i = 0; i < funcScopeInfo->ScopeCount; ++i)
  704. {
  705. writer->WriteRecordStart(i != 0 ? NSTokens::Separator::CommaSeparator : NSTokens::Separator::NoSeparator);
  706. writer->WriteTag<Js::ScopeType>(NSTokens::Key::scopeType, funcScopeInfo->ScopeArray[i].Tag);
  707. writer->WriteAddr(NSTokens::Key::subscopeId, funcScopeInfo->ScopeArray[i].IDValue, NSTokens::Separator::CommaSeparator);
  708. writer->WriteRecordEnd();
  709. }
  710. writer->WriteSequenceEnd();
  711. writer->WriteRecordEnd();
  712. }
  713. void ParseScriptFunctionScopeInfo(ScriptFunctionScopeInfo* funcScopeInfo, bool readSeparator, FileReader* reader, SlabAllocator& alloc)
  714. {
  715. reader->ReadRecordStart(readSeparator);
  716. funcScopeInfo->ScopeId = reader->ReadAddr(NSTokens::Key::scopeId);
  717. funcScopeInfo->ScriptContextLogId = reader->ReadLogTag(NSTokens::Key::ctxTag, true);
  718. funcScopeInfo->ScopeCount = (uint16)reader->ReadUInt32(NSTokens::Key::count, true);
  719. reader->ReadSequenceStart_WDefaultKey(true);
  720. funcScopeInfo->ScopeArray = alloc.SlabAllocateArray<ScopeInfoEntry>(funcScopeInfo->ScopeCount);
  721. for(uint32 i = 0; i < funcScopeInfo->ScopeCount; ++i)
  722. {
  723. reader->ReadRecordStart(i != 0);
  724. funcScopeInfo->ScopeArray[i].Tag = reader->ReadTag<Js::ScopeType>(NSTokens::Key::scopeType);
  725. funcScopeInfo->ScopeArray[i].IDValue = reader->ReadAddr(NSTokens::Key::subscopeId, true);
  726. reader->ReadRecordEnd();
  727. }
  728. reader->ReadSequenceEnd();
  729. reader->ReadRecordEnd();
  730. }
  731. #if ENABLE_SNAPSHOT_COMPARE
  732. void AssertSnapEquiv(const ScriptFunctionScopeInfo* funcScopeInfo1, const ScriptFunctionScopeInfo* funcScopeInfo2, TTDCompareMap& compareMap)
  733. {
  734. compareMap.DiagnosticAssert(funcScopeInfo1->ScriptContextLogId == funcScopeInfo2->ScriptContextLogId);
  735. compareMap.DiagnosticAssert(funcScopeInfo1->ScopeCount == funcScopeInfo2->ScopeCount);
  736. for(uint32 i = 0; i < funcScopeInfo1->ScopeCount; ++i)
  737. {
  738. compareMap.DiagnosticAssert(funcScopeInfo1->ScopeArray[i].Tag == funcScopeInfo2->ScopeArray[i].Tag);
  739. compareMap.CheckConsistentAndAddPtrIdMapping_Scope(funcScopeInfo1->ScopeArray[i].IDValue, funcScopeInfo2->ScopeArray[i].IDValue, i);
  740. }
  741. }
  742. #endif
  743. //////////////////
  744. Js::JavascriptPromiseCapability* InflatePromiseCapabilityInfo(const SnapPromiseCapabilityInfo* capabilityInfo, Js::ScriptContext* ctx, InflateMap* inflator)
  745. {
  746. if(!inflator->IsPromiseInfoDefined<Js::JavascriptPromiseCapability>(capabilityInfo->CapabilityId))
  747. {
  748. Js::Var promise = inflator->InflateTTDVar(capabilityInfo->PromiseVar);
  749. Js::Var resolve = inflator->InflateTTDVar(capabilityInfo->ResolveVar);
  750. Js::Var reject = inflator->InflateTTDVar(capabilityInfo->RejectVar);
  751. Js::JavascriptPromiseCapability* res = ctx->GetLibrary()->CreatePromiseCapability_TTD(promise, resolve, reject);
  752. inflator->AddInflatedPromiseInfo<Js::JavascriptPromiseCapability>(capabilityInfo->CapabilityId, res);
  753. }
  754. return inflator->LookupInflatedPromiseInfo<Js::JavascriptPromiseCapability>(capabilityInfo->CapabilityId);
  755. }
  756. void EmitPromiseCapabilityInfo(const SnapPromiseCapabilityInfo* capabilityInfo, FileWriter* writer, NSTokens::Separator separator)
  757. {
  758. writer->WriteRecordStart(separator);
  759. writer->WriteAddr(NSTokens::Key::ptrIdVal, capabilityInfo->CapabilityId);
  760. writer->WriteKey(NSTokens::Key::entry, NSTokens::Separator::CommaSeparator);
  761. EmitTTDVar(capabilityInfo->PromiseVar, writer, NSTokens::Separator::NoSeparator);
  762. writer->WriteKey(NSTokens::Key::entry, NSTokens::Separator::CommaSeparator);
  763. EmitTTDVar(capabilityInfo->ResolveVar, writer, NSTokens::Separator::NoSeparator);
  764. writer->WriteKey(NSTokens::Key::entry, NSTokens::Separator::CommaSeparator);
  765. EmitTTDVar(capabilityInfo->RejectVar, writer, NSTokens::Separator::NoSeparator);
  766. writer->WriteRecordEnd();
  767. }
  768. void ParsePromiseCapabilityInfo(SnapPromiseCapabilityInfo* capabilityInfo, bool readSeparator, FileReader* reader, SlabAllocator& alloc)
  769. {
  770. reader->ReadRecordStart(readSeparator);
  771. capabilityInfo->CapabilityId = reader->ReadAddr(NSTokens::Key::ptrIdVal);
  772. reader->ReadKey(NSTokens::Key::entry, true);
  773. capabilityInfo->PromiseVar = ParseTTDVar(false, reader);
  774. reader->ReadKey(NSTokens::Key::entry, true);
  775. capabilityInfo->ResolveVar = ParseTTDVar(false, reader);
  776. reader->ReadKey(NSTokens::Key::entry, true);
  777. capabilityInfo->RejectVar = ParseTTDVar(false, reader);
  778. reader->ReadRecordEnd();
  779. }
  780. #if ENABLE_SNAPSHOT_COMPARE
  781. void AssertSnapEquiv(const SnapPromiseCapabilityInfo* capabilityInfo1, const SnapPromiseCapabilityInfo* capabilityInfo2, TTDCompareMap& compareMap)
  782. {
  783. compareMap.CheckConsistentAndAddPtrIdMapping_NoEnqueue(capabilityInfo1->CapabilityId, capabilityInfo2->CapabilityId);
  784. AssertSnapEquivTTDVar_Special(capabilityInfo1->PromiseVar, capabilityInfo2->PromiseVar, compareMap, _u("promiseVar"));
  785. AssertSnapEquivTTDVar_Special(capabilityInfo1->ResolveVar, capabilityInfo2->ResolveVar, compareMap, _u("resolveObjId"));
  786. AssertSnapEquivTTDVar_Special(capabilityInfo1->RejectVar, capabilityInfo2->RejectVar, compareMap, _u("rejectObjId"));
  787. }
  788. #endif
  789. Js::JavascriptPromiseReaction* InflatePromiseReactionInfo(const SnapPromiseReactionInfo* reactionInfo, Js::ScriptContext* ctx, InflateMap* inflator)
  790. {
  791. if(!inflator->IsPromiseInfoDefined<Js::JavascriptPromiseReaction>(reactionInfo->PromiseReactionId))
  792. {
  793. Js::RecyclableObject* handler = inflator->LookupObject(reactionInfo->HandlerObjId);
  794. Js::JavascriptPromiseCapability* capabilities = InflatePromiseCapabilityInfo(&reactionInfo->Capabilities, ctx, inflator);
  795. Js::JavascriptPromiseReaction* res = ctx->GetLibrary()->CreatePromiseReaction_TTD(handler, capabilities);
  796. inflator->AddInflatedPromiseInfo<Js::JavascriptPromiseReaction>(reactionInfo->PromiseReactionId, res);
  797. }
  798. return inflator->LookupInflatedPromiseInfo<Js::JavascriptPromiseReaction>(reactionInfo->PromiseReactionId);
  799. }
  800. void EmitPromiseReactionInfo(const SnapPromiseReactionInfo* reactionInfo, FileWriter* writer, NSTokens::Separator separator)
  801. {
  802. writer->WriteRecordStart(separator);
  803. writer->WriteAddr(NSTokens::Key::ptrIdVal, reactionInfo->PromiseReactionId);
  804. writer->WriteAddr(NSTokens::Key::ptrIdVal, reactionInfo->HandlerObjId, NSTokens::Separator::CommaSeparator);
  805. writer->WriteKey(NSTokens::Key::entry, NSTokens::Separator::CommaSeparator);
  806. EmitPromiseCapabilityInfo(&reactionInfo->Capabilities, writer, NSTokens::Separator::NoSeparator);
  807. writer->WriteRecordEnd();
  808. }
  809. void ParsePromiseReactionInfo(SnapPromiseReactionInfo* reactionInfo, bool readSeparator, FileReader* reader, SlabAllocator& alloc)
  810. {
  811. reader->ReadRecordStart(readSeparator);
  812. reactionInfo->PromiseReactionId = reader->ReadAddr(NSTokens::Key::ptrIdVal);
  813. reactionInfo->HandlerObjId = reader->ReadAddr(NSTokens::Key::ptrIdVal, true);
  814. reader->ReadKey(NSTokens::Key::entry, true);
  815. ParsePromiseCapabilityInfo(&reactionInfo->Capabilities, false, reader, alloc);
  816. reader->ReadRecordEnd();
  817. }
  818. #if ENABLE_SNAPSHOT_COMPARE
  819. void AssertSnapEquiv(const SnapPromiseReactionInfo* reactionInfo1, const SnapPromiseReactionInfo* reactionInfo2, TTDCompareMap& compareMap)
  820. {
  821. compareMap.CheckConsistentAndAddPtrIdMapping_NoEnqueue(reactionInfo1->PromiseReactionId, reactionInfo2->PromiseReactionId);
  822. compareMap.CheckConsistentAndAddPtrIdMapping_Special(reactionInfo1->HandlerObjId, reactionInfo2->HandlerObjId, _u("handlerObjId"));
  823. AssertSnapEquiv(&(reactionInfo1->Capabilities), &(reactionInfo2->Capabilities), compareMap);
  824. }
  825. #endif
  826. //////////////////
  827. void ExtractSnapFunctionBodyScopeChain(bool isWellKnownFunction, SnapFunctionBodyScopeChain& scopeChain, Js::FunctionBody* fb, SlabAllocator& alloc)
  828. {
  829. scopeChain.ScopeCount = 0;
  830. scopeChain.ScopeArray = nullptr;
  831. if(!isWellKnownFunction && fb->GetScopeObjectChain() != nullptr)
  832. {
  833. Js::ScopeObjectChain* scChain = fb->GetScopeObjectChain();
  834. scopeChain.ScopeCount = (uint32)scChain->pScopeChain->Count();
  835. if(scopeChain.ScopeCount == 0)
  836. {
  837. scopeChain.ScopeArray = nullptr;
  838. }
  839. else
  840. {
  841. scopeChain.ScopeArray = alloc.SlabAllocateArray<TTD_PTR_ID>(scopeChain.ScopeCount);
  842. for(int32 i = 0; i < scChain->pScopeChain->Count(); ++i)
  843. {
  844. Js::DebuggerScope* dbgScope = scChain->pScopeChain->Item(i);
  845. scopeChain.ScopeArray[i] = TTD_CONVERT_DEBUGSCOPE_TO_PTR_ID(dbgScope);
  846. }
  847. }
  848. }
  849. }
  850. void EmitSnapFunctionBodyScopeChain(const SnapFunctionBodyScopeChain& scopeChain, FileWriter* writer)
  851. {
  852. writer->WriteRecordStart();
  853. writer->WriteLengthValue(scopeChain.ScopeCount);
  854. writer->WriteSequenceStart_DefaultKey(NSTokens::Separator::CommaSeparator);
  855. for(uint32 i = 0; i < scopeChain.ScopeCount; ++i)
  856. {
  857. writer->WriteNakedAddr(scopeChain.ScopeArray[i], (i != 0) ? NSTokens::Separator::CommaSeparator : NSTokens::Separator::NoSeparator);
  858. }
  859. writer->WriteSequenceEnd();
  860. writer->WriteRecordEnd();
  861. }
  862. void ParseSnapFunctionBodyScopeChain(SnapFunctionBodyScopeChain& scopeChain, FileReader* reader, SlabAllocator& alloc)
  863. {
  864. reader->ReadRecordStart();
  865. scopeChain.ScopeCount = reader->ReadLengthValue();
  866. scopeChain.ScopeArray = (scopeChain.ScopeCount != 0) ? alloc.SlabAllocateArray<TTD_PTR_ID>(scopeChain.ScopeCount) : nullptr;
  867. reader->ReadSequenceStart_WDefaultKey(true);
  868. for(uint32 i = 0; i < scopeChain.ScopeCount; ++i)
  869. {
  870. scopeChain.ScopeArray[i] = reader->ReadNakedAddr(i != 0);
  871. }
  872. reader->ReadSequenceEnd();
  873. reader->ReadRecordEnd();
  874. }
  875. #if ENABLE_SNAPSHOT_COMPARE
  876. void AssertSnapEquiv(const SnapFunctionBodyScopeChain& chain1, const SnapFunctionBodyScopeChain& chain2, TTDCompareMap& compareMap)
  877. {
  878. compareMap.DiagnosticAssert(chain1.ScopeCount == chain2.ScopeCount);
  879. //Not sure if there is a way to compare the pointer ids in the two scopes
  880. }
  881. #endif
  882. //////////////////
  883. void ExtractTopLevelCommonBodyResolveInfo(TopLevelCommonBodyResolveInfo* fbInfo, Js::FunctionBody* fb, uint32 topLevelCtr, Js::ModuleID moduleId, uint64 sourceContextId, bool isUtf8source, const byte* source, uint32 sourceLen, SlabAllocator& alloc)
  884. {
  885. fbInfo->ScriptContextLogId = fb->GetScriptContext()->ScriptContextLogTag;
  886. fbInfo->TopLevelBodyCtr = topLevelCtr;
  887. alloc.CopyNullTermStringInto(fb->GetDisplayName(), fbInfo->FunctionName);
  888. fbInfo->ModuleId = moduleId;
  889. fbInfo->SourceContextId = sourceContextId;
  890. alloc.CopyNullTermStringInto(fb->GetSourceContextInfo()->url, fbInfo->SourceUri);
  891. fbInfo->IsUtf8 = isUtf8source;
  892. fbInfo->ByteLength = sourceLen;
  893. fbInfo->SourceBuffer = alloc.SlabAllocateArray<byte>(fbInfo->ByteLength);
  894. js_memcpy_s(fbInfo->SourceBuffer, fbInfo->ByteLength, source, sourceLen);
  895. fbInfo->DbgSerializedBytecodeSize = 0;
  896. fbInfo->DbgSerializedBytecodeBuffer = nullptr;
  897. ExtractSnapFunctionBodyScopeChain(false, fbInfo->ScopeChainInfo, fb, alloc);
  898. }
  899. void EmitTopLevelCommonBodyResolveInfo(const TopLevelCommonBodyResolveInfo* fbInfo, bool emitInline, ThreadContext* threadContext, FileWriter* writer, NSTokens::Separator separator)
  900. {
  901. writer->WriteRecordStart(separator);
  902. writer->WriteUInt32(NSTokens::Key::functionBodyId, fbInfo->TopLevelBodyCtr);
  903. writer->WriteLogTag(NSTokens::Key::ctxTag, fbInfo->ScriptContextLogId, NSTokens::Separator::CommaSeparator);
  904. writer->WriteString(NSTokens::Key::name, fbInfo->FunctionName, NSTokens::Separator::CommaSeparator);
  905. writer->WriteUInt64(NSTokens::Key::moduleId, fbInfo->ModuleId, NSTokens::Separator::CommaSeparator);
  906. writer->WriteUInt64(NSTokens::Key::sourceContextId, fbInfo->SourceContextId, NSTokens::Separator::CommaSeparator);
  907. writer->WriteString(NSTokens::Key::uri, fbInfo->SourceUri, NSTokens::Separator::CommaSeparator);
  908. writer->WriteBool(NSTokens::Key::boolVal, fbInfo->IsUtf8, NSTokens::Separator::CommaSeparator);
  909. writer->WriteLengthValue(fbInfo->ByteLength, NSTokens::Separator::CommaSeparator);
  910. writer->WriteKey(NSTokens::Key::scopeChain, NSTokens::Separator::CommaSeparator);
  911. EmitSnapFunctionBodyScopeChain(fbInfo->ScopeChainInfo, writer);
  912. if(emitInline || IsNullPtrTTString(fbInfo->SourceUri))
  913. {
  914. TTDAssert(!fbInfo->IsUtf8, "Should only emit char16 encoded data in inline mode.");
  915. writer->WriteInlineCode((char16*)fbInfo->SourceBuffer, fbInfo->ByteLength / sizeof(char16), NSTokens::Separator::CommaSeparator);
  916. }
  917. else
  918. {
  919. JsSupport::WriteCodeToFile(threadContext, false, fbInfo->TopLevelBodyCtr, fbInfo->IsUtf8, fbInfo->SourceBuffer, fbInfo->ByteLength);
  920. }
  921. }
  922. void ParseTopLevelCommonBodyResolveInfo(TopLevelCommonBodyResolveInfo* fbInfo, bool readSeparator, bool parseInline, ThreadContext* threadContext, FileReader* reader, SlabAllocator& alloc)
  923. {
  924. reader->ReadRecordStart(readSeparator);
  925. fbInfo->TopLevelBodyCtr = reader->ReadUInt32(NSTokens::Key::functionBodyId);
  926. fbInfo->ScriptContextLogId = reader->ReadLogTag(NSTokens::Key::ctxTag, true);
  927. reader->ReadString(NSTokens::Key::name, alloc, fbInfo->FunctionName, true);
  928. fbInfo->ModuleId = (Js::ModuleID)reader->ReadUInt64(NSTokens::Key::moduleId, true);
  929. fbInfo->SourceContextId = reader->ReadUInt64(NSTokens::Key::sourceContextId, true);
  930. reader->ReadString(NSTokens::Key::uri, alloc, fbInfo->SourceUri, true);
  931. fbInfo->IsUtf8 = reader->ReadBool(NSTokens::Key::boolVal, true);
  932. fbInfo->ByteLength = reader->ReadLengthValue(true);
  933. fbInfo->SourceBuffer = alloc.SlabAllocateArray<byte>(fbInfo->ByteLength);
  934. reader->ReadKey(NSTokens::Key::scopeChain, true);
  935. ParseSnapFunctionBodyScopeChain(fbInfo->ScopeChainInfo, reader, alloc);
  936. if(parseInline || IsNullPtrTTString(fbInfo->SourceUri))
  937. {
  938. TTDAssert(!fbInfo->IsUtf8, "Should only emit char16 encoded data in inline mode.");
  939. reader->ReadInlineCode((char16*)fbInfo->SourceBuffer, fbInfo->ByteLength / sizeof(char16), true);
  940. }
  941. else
  942. {
  943. JsSupport::ReadCodeFromFile(threadContext, false, fbInfo->TopLevelBodyCtr, fbInfo->IsUtf8, fbInfo->SourceBuffer, fbInfo->ByteLength);
  944. }
  945. fbInfo->DbgSerializedBytecodeSize = 0;
  946. fbInfo->DbgSerializedBytecodeBuffer = nullptr;
  947. }
  948. #if ENABLE_SNAPSHOT_COMPARE
  949. void AssertSnapEquiv(const TopLevelCommonBodyResolveInfo* fbInfo1, const TopLevelCommonBodyResolveInfo* fbInfo2, TTDCompareMap& compareMap)
  950. {
  951. compareMap.DiagnosticAssert(fbInfo1->ScriptContextLogId == fbInfo2->ScriptContextLogId);
  952. compareMap.DiagnosticAssert(fbInfo1->TopLevelBodyCtr == fbInfo2->TopLevelBodyCtr);
  953. compareMap.DiagnosticAssert(TTStringEQForDiagnostics(fbInfo1->FunctionName, fbInfo2->FunctionName));
  954. compareMap.DiagnosticAssert(fbInfo1->ModuleId == fbInfo2->ModuleId);
  955. compareMap.DiagnosticAssert(fbInfo1->SourceContextId == fbInfo2->SourceContextId);
  956. compareMap.DiagnosticAssert(TTStringEQForDiagnostics(fbInfo1->SourceUri, fbInfo2->SourceUri));
  957. compareMap.DiagnosticAssert(fbInfo1->IsUtf8 == fbInfo2->IsUtf8);
  958. compareMap.DiagnosticAssert(fbInfo1->ByteLength == fbInfo2->ByteLength);
  959. for(uint32 i = 0; i < fbInfo1->ByteLength; ++i)
  960. {
  961. compareMap.DiagnosticAssert(fbInfo1->SourceBuffer[i] == fbInfo2->SourceBuffer[i]);
  962. }
  963. AssertSnapEquiv(fbInfo1->ScopeChainInfo, fbInfo2->ScopeChainInfo, compareMap);
  964. }
  965. #endif
  966. ////
  967. //Regular script-load functions
  968. void ExtractTopLevelLoadedFunctionBodyInfo(TopLevelScriptLoadFunctionBodyResolveInfo* fbInfo, Js::FunctionBody* fb, uint32 topLevelCtr, Js::ModuleID moduleId, uint64 sourceContextId, bool isUtf8, const byte* source, uint32 sourceLen, LoadScriptFlag loadFlag, SlabAllocator& alloc)
  969. {
  970. NSSnapValues::ExtractTopLevelCommonBodyResolveInfo(&fbInfo->TopLevelBase, fb, topLevelCtr, moduleId, sourceContextId, isUtf8, source, sourceLen, alloc);
  971. fbInfo->LoadFlag = loadFlag;
  972. }
  973. Js::FunctionBody* InflateTopLevelLoadedFunctionBodyInfo(const TopLevelScriptLoadFunctionBodyResolveInfo* fbInfo, Js::ScriptContext* ctx)
  974. {
  975. byte* script = fbInfo->TopLevelBase.SourceBuffer;
  976. uint32 scriptLength = fbInfo->TopLevelBase.ByteLength;
  977. uint64 sourceContext = fbInfo->TopLevelBase.SourceContextId;
  978. TTDAssert(ctx->GetSourceContextInfo((DWORD_PTR)sourceContext, nullptr) == nullptr, "On inflate we should either have clean ctxts or we want to optimize the inflate process by skipping redoing this work!!!");
  979. TTDAssert(fbInfo->TopLevelBase.IsUtf8 == ((fbInfo->LoadFlag & LoadScriptFlag_Utf8Source) == LoadScriptFlag_Utf8Source), "Utf8 status is inconsistent!!!");
  980. const char16* srcUri = fbInfo->TopLevelBase.SourceUri.Contents;
  981. uint32 srcUriLength = fbInfo->TopLevelBase.SourceUri.Length;
  982. SourceContextInfo * sourceContextInfo = ctx->CreateSourceContextInfo((DWORD_PTR)sourceContext, srcUri, srcUriLength, nullptr);
  983. TTDAssert(fbInfo->TopLevelBase.IsUtf8 || sizeof(wchar) == sizeof(char16), "Non-utf8 code only allowed on windows!!!");
  984. const int chsize = (fbInfo->LoadFlag & LoadScriptFlag_Utf8Source) ? sizeof(char) : sizeof(char16);
  985. SRCINFO si = {
  986. /* sourceContextInfo */ sourceContextInfo,
  987. /* dlnHost */ 0,
  988. /* ulColumnHost */ 0,
  989. /* lnMinHost */ 0,
  990. /* ichMinHost */ 0,
  991. /* ichLimHost */ static_cast<ULONG>(scriptLength / chsize), // OK to truncate since this is used to limit sourceText in debugDocument/compilation errors.
  992. /* ulCharOffset */ 0,
  993. /* mod */ fbInfo->TopLevelBase.ModuleId,
  994. /* grfsi */ 0
  995. };
  996. Js::Utf8SourceInfo* utf8SourceInfo = nullptr;
  997. CompileScriptException se;
  998. Js::JavascriptFunction* scriptFunction = nullptr;
  999. Js::FunctionBody* globalBody = nullptr;
  1000. if(fbInfo->TopLevelBase.DbgSerializedBytecodeSize != 0)
  1001. {
  1002. //
  1003. //TODO: Bytecode serializer does not support debug bytecode (StatementMaps vs Positions) so add this to serializer code.
  1004. // Then we can add code do optimized bytecode reload here.
  1005. //
  1006. TTDAssert(false, "Not implemented yet -- this branch should never be taken.");
  1007. }
  1008. else
  1009. {
  1010. scriptFunction = ctx->LoadScript(script, scriptLength, &si, &se, &utf8SourceInfo, Js::Constants::GlobalCode, fbInfo->LoadFlag, nullptr);
  1011. TTDAssert(scriptFunction != nullptr, "Something went wrong");
  1012. globalBody = TTD::JsSupport::ForceAndGetFunctionBody(scriptFunction->GetParseableFunctionInfo());
  1013. //
  1014. //TODO: Bytecode serializer does not suppper debug bytecode (StatementMaps vs Positions) so add this to serializer code.
  1015. // Then we can add code to do optimized bytecode reload here.
  1016. //
  1017. }
  1018. ////
  1019. //We don't do this automatically in the load script helper so do it here
  1020. BEGIN_JS_RUNTIME_CALL(ctx);
  1021. {
  1022. ctx->TTDContextInfo->ProcessFunctionBodyOnLoad(globalBody, nullptr);
  1023. ctx->TTDContextInfo->RegisterLoadedScript(globalBody, fbInfo->TopLevelBase.TopLevelBodyCtr);
  1024. globalBody->GetUtf8SourceInfo()->SetSourceInfoForDebugReplay_TTD(fbInfo->TopLevelBase.TopLevelBodyCtr);
  1025. }
  1026. END_JS_RUNTIME_CALL(ctx);
  1027. bool isLibraryCode = ((fbInfo->LoadFlag & LoadScriptFlag_LibraryCode) == LoadScriptFlag_LibraryCode);
  1028. if(ctx->GetThreadContext()->TTDExecutionInfo != nullptr && !isLibraryCode)
  1029. {
  1030. ctx->GetThreadContext()->TTDExecutionInfo->ProcessScriptLoad(ctx, fbInfo->TopLevelBase.TopLevelBodyCtr, globalBody, utf8SourceInfo, &se);
  1031. }
  1032. ////
  1033. return globalBody;
  1034. }
  1035. void EmitTopLevelLoadedFunctionBodyInfo(const TopLevelScriptLoadFunctionBodyResolveInfo* fbInfo, ThreadContext* threadContext, FileWriter* writer, NSTokens::Separator separator)
  1036. {
  1037. NSSnapValues::EmitTopLevelCommonBodyResolveInfo(&fbInfo->TopLevelBase, false, threadContext, writer, separator);
  1038. writer->WriteTag<LoadScriptFlag>(NSTokens::Key::loadFlag, fbInfo->LoadFlag, NSTokens::Separator::CommaSeparator);
  1039. writer->WriteRecordEnd();
  1040. }
  1041. void ParseTopLevelLoadedFunctionBodyInfo(TopLevelScriptLoadFunctionBodyResolveInfo* fbInfo, bool readSeparator, ThreadContext* threadContext, FileReader* reader, SlabAllocator& alloc)
  1042. {
  1043. NSSnapValues::ParseTopLevelCommonBodyResolveInfo(&fbInfo->TopLevelBase, readSeparator, false, threadContext, reader, alloc);
  1044. fbInfo->LoadFlag = reader->ReadTag<LoadScriptFlag>(NSTokens::Key::loadFlag, true);
  1045. reader->ReadRecordEnd();
  1046. }
  1047. #if ENABLE_SNAPSHOT_COMPARE
  1048. void AssertSnapEquiv(const TopLevelScriptLoadFunctionBodyResolveInfo* fbInfo1, const TopLevelScriptLoadFunctionBodyResolveInfo* fbInfo2, TTDCompareMap& compareMap)
  1049. {
  1050. compareMap.DiagnosticAssert(fbInfo1->LoadFlag == fbInfo2->LoadFlag);
  1051. AssertSnapEquiv(&(fbInfo1->TopLevelBase), &(fbInfo2->TopLevelBase), compareMap);
  1052. }
  1053. #endif
  1054. ////
  1055. //'new Function(...)' functions
  1056. void ExtractTopLevelNewFunctionBodyInfo(TopLevelNewFunctionBodyResolveInfo* fbInfo, Js::FunctionBody* fb, uint32 topLevelCtr, Js::ModuleID moduleId, const char16* source, uint32 sourceLen, SlabAllocator& alloc)
  1057. {
  1058. NSSnapValues::ExtractTopLevelCommonBodyResolveInfo(&fbInfo->TopLevelBase, fb, topLevelCtr, moduleId, 0, false, (const byte*)source, sourceLen * sizeof(char16), alloc);
  1059. }
  1060. Js::FunctionBody* InflateTopLevelNewFunctionBodyInfo(const TopLevelNewFunctionBodyResolveInfo* fbInfo, Js::ScriptContext* ctx)
  1061. {
  1062. // Bug 1105479. Get the module id from the caller
  1063. Js::ModuleID moduleID = kmodGlobal;
  1064. BOOL strictMode = FALSE;
  1065. char16* source = (char16*)fbInfo->TopLevelBase.SourceBuffer;
  1066. int32 length = (int32)(fbInfo->TopLevelBase.ByteLength / sizeof(char16));
  1067. Js::JavascriptFunction* pfuncScript = ctx->GetGlobalObject()->EvalHelper(ctx, source, length, moduleID, fscrNil, Js::Constants::FunctionCode, TRUE, TRUE, strictMode);
  1068. TTDAssert(pfuncScript != nullptr, "Something went wrong!!!");
  1069. // Indicate that this is a top-level function. We don't pass the fscrGlobalCode flag to the eval helper,
  1070. // or it will return the global function that wraps the declared function body, as though it were an eval.
  1071. // But we want, for instance, to be able to verify that we did the right amount of deferred parsing.
  1072. Js::ParseableFunctionInfo* functionInfo = pfuncScript->GetParseableFunctionInfo();
  1073. functionInfo->SetGrfscr(functionInfo->GetGrfscr() | fscrGlobalCode);
  1074. Js::FunctionBody* fb = JsSupport::ForceAndGetFunctionBody(pfuncScript->GetParseableFunctionInfo());
  1075. //We don't do this automatically in the eval helper so do it here
  1076. ctx->TTDContextInfo->ProcessFunctionBodyOnLoad(fb, nullptr);
  1077. ctx->TTDContextInfo->RegisterNewScript(fb, fbInfo->TopLevelBase.TopLevelBodyCtr);
  1078. return fb;
  1079. }
  1080. void EmitTopLevelNewFunctionBodyInfo(const TopLevelNewFunctionBodyResolveInfo* fbInfo, ThreadContext* threadContext, FileWriter* writer, NSTokens::Separator separator)
  1081. {
  1082. NSSnapValues::EmitTopLevelCommonBodyResolveInfo(&fbInfo->TopLevelBase, true, threadContext, writer, separator);
  1083. writer->WriteRecordEnd();
  1084. }
  1085. void ParseTopLevelNewFunctionBodyInfo(TopLevelNewFunctionBodyResolveInfo* fbInfo, bool readSeparator, ThreadContext* threadContext, FileReader* reader, SlabAllocator& alloc)
  1086. {
  1087. NSSnapValues::ParseTopLevelCommonBodyResolveInfo(&fbInfo->TopLevelBase, readSeparator, false, threadContext, reader, alloc);
  1088. reader->ReadRecordEnd();
  1089. }
  1090. #if ENABLE_SNAPSHOT_COMPARE
  1091. void AssertSnapEquiv(const TopLevelNewFunctionBodyResolveInfo* fbInfo1, const TopLevelNewFunctionBodyResolveInfo* fbInfo2, TTDCompareMap& compareMap)
  1092. {
  1093. AssertSnapEquiv(&(fbInfo1->TopLevelBase), &(fbInfo2->TopLevelBase), compareMap);
  1094. }
  1095. #endif
  1096. ////
  1097. //'eval(...)' functions
  1098. void ExtractTopLevelEvalFunctionBodyInfo(TopLevelEvalFunctionBodyResolveInfo* fbInfo, Js::FunctionBody* fb, uint32 topLevelCtr, Js::ModuleID moduleId, const char16* source, uint32 sourceLen, uint32 grfscr, bool registerDocument, BOOL isIndirect, BOOL strictMode, SlabAllocator& alloc)
  1099. {
  1100. NSSnapValues::ExtractTopLevelCommonBodyResolveInfo(&fbInfo->TopLevelBase, fb, topLevelCtr, moduleId, 0, false, (const byte*)source, sourceLen * sizeof(char16), alloc);
  1101. fbInfo->EvalFlags = grfscr;
  1102. fbInfo->RegisterDocument = registerDocument;
  1103. fbInfo->IsIndirect = !!isIndirect;
  1104. fbInfo->IsStrictMode = !!strictMode;
  1105. }
  1106. Js::FunctionBody* InflateTopLevelEvalFunctionBodyInfo(const TopLevelEvalFunctionBodyResolveInfo* fbInfo, Js::ScriptContext* ctx)
  1107. {
  1108. uint32 grfscr = ((uint32)fbInfo->EvalFlags) | fscrReturnExpression | fscrEval | fscrEvalCode | fscrGlobalCode;
  1109. char16* source = (char16*)fbInfo->TopLevelBase.SourceBuffer;
  1110. int32 sourceLen = (int32)(fbInfo->TopLevelBase.ByteLength / sizeof(char16));
  1111. Js::ScriptFunction* pfuncScript = ctx->GetLibrary()->GetGlobalObject()->EvalHelper(ctx, source, sourceLen, fbInfo->TopLevelBase.ModuleId, grfscr, Js::Constants::EvalCode, fbInfo->RegisterDocument, fbInfo->IsIndirect, fbInfo->IsStrictMode);
  1112. Assert(!pfuncScript->GetFunctionInfo()->IsGenerator());
  1113. Js::FastEvalMapString key(source, sourceLen, fbInfo->TopLevelBase.ModuleId, fbInfo->IsStrictMode, false);
  1114. ctx->AddToEvalMap(key, fbInfo->IsIndirect, pfuncScript);
  1115. Js::FunctionBody* fb = JsSupport::ForceAndGetFunctionBody(pfuncScript->GetParseableFunctionInfo());
  1116. //We don't do this automatically ing the eval helper so do it here
  1117. ctx->TTDContextInfo->ProcessFunctionBodyOnLoad(fb, nullptr);
  1118. ctx->TTDContextInfo->RegisterEvalScript(fb, fbInfo->TopLevelBase.TopLevelBodyCtr);
  1119. return fb;
  1120. }
  1121. void EmitTopLevelEvalFunctionBodyInfo(const TopLevelEvalFunctionBodyResolveInfo* fbInfo, ThreadContext* threadContext, FileWriter* writer, NSTokens::Separator separator)
  1122. {
  1123. NSSnapValues::EmitTopLevelCommonBodyResolveInfo(&fbInfo->TopLevelBase, true, threadContext, writer, separator);
  1124. writer->WriteUInt64(NSTokens::Key::u64Val, fbInfo->EvalFlags, NSTokens::Separator::CommaSeparator);
  1125. writer->WriteBool(NSTokens::Key::boolVal, fbInfo->RegisterDocument, NSTokens::Separator::CommaSeparator);
  1126. writer->WriteBool(NSTokens::Key::boolVal, fbInfo->IsIndirect, NSTokens::Separator::CommaSeparator);
  1127. writer->WriteBool(NSTokens::Key::boolVal, fbInfo->IsStrictMode, NSTokens::Separator::CommaSeparator);
  1128. writer->WriteRecordEnd();
  1129. }
  1130. void ParseTopLevelEvalFunctionBodyInfo(TopLevelEvalFunctionBodyResolveInfo* fbInfo, bool readSeparator, ThreadContext* threadContext, FileReader* reader, SlabAllocator& alloc)
  1131. {
  1132. NSSnapValues::ParseTopLevelCommonBodyResolveInfo(&fbInfo->TopLevelBase, readSeparator, false, threadContext, reader, alloc);
  1133. fbInfo->EvalFlags = reader->ReadUInt64(NSTokens::Key::u64Val, true);
  1134. fbInfo->RegisterDocument = reader->ReadBool(NSTokens::Key::boolVal, true);
  1135. fbInfo->IsIndirect = reader->ReadBool(NSTokens::Key::boolVal, true);
  1136. fbInfo->IsStrictMode = reader->ReadBool(NSTokens::Key::boolVal, true);
  1137. reader->ReadRecordEnd();
  1138. }
  1139. #if ENABLE_SNAPSHOT_COMPARE
  1140. void AssertSnapEquiv(const TopLevelEvalFunctionBodyResolveInfo* fbInfo1, const TopLevelEvalFunctionBodyResolveInfo* fbInfo2, TTDCompareMap& compareMap)
  1141. {
  1142. compareMap.DiagnosticAssert(fbInfo1->EvalFlags == fbInfo2->EvalFlags);
  1143. compareMap.DiagnosticAssert(fbInfo1->RegisterDocument == fbInfo2->RegisterDocument);
  1144. compareMap.DiagnosticAssert(fbInfo1->IsIndirect == fbInfo2->IsIndirect);
  1145. compareMap.DiagnosticAssert(fbInfo1->IsStrictMode == fbInfo2->IsStrictMode);
  1146. AssertSnapEquiv(&(fbInfo1->TopLevelBase), &(fbInfo2->TopLevelBase), compareMap);
  1147. }
  1148. #endif
  1149. void ExtractFunctionBodyInfo(FunctionBodyResolveInfo* fbInfo, Js::FunctionBody* fb, bool isWellKnown, SlabAllocator& alloc)
  1150. {
  1151. fbInfo->FunctionBodyId = TTD_CONVERT_FUNCTIONBODY_TO_PTR_ID(fb);
  1152. fbInfo->ScriptContextLogId = fb->GetScriptContext()->ScriptContextLogTag;
  1153. alloc.CopyStringIntoWLength(fb->GetDisplayName(), fb->GetDisplayNameLength(), fbInfo->FunctionName);
  1154. TTDAssert(wcscmp(fbInfo->FunctionName.Contents, Js::Constants::GlobalCode) != 0, "Why are we snapshotting global code??");
  1155. if(isWellKnown)
  1156. {
  1157. fbInfo->OptKnownPath = alloc.CopyRawNullTerminatedStringInto(fb->GetScriptContext()->TTDWellKnownInfo->ResolvePathForKnownFunctionBody(fb));
  1158. fbInfo->OptParentBodyId = TTD_INVALID_PTR_ID;
  1159. fbInfo->OptLine = -1;
  1160. fbInfo->OptColumn = -1;
  1161. }
  1162. else
  1163. {
  1164. fbInfo->OptKnownPath = TTD_INVALID_WELLKNOWN_TOKEN;
  1165. Js::FunctionBody* parentBody = fb->GetScriptContext()->TTDContextInfo->ResolveParentBody(fb);
  1166. TTDAssert(parentBody != nullptr, "We missed something!!!");
  1167. fbInfo->OptParentBodyId = TTD_CONVERT_FUNCTIONBODY_TO_PTR_ID(parentBody);
  1168. fbInfo->OptLine = fb->GetLineNumber();
  1169. fbInfo->OptColumn = fb->GetColumnNumber();
  1170. }
  1171. ExtractSnapFunctionBodyScopeChain(fbInfo->OptKnownPath != TTD_INVALID_WELLKNOWN_TOKEN, fbInfo->ScopeChainInfo, fb, alloc);
  1172. }
  1173. void InflateFunctionBody(const FunctionBodyResolveInfo* fbInfo, InflateMap* inflator, const TTDIdentifierDictionary<TTD_PTR_ID, FunctionBodyResolveInfo*>& idToFbResolveMap)
  1174. {
  1175. if(inflator->IsFunctionBodyAlreadyInflated(fbInfo->FunctionBodyId))
  1176. {
  1177. return;
  1178. }
  1179. Js::ScriptContext* ctx = inflator->LookupScriptContext(fbInfo->ScriptContextLogId);
  1180. Js::FunctionBody* resfb = nullptr;
  1181. if(fbInfo->OptKnownPath != TTD_INVALID_WELLKNOWN_TOKEN)
  1182. {
  1183. resfb = ctx->TTDWellKnownInfo->LookupKnownFunctionBodyFromPath(fbInfo->OptKnownPath);
  1184. }
  1185. else
  1186. {
  1187. resfb = inflator->FindReusableFunctionBodyIfExists(fbInfo->FunctionBodyId);
  1188. if(resfb == nullptr)
  1189. {
  1190. //Find and inflate the parent body
  1191. if(!inflator->IsFunctionBodyAlreadyInflated(fbInfo->OptParentBodyId))
  1192. {
  1193. const FunctionBodyResolveInfo* pBodyInfo = idToFbResolveMap.LookupKnownItem(fbInfo->OptParentBodyId);
  1194. InflateFunctionBody(pBodyInfo, inflator, idToFbResolveMap);
  1195. }
  1196. Js::FunctionBody* parentBody = inflator->LookupFunctionBody(fbInfo->OptParentBodyId);
  1197. //
  1198. //TODO: this is a potentially expensive linear search (but needed since classes dump implicit functions out-of-text order).
  1199. // May want to add sort and save in inflator or our shaddow info in script context if this is looking expensive.
  1200. //
  1201. uint32 blength = parentBody->GetNestedCount();
  1202. for(uint32 i = 0; i < blength; ++i)
  1203. {
  1204. Js::ParseableFunctionInfo* pfi = parentBody->GetNestedFunctionForExecution(i);
  1205. Js::FunctionBody* currfb = JsSupport::ForceAndGetFunctionBody(pfi);
  1206. if(fbInfo->OptLine == currfb->GetLineNumber() && fbInfo->OptColumn == currfb->GetColumnNumber())
  1207. {
  1208. resfb = currfb;
  1209. break;
  1210. }
  1211. }
  1212. TTDAssert(resfb != nullptr && fbInfo->OptLine == resfb->GetLineNumber() && fbInfo->OptColumn == resfb->GetColumnNumber(), "We are missing something");
  1213. TTDAssert(resfb != nullptr && (wcscmp(fbInfo->FunctionName.Contents, resfb->GetDisplayName()) == 0 || wcscmp(_u("get"), resfb->GetDisplayName()) == 0 || wcscmp(_u("set"), resfb->GetDisplayName()) == 0), "We are missing something");
  1214. }
  1215. //Make sure to register any scopes the found function body has (but *not* for well known functions)
  1216. inflator->UpdateFBScopes(fbInfo->ScopeChainInfo, resfb);
  1217. }
  1218. bool updateName = false;
  1219. if(fbInfo->FunctionName.Length != resfb->GetDisplayNameLength())
  1220. {
  1221. updateName = true;
  1222. }
  1223. else
  1224. {
  1225. const char16* fname = resfb->GetDisplayName();
  1226. for(uint32 i = 0; i < fbInfo->FunctionName.Length; ++i)
  1227. {
  1228. updateName |= (fbInfo->FunctionName.Contents[i] != fname[i]);
  1229. }
  1230. }
  1231. if(updateName)
  1232. {
  1233. uint32 suffixWDotPos = (fbInfo->FunctionName.Length - 4);
  1234. uint32 suffixPos = (fbInfo->FunctionName.Length - 3);
  1235. TTDAssert(wcsstr(fbInfo->FunctionName.Contents, _u(".get")) == (fbInfo->FunctionName.Contents + suffixWDotPos) || wcsstr(fbInfo->FunctionName.Contents, _u(".set")) == (fbInfo->FunctionName.Contents + suffixWDotPos), "Does not start with get or set");
  1236. resfb->SetDisplayName(fbInfo->FunctionName.Contents, fbInfo->FunctionName.Length, suffixPos, Js::FunctionProxy::SetDisplayNameFlagsRecyclerAllocated);
  1237. }
  1238. inflator->AddInflationFunctionBody(fbInfo->FunctionBodyId, resfb);
  1239. }
  1240. void EmitFunctionBodyInfo(const FunctionBodyResolveInfo* fbInfo, FileWriter* writer, NSTokens::Separator separator)
  1241. {
  1242. writer->WriteRecordStart(separator);
  1243. writer->WriteAddr(NSTokens::Key::functionBodyId, fbInfo->FunctionBodyId);
  1244. writer->WriteLogTag(NSTokens::Key::ctxTag, fbInfo->ScriptContextLogId, NSTokens::Separator::CommaSeparator);
  1245. writer->WriteString(NSTokens::Key::name, fbInfo->FunctionName, NSTokens::Separator::CommaSeparator);
  1246. writer->WriteBool(NSTokens::Key::isWellKnownToken, fbInfo->OptKnownPath != nullptr, NSTokens::Separator::CommaSeparator);
  1247. if(fbInfo->OptKnownPath != TTD_INVALID_WELLKNOWN_TOKEN)
  1248. {
  1249. writer->WriteWellKnownToken(NSTokens::Key::wellKnownToken, fbInfo->OptKnownPath, NSTokens::Separator::CommaSeparator);
  1250. }
  1251. else
  1252. {
  1253. writer->WriteAddr(NSTokens::Key::parentBodyId, fbInfo->OptParentBodyId, NSTokens::Separator::CommaSeparator);
  1254. writer->WriteInt64(NSTokens::Key::line, fbInfo->OptLine, NSTokens::Separator::CommaSeparator);
  1255. writer->WriteInt64(NSTokens::Key::column, fbInfo->OptColumn, NSTokens::Separator::CommaSeparator);
  1256. }
  1257. writer->WriteKey(NSTokens::Key::scopeChain, NSTokens::Separator::CommaSeparator);
  1258. EmitSnapFunctionBodyScopeChain(fbInfo->ScopeChainInfo, writer);
  1259. writer->WriteRecordEnd();
  1260. }
  1261. void ParseFunctionBodyInfo(FunctionBodyResolveInfo* fbInfo, bool readSeparator, FileReader* reader, SlabAllocator& alloc)
  1262. {
  1263. reader->ReadRecordStart(readSeparator);
  1264. fbInfo->FunctionBodyId = reader->ReadAddr(NSTokens::Key::functionBodyId);
  1265. fbInfo->ScriptContextLogId = reader->ReadLogTag(NSTokens::Key::ctxTag, true);
  1266. reader->ReadString(NSTokens::Key::name, alloc, fbInfo->FunctionName, true);
  1267. bool isWellKnown = reader->ReadBool(NSTokens::Key::isWellKnownToken, true);
  1268. if(isWellKnown)
  1269. {
  1270. fbInfo->OptKnownPath = reader->ReadWellKnownToken(NSTokens::Key::wellKnownToken, alloc, true);
  1271. fbInfo->OptParentBodyId = TTD_INVALID_PTR_ID;
  1272. fbInfo->OptLine = -1;
  1273. fbInfo->OptColumn = -1;
  1274. }
  1275. else
  1276. {
  1277. fbInfo->OptKnownPath = TTD_INVALID_WELLKNOWN_TOKEN;
  1278. fbInfo->OptParentBodyId = reader->ReadAddr(NSTokens::Key::parentBodyId, true);
  1279. fbInfo->OptLine = reader->ReadInt64(NSTokens::Key::line, true);
  1280. fbInfo->OptColumn = reader->ReadInt64(NSTokens::Key::column, true);
  1281. }
  1282. reader->ReadKey(NSTokens::Key::scopeChain, true);
  1283. ParseSnapFunctionBodyScopeChain(fbInfo->ScopeChainInfo, reader, alloc);
  1284. reader->ReadRecordEnd();
  1285. }
  1286. #if ENABLE_SNAPSHOT_COMPARE
  1287. void AssertSnapEquiv(const FunctionBodyResolveInfo* fbInfo1, const FunctionBodyResolveInfo* fbInfo2, TTDCompareMap& compareMap)
  1288. {
  1289. compareMap.DiagnosticAssert(fbInfo1->ScriptContextLogId == fbInfo2->ScriptContextLogId);
  1290. compareMap.DiagnosticAssert(TTStringEQForDiagnostics(fbInfo1->FunctionName, fbInfo2->FunctionName));
  1291. compareMap.DiagnosticAssert(TTD_DIAGNOSTIC_COMPARE_WELLKNOWN_TOKENS(fbInfo1->OptKnownPath, fbInfo2->OptKnownPath));
  1292. if(fbInfo1->OptKnownPath == TTD_INVALID_WELLKNOWN_TOKEN)
  1293. {
  1294. compareMap.CheckConsistentAndAddPtrIdMapping_FunctionBody(fbInfo1->OptParentBodyId, fbInfo2->OptParentBodyId);
  1295. compareMap.DiagnosticAssert(fbInfo1->OptLine == fbInfo2->OptLine);
  1296. compareMap.DiagnosticAssert(fbInfo1->OptColumn == fbInfo2->OptColumn);
  1297. }
  1298. AssertSnapEquiv(fbInfo1->ScopeChainInfo, fbInfo1->ScopeChainInfo, compareMap);
  1299. }
  1300. #endif
  1301. //////////////////
  1302. void ExtractScriptContext(SnapContext* snapCtx, Js::ScriptContext* ctx, const JsUtil::BaseDictionary<Js::RecyclableObject*, TTD_LOG_PTR_ID, HeapAllocator>& objToLogIdMap, const JsUtil::BaseHashSet<Js::FunctionBody*, HeapAllocator>& liveTopLevelBodies, SlabAllocator& alloc)
  1303. {
  1304. snapCtx->ScriptContextLogId = ctx->ScriptContextLogTag;
  1305. snapCtx->IsPNRGSeeded = ctx->GetLibrary()->IsPRNGSeeded();
  1306. snapCtx->RandomSeed0 = ctx->GetLibrary()->GetRandSeed0();
  1307. snapCtx->RandomSeed1 = ctx->GetLibrary()->GetRandSeed1();
  1308. alloc.CopyNullTermStringInto(ctx->GetUrl(), snapCtx->ContextSRC);
  1309. JsUtil::List<TopLevelFunctionInContextRelation, HeapAllocator> topLevelScriptLoad(&HeapAllocator::Instance);
  1310. JsUtil::List<TopLevelFunctionInContextRelation, HeapAllocator> topLevelNewFunction(&HeapAllocator::Instance);
  1311. JsUtil::List<TopLevelFunctionInContextRelation, HeapAllocator> topLevelEval(&HeapAllocator::Instance);
  1312. ctx->TTDContextInfo->GetLoadedSources(&liveTopLevelBodies, topLevelScriptLoad, topLevelNewFunction, topLevelEval);
  1313. snapCtx->LoadedTopLevelScriptCount = topLevelScriptLoad.Count();
  1314. if(snapCtx->LoadedTopLevelScriptCount == 0)
  1315. {
  1316. snapCtx->LoadedTopLevelScriptArray = nullptr;
  1317. }
  1318. else
  1319. {
  1320. snapCtx->LoadedTopLevelScriptArray = alloc.SlabAllocateArray<TopLevelFunctionInContextRelation>(snapCtx->LoadedTopLevelScriptCount);
  1321. for(int32 i = 0; i < topLevelScriptLoad.Count(); ++i)
  1322. {
  1323. snapCtx->LoadedTopLevelScriptArray[i] = topLevelScriptLoad.Item(i);
  1324. }
  1325. }
  1326. snapCtx->NewFunctionTopLevelScriptCount = topLevelNewFunction.Count();
  1327. if(snapCtx->NewFunctionTopLevelScriptCount == 0)
  1328. {
  1329. snapCtx->NewFunctionTopLevelScriptArray = nullptr;
  1330. }
  1331. else
  1332. {
  1333. snapCtx->NewFunctionTopLevelScriptArray = alloc.SlabAllocateArray<TopLevelFunctionInContextRelation>(snapCtx->NewFunctionTopLevelScriptCount);
  1334. for(int32 i = 0; i < topLevelNewFunction.Count(); ++i)
  1335. {
  1336. snapCtx->NewFunctionTopLevelScriptArray[i] = topLevelNewFunction.Item(i);
  1337. }
  1338. }
  1339. snapCtx->EvalTopLevelScriptCount = topLevelEval.Count();
  1340. if(snapCtx->EvalTopLevelScriptCount == 0)
  1341. {
  1342. snapCtx->EvalTopLevelScriptArray = nullptr;
  1343. }
  1344. else
  1345. {
  1346. snapCtx->EvalTopLevelScriptArray = alloc.SlabAllocateArray<TopLevelFunctionInContextRelation>(snapCtx->EvalTopLevelScriptCount);
  1347. for(int32 i = 0; i < topLevelEval.Count(); ++i)
  1348. {
  1349. snapCtx->EvalTopLevelScriptArray[i] = topLevelEval.Item(i);
  1350. }
  1351. }
  1352. //Extract pending async modification info
  1353. const JsUtil::List<TTDPendingAsyncBufferModification, HeapAllocator>& pendingAsyncList = ctx->TTDContextInfo->GetPendingAsyncModListForSnapshot();
  1354. snapCtx->PendingAsyncModCount = pendingAsyncList.Count();
  1355. if(snapCtx->PendingAsyncModCount == 0)
  1356. {
  1357. snapCtx->PendingAsyncModArray = nullptr;
  1358. }
  1359. else
  1360. {
  1361. snapCtx->PendingAsyncModArray = alloc.SlabAllocateArray<SnapPendingAsyncBufferModification>(snapCtx->PendingAsyncModCount);
  1362. for(int32 k = 0; k < pendingAsyncList.Count(); ++k)
  1363. {
  1364. const TTDPendingAsyncBufferModification& pk = pendingAsyncList.Item(k);
  1365. snapCtx->PendingAsyncModArray[k].LogId = objToLogIdMap.Item(Js::RecyclableObject::FromVar(pk.ArrayBufferVar));
  1366. snapCtx->PendingAsyncModArray[k].Index = pk.Index;
  1367. }
  1368. }
  1369. }
  1370. void InflateScriptContext(const SnapContext* snpCtx, Js::ScriptContext* intoCtx, InflateMap* inflator,
  1371. const TTDIdentifierDictionary<uint64, TopLevelScriptLoadFunctionBodyResolveInfo*>& topLevelLoadScriptMap,
  1372. const TTDIdentifierDictionary<uint64, TopLevelNewFunctionBodyResolveInfo*>& topLevelNewScriptMap,
  1373. const TTDIdentifierDictionary<uint64, TopLevelEvalFunctionBodyResolveInfo*>& topLevelEvalScriptMap)
  1374. {
  1375. TTDAssert(wcscmp(snpCtx->ContextSRC.Contents, intoCtx->GetUrl()) == 0, "Make sure the src uri values are the same.");
  1376. intoCtx->GetLibrary()->SetIsPRNGSeeded(snpCtx->IsPNRGSeeded);
  1377. intoCtx->GetLibrary()->SetRandSeed0(snpCtx->RandomSeed0);
  1378. intoCtx->GetLibrary()->SetRandSeed1(snpCtx->RandomSeed1);
  1379. inflator->AddScriptContext(snpCtx->ScriptContextLogId, intoCtx);
  1380. intoCtx->TTDContextInfo->ClearLoadedSourcesForSnapshotRestore();
  1381. if(intoCtx->HasRecordedException())
  1382. {
  1383. intoCtx->GetAndClearRecordedException(nullptr);
  1384. }
  1385. for(uint32 i = 0; i < snpCtx->LoadedTopLevelScriptCount; ++i)
  1386. {
  1387. const TopLevelFunctionInContextRelation& cri = snpCtx->LoadedTopLevelScriptArray[i];
  1388. Js::FunctionBody* fb = inflator->FindReusableFunctionBodyIfExists(cri.ContextSpecificBodyPtrId);
  1389. const TopLevelScriptLoadFunctionBodyResolveInfo* fbInfo = topLevelLoadScriptMap.LookupKnownItem(cri.TopLevelBodyCtr);
  1390. if(fb == nullptr)
  1391. {
  1392. fb = NSSnapValues::InflateTopLevelLoadedFunctionBodyInfo(fbInfo, intoCtx);
  1393. }
  1394. else
  1395. {
  1396. intoCtx->TTDContextInfo->ProcessFunctionBodyOnLoad(fb, nullptr);
  1397. intoCtx->TTDContextInfo->RegisterLoadedScript(fb, cri.TopLevelBodyCtr);
  1398. intoCtx->GetThreadContext()->TTDExecutionInfo->ProcessScriptLoad_InflateReuseBody(cri.TopLevelBodyCtr, fb);
  1399. }
  1400. inflator->UpdateFBScopes(fbInfo->TopLevelBase.ScopeChainInfo, fb);
  1401. inflator->AddInflationFunctionBody(cri.ContextSpecificBodyPtrId, fb);
  1402. }
  1403. //The inflation code for NewFunction and Eval uses the paths in the runtime (which assume they are in script) -- so enter here to make them happy
  1404. BEGIN_ENTER_SCRIPT(intoCtx, true, true, true)
  1405. {
  1406. for(uint32 i = 0; i < snpCtx->NewFunctionTopLevelScriptCount; ++i)
  1407. {
  1408. const TopLevelFunctionInContextRelation& cri = snpCtx->NewFunctionTopLevelScriptArray[i];
  1409. Js::FunctionBody* fb = inflator->FindReusableFunctionBodyIfExists(cri.ContextSpecificBodyPtrId);
  1410. const TopLevelNewFunctionBodyResolveInfo* fbInfo = topLevelNewScriptMap.LookupKnownItem(cri.TopLevelBodyCtr);
  1411. if(fb == nullptr)
  1412. {
  1413. fb = NSSnapValues::InflateTopLevelNewFunctionBodyInfo(fbInfo, intoCtx);
  1414. }
  1415. else
  1416. {
  1417. intoCtx->TTDContextInfo->ProcessFunctionBodyOnLoad(fb, nullptr);
  1418. intoCtx->TTDContextInfo->RegisterNewScript(fb, cri.TopLevelBodyCtr);
  1419. intoCtx->GetThreadContext()->TTDExecutionInfo->ProcessScriptLoad_InflateReuseBody(cri.TopLevelBodyCtr, fb);
  1420. }
  1421. inflator->UpdateFBScopes(fbInfo->TopLevelBase.ScopeChainInfo, fb);
  1422. inflator->AddInflationFunctionBody(cri.ContextSpecificBodyPtrId, fb);
  1423. }
  1424. for(uint32 i = 0; i < snpCtx->EvalTopLevelScriptCount; ++i)
  1425. {
  1426. const TopLevelFunctionInContextRelation& cri = snpCtx->EvalTopLevelScriptArray[i];
  1427. Js::FunctionBody* fb = inflator->FindReusableFunctionBodyIfExists(cri.ContextSpecificBodyPtrId);
  1428. const TopLevelEvalFunctionBodyResolveInfo* fbInfo = topLevelEvalScriptMap.LookupKnownItem(cri.TopLevelBodyCtr);
  1429. if(fb == nullptr)
  1430. {
  1431. fb = NSSnapValues::InflateTopLevelEvalFunctionBodyInfo(fbInfo, intoCtx);
  1432. }
  1433. else
  1434. {
  1435. intoCtx->TTDContextInfo->ProcessFunctionBodyOnLoad(fb, nullptr);
  1436. intoCtx->TTDContextInfo->RegisterEvalScript(fb, cri.TopLevelBodyCtr);
  1437. intoCtx->GetThreadContext()->TTDExecutionInfo->ProcessScriptLoad_InflateReuseBody(cri.TopLevelBodyCtr, fb);
  1438. }
  1439. inflator->UpdateFBScopes(fbInfo->TopLevelBase.ScopeChainInfo, fb);
  1440. inflator->AddInflationFunctionBody(cri.ContextSpecificBodyPtrId, fb);
  1441. }
  1442. }
  1443. END_ENTER_SCRIPT
  1444. }
  1445. void ResetPendingAsyncBufferModInfo(const SnapContext* snpCtx, Js::ScriptContext* intoCtx, InflateMap* inflator)
  1446. {
  1447. intoCtx->TTDContextInfo->ClearPendingAsyncModListForSnapRestore();
  1448. for(uint32 i = 0; i < snpCtx->PendingAsyncModCount; ++i)
  1449. {
  1450. Js::RecyclableObject* buff = intoCtx->GetThreadContext()->TTDContext->LookupObjectForLogID(snpCtx->PendingAsyncModArray[i].LogId);
  1451. uint32 index = snpCtx->PendingAsyncModArray[i].Index;
  1452. TTDAssert(Js::ArrayBuffer::Is(buff), "Not an ArrayBuffer!!!");
  1453. intoCtx->TTDContextInfo->AddToAsyncPendingList(Js::ArrayBuffer::FromVar(buff), index);
  1454. }
  1455. }
  1456. void EmitSnapContext(const SnapContext* snapCtx, FileWriter* writer, NSTokens::Separator separator)
  1457. {
  1458. writer->WriteRecordStart(separator);
  1459. writer->WriteLogTag(NSTokens::Key::ctxTag, snapCtx->ScriptContextLogId);
  1460. writer->WriteBool(NSTokens::Key::boolVal, snapCtx->IsPNRGSeeded, NSTokens::Separator::CommaSeparator);
  1461. writer->WriteUInt64(NSTokens::Key::u64Val, snapCtx->RandomSeed0, NSTokens::Separator::CommaSeparator);
  1462. writer->WriteUInt64(NSTokens::Key::u64Val, snapCtx->RandomSeed1, NSTokens::Separator::CommaSeparator);
  1463. writer->WriteString(NSTokens::Key::ctxUri, snapCtx->ContextSRC, NSTokens::Separator::CommaSeparator);
  1464. writer->WriteLengthValue(snapCtx->LoadedTopLevelScriptCount, NSTokens::Separator::CommaSeparator);
  1465. writer->WriteSequenceStart_DefaultKey(NSTokens::Separator::CommaSeparator);
  1466. for(uint32 i = 0; i < snapCtx->LoadedTopLevelScriptCount; ++i)
  1467. {
  1468. const TopLevelFunctionInContextRelation* cri = snapCtx->LoadedTopLevelScriptArray + i;
  1469. NSTokens::Separator sep = (i != 0) ? NSTokens::Separator::CommaSeparator : NSTokens::Separator::NoSeparator;
  1470. writer->WriteRecordStart(sep);
  1471. writer->WriteUInt32(NSTokens::Key::bodyCounterId, cri->TopLevelBodyCtr);
  1472. writer->WriteAddr(NSTokens::Key::functionBodyId, cri->ContextSpecificBodyPtrId, NSTokens::Separator::CommaSeparator);
  1473. writer->WriteRecordEnd();
  1474. }
  1475. writer->WriteSequenceEnd();
  1476. writer->WriteLengthValue(snapCtx->NewFunctionTopLevelScriptCount, NSTokens::Separator::CommaSeparator);
  1477. writer->WriteSequenceStart_DefaultKey(NSTokens::Separator::CommaSeparator);
  1478. for(uint32 i = 0; i < snapCtx->NewFunctionTopLevelScriptCount; ++i)
  1479. {
  1480. const TopLevelFunctionInContextRelation* cri = snapCtx->NewFunctionTopLevelScriptArray + i;
  1481. NSTokens::Separator sep = (i != 0) ? NSTokens::Separator::CommaSeparator : NSTokens::Separator::NoSeparator;
  1482. writer->WriteRecordStart(sep);
  1483. writer->WriteUInt32(NSTokens::Key::bodyCounterId, cri->TopLevelBodyCtr);
  1484. writer->WriteAddr(NSTokens::Key::functionBodyId, cri->ContextSpecificBodyPtrId, NSTokens::Separator::CommaSeparator);
  1485. writer->WriteRecordEnd();
  1486. }
  1487. writer->WriteSequenceEnd();
  1488. writer->WriteLengthValue(snapCtx->EvalTopLevelScriptCount, NSTokens::Separator::CommaSeparator);
  1489. writer->WriteSequenceStart_DefaultKey(NSTokens::Separator::CommaSeparator);
  1490. for(uint32 i = 0; i < snapCtx->EvalTopLevelScriptCount; ++i)
  1491. {
  1492. const TopLevelFunctionInContextRelation* cri = snapCtx->EvalTopLevelScriptArray + i;
  1493. NSTokens::Separator sep = (i != 0) ? NSTokens::Separator::CommaSeparator : NSTokens::Separator::NoSeparator;
  1494. writer->WriteRecordStart(sep);
  1495. writer->WriteUInt32(NSTokens::Key::bodyCounterId, cri->TopLevelBodyCtr);
  1496. writer->WriteAddr(NSTokens::Key::functionBodyId, cri->ContextSpecificBodyPtrId, NSTokens::Separator::CommaSeparator);
  1497. writer->WriteRecordEnd();
  1498. }
  1499. writer->WriteSequenceEnd();
  1500. writer->WriteLengthValue(snapCtx->PendingAsyncModCount, NSTokens::Separator::CommaSeparator);
  1501. writer->WriteSequenceStart_DefaultKey(NSTokens::Separator::CommaSeparator);
  1502. for(uint32 i = 0; i < snapCtx->PendingAsyncModCount; ++i)
  1503. {
  1504. NSTokens::Separator sep = (i != 0) ? NSTokens::Separator::CommaSeparator : NSTokens::Separator::NoSeparator;
  1505. writer->WriteRecordStart(sep);
  1506. writer->WriteLogTag(NSTokens::Key::logTag, snapCtx->PendingAsyncModArray[i].LogId);
  1507. writer->WriteUInt32(NSTokens::Key::u32Val, snapCtx->PendingAsyncModArray[i].Index, NSTokens::Separator::CommaSeparator);
  1508. writer->WriteRecordEnd();
  1509. }
  1510. writer->WriteSequenceEnd();
  1511. writer->WriteRecordEnd();
  1512. }
  1513. void ParseSnapContext(SnapContext* intoCtx, bool readSeparator, FileReader* reader, SlabAllocator& alloc)
  1514. {
  1515. reader->ReadRecordStart(readSeparator);
  1516. intoCtx->ScriptContextLogId = reader->ReadLogTag(NSTokens::Key::ctxTag);
  1517. intoCtx->IsPNRGSeeded = reader->ReadBool(NSTokens::Key::boolVal, true);
  1518. intoCtx->RandomSeed0 = reader->ReadUInt64(NSTokens::Key::u64Val, true);
  1519. intoCtx->RandomSeed1 = reader->ReadUInt64(NSTokens::Key::u64Val, true);
  1520. reader->ReadString(NSTokens::Key::ctxUri, alloc, intoCtx->ContextSRC, true);
  1521. intoCtx->LoadedTopLevelScriptCount = reader->ReadLengthValue(true);
  1522. intoCtx->LoadedTopLevelScriptArray = (intoCtx->LoadedTopLevelScriptCount != 0) ? alloc.SlabAllocateArray<TopLevelFunctionInContextRelation>(intoCtx->LoadedTopLevelScriptCount) : nullptr;
  1523. reader->ReadSequenceStart_WDefaultKey(true);
  1524. for(uint32 i = 0; i < intoCtx->LoadedTopLevelScriptCount; ++i)
  1525. {
  1526. TopLevelFunctionInContextRelation* cri = intoCtx->LoadedTopLevelScriptArray + i;
  1527. reader->ReadRecordStart(i != 0);
  1528. cri->TopLevelBodyCtr = reader->ReadUInt32(NSTokens::Key::bodyCounterId);
  1529. cri->ContextSpecificBodyPtrId = reader->ReadAddr(NSTokens::Key::functionBodyId, true);
  1530. reader->ReadRecordEnd();
  1531. }
  1532. reader->ReadSequenceEnd();
  1533. intoCtx->NewFunctionTopLevelScriptCount = reader->ReadLengthValue(true);
  1534. intoCtx->NewFunctionTopLevelScriptArray = (intoCtx->NewFunctionTopLevelScriptCount != 0) ? alloc.SlabAllocateArray<TopLevelFunctionInContextRelation>(intoCtx->NewFunctionTopLevelScriptCount) : nullptr;
  1535. reader->ReadSequenceStart_WDefaultKey(true);
  1536. for(uint32 i = 0; i < intoCtx->NewFunctionTopLevelScriptCount; ++i)
  1537. {
  1538. TopLevelFunctionInContextRelation* cri = intoCtx->NewFunctionTopLevelScriptArray + i;
  1539. reader->ReadRecordStart(i != 0);
  1540. cri->TopLevelBodyCtr = reader->ReadUInt32(NSTokens::Key::bodyCounterId);
  1541. cri->ContextSpecificBodyPtrId = reader->ReadAddr(NSTokens::Key::functionBodyId, true);
  1542. reader->ReadRecordEnd();
  1543. }
  1544. reader->ReadSequenceEnd();
  1545. intoCtx->EvalTopLevelScriptCount = reader->ReadLengthValue(true);
  1546. intoCtx->EvalTopLevelScriptArray = (intoCtx->EvalTopLevelScriptCount != 0) ? alloc.SlabAllocateArray<TopLevelFunctionInContextRelation>(intoCtx->EvalTopLevelScriptCount) : nullptr;
  1547. reader->ReadSequenceStart_WDefaultKey(true);
  1548. for(uint32 i = 0; i < intoCtx->EvalTopLevelScriptCount; ++i)
  1549. {
  1550. TopLevelFunctionInContextRelation* cri = intoCtx->EvalTopLevelScriptArray + i;
  1551. reader->ReadRecordStart(i != 0);
  1552. cri->TopLevelBodyCtr = reader->ReadUInt32(NSTokens::Key::bodyCounterId);
  1553. cri->ContextSpecificBodyPtrId = reader->ReadAddr(NSTokens::Key::functionBodyId, true);
  1554. reader->ReadRecordEnd();
  1555. }
  1556. reader->ReadSequenceEnd();
  1557. intoCtx->PendingAsyncModCount = reader->ReadLengthValue(true);
  1558. intoCtx->PendingAsyncModArray = (intoCtx->PendingAsyncModCount != 0) ? alloc.SlabAllocateArray<SnapPendingAsyncBufferModification>(intoCtx->PendingAsyncModCount) : nullptr;
  1559. reader->ReadSequenceStart_WDefaultKey(true);
  1560. for(uint32 i = 0; i < intoCtx->PendingAsyncModCount; ++i)
  1561. {
  1562. reader->ReadRecordStart(i != 0);
  1563. intoCtx->PendingAsyncModArray[i].LogId = reader->ReadLogTag(NSTokens::Key::logTag);
  1564. intoCtx->PendingAsyncModArray[i].Index = reader->ReadUInt32(NSTokens::Key::u32Val, true);
  1565. reader->ReadRecordEnd();
  1566. }
  1567. reader->ReadSequenceEnd();
  1568. reader->ReadRecordEnd();
  1569. }
  1570. #if ENABLE_SNAPSHOT_COMPARE
  1571. void AssertSnapEquiv(const SnapContext* snapCtx1, const SnapContext* snapCtx2, const JsUtil::BaseDictionary<TTD_LOG_PTR_ID, NSSnapValues::SnapRootInfoEntry*, HeapAllocator>& allRootMap1, const JsUtil::BaseDictionary<TTD_LOG_PTR_ID, NSSnapValues::SnapRootInfoEntry*, HeapAllocator>& allRootMap2, TTDCompareMap& compareMap)
  1572. {
  1573. compareMap.DiagnosticAssert(snapCtx1->ScriptContextLogId == snapCtx2->ScriptContextLogId);
  1574. compareMap.DiagnosticAssert(snapCtx1->IsPNRGSeeded == snapCtx2->IsPNRGSeeded);
  1575. compareMap.DiagnosticAssert(snapCtx1->RandomSeed0 == snapCtx2->RandomSeed0);
  1576. compareMap.DiagnosticAssert(snapCtx1->RandomSeed1 == snapCtx2->RandomSeed1);
  1577. compareMap.DiagnosticAssert(TTStringEQForDiagnostics(snapCtx1->ContextSRC, snapCtx2->ContextSRC));
  1578. //
  1579. //TODO: For now just sanity check the number of top-level functions and let the FunctionBody matching drive any matching.
  1580. //
  1581. compareMap.DiagnosticAssert(snapCtx1->LoadedTopLevelScriptCount == snapCtx2->LoadedTopLevelScriptCount);
  1582. //TopLevelScriptLoadFunctionBodyResolveInfo* m_loadedScriptArray;
  1583. compareMap.DiagnosticAssert(snapCtx1->NewFunctionTopLevelScriptCount == snapCtx2->NewFunctionTopLevelScriptCount);
  1584. //TopLevelNewFunctionBodyResolveInfo* m_newScriptArray;
  1585. compareMap.DiagnosticAssert(snapCtx1->EvalTopLevelScriptCount == snapCtx2->EvalTopLevelScriptCount);
  1586. //TopLevelEvalFunctionBodyResolveInfo* m_evalScriptArray;
  1587. compareMap.DiagnosticAssert(snapCtx1->PendingAsyncModCount == snapCtx2->PendingAsyncModCount);
  1588. for(uint32 i = 0; i < snapCtx1->PendingAsyncModCount; ++i)
  1589. {
  1590. const SnapPendingAsyncBufferModification& pendEntry1 = snapCtx1->PendingAsyncModArray[i];
  1591. const SnapPendingAsyncBufferModification& pendEntry2 = snapCtx2->PendingAsyncModArray[i];
  1592. compareMap.DiagnosticAssert(pendEntry1.LogId == pendEntry2.LogId && pendEntry1.Index == pendEntry2.Index);
  1593. compareMap.H1PendingAsyncModBufferSet.AddNew(allRootMap1.Item(pendEntry1.LogId)->LogObject);
  1594. compareMap.H2PendingAsyncModBufferSet.AddNew(allRootMap2.Item(pendEntry2.LogId)->LogObject);
  1595. }
  1596. }
  1597. #endif
  1598. }
  1599. }
  1600. #endif