JavascriptStackWalker.cpp 61 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610
  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 "RuntimeLanguagePch.h"
  6. #include "Language/JavascriptFunctionArgIndex.h"
  7. #include "Language/InterpreterStackFrame.h"
  8. #define FAligned(VALUE, TYPE) ((((LONG_PTR)VALUE) & (sizeof(TYPE)-1)) == 0)
  9. #define AlignIt(VALUE, TYPE) (~(~((LONG_PTR)(VALUE) + (sizeof(TYPE)-1)) | (sizeof(TYPE)-1)))
  10. namespace Js
  11. {
  12. Js::ArgumentsObject * JavascriptCallStackLayout::GetArgumentsObject() const
  13. {
  14. return (Js::ArgumentsObject *)((void **)this)[JavascriptFunctionArgIndex_ArgumentsObject];
  15. }
  16. Js::Var* JavascriptCallStackLayout::GetArgumentsObjectLocation() const
  17. {
  18. return (Js::Var *)&((void **)this)[JavascriptFunctionArgIndex_ArgumentsObject];
  19. }
  20. void JavascriptCallStackLayout::SetArgumentsObject(Js::ArgumentsObject * obj)
  21. {
  22. ((void **)this)[JavascriptFunctionArgIndex_ArgumentsObject] = obj;
  23. }
  24. Js::Var JavascriptCallStackLayout::GetOffset(int offset) const
  25. {
  26. Js::Var *varPtr = (Js::Var *)(((char *)this) + offset);
  27. Assert(FAligned(varPtr, Js::Var));
  28. return *varPtr;
  29. }
  30. double JavascriptCallStackLayout::GetDoubleAtOffset(int offset) const
  31. {
  32. double *dblPtr = (double *)(((char *)this) + offset);
  33. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  34. if (Js::Configuration::Global.flags.IsEnabled(Js::CheckAlignmentFlag))
  35. {
  36. Assert(FAligned(dblPtr, double));
  37. }
  38. #endif
  39. return *dblPtr;
  40. }
  41. int32 JavascriptCallStackLayout::GetInt32AtOffset(int offset) const
  42. {
  43. int32 *intPtr = (int32 *)(((char *)this) + offset);
  44. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  45. if (Js::Configuration::Global.flags.IsEnabled(Js::CheckAlignmentFlag))
  46. {
  47. Assert(FAligned(intPtr, int32));
  48. }
  49. #endif
  50. return *intPtr;
  51. }
  52. SIMDValue JavascriptCallStackLayout::GetSimdValueAtOffset(int offset) const
  53. {
  54. return *((SIMDValue *)(((char *)this) + offset));
  55. }
  56. char * JavascriptCallStackLayout::GetValueChangeOffset(int offset) const
  57. {
  58. Js::Var *varPtr = (Js::Var *)(((char *)this) + offset);
  59. Assert(FAligned(varPtr, Js::Var));
  60. return (char *)varPtr;
  61. }
  62. ForInObjectEnumerator * JavascriptCallStackLayout::GetForInObjectEnumeratorArrayAtOffset(int offset) const
  63. {
  64. return (ForInObjectEnumerator *)(((char *)this) + offset);
  65. }
  66. JavascriptCallStackLayout *JavascriptCallStackLayout::FromFramePointer(void *const framePointer)
  67. {
  68. return
  69. reinterpret_cast<JavascriptCallStackLayout *>(
  70. static_cast<void **>(framePointer) + (JavascriptFunctionArgIndex_Function - JavascriptFunctionArgIndex_Frame));
  71. }
  72. void* const JavascriptCallStackLayout::ToFramePointer(JavascriptCallStackLayout* callstackLayout)
  73. {
  74. return
  75. reinterpret_cast<void * const>(
  76. reinterpret_cast<void **>(callstackLayout) - (JavascriptFunctionArgIndex_Function - JavascriptFunctionArgIndex_Frame));
  77. }
  78. Js::Var* JavascriptCallStackLayout::GetArgv() const
  79. {
  80. return const_cast<Js::Var*>(&this->args[0]);
  81. }
  82. ScriptContext* JavascriptStackWalker::GetCurrentScriptContext() const
  83. {
  84. return this->GetCurrentInterpreterFrame() ? this->GetCurrentInterpreterFrame()->GetScriptContext() : this->scriptContext;
  85. }
  86. Var JavascriptStackWalker::GetCurrentArgumentsObject() const
  87. {
  88. #if ENABLE_PROFILE_INFO
  89. if (interpreterFrame)
  90. #else
  91. Assert(interpreterFrame);
  92. #endif
  93. {
  94. return interpreterFrame->GetArgumentsObject();
  95. }
  96. #if ENABLE_NATIVE_CODEGEN
  97. else
  98. {
  99. if (inlinedFramesBeingWalked)
  100. {
  101. return inlinedFrameWalker.GetArgumentsObject();
  102. }
  103. else
  104. {
  105. return this->GetCurrentNativeArgumentsObject();
  106. }
  107. }
  108. #endif
  109. }
  110. void JavascriptStackWalker::SetCurrentArgumentsObject(Var args)
  111. {
  112. #if ENABLE_NATIVE_CODEGEN
  113. if (interpreterFrame)
  114. #else
  115. Assert(interpreterFrame);
  116. #endif
  117. {
  118. interpreterFrame->SetArgumentsObject(args);
  119. }
  120. #if ENABLE_NATIVE_CODEGEN
  121. else
  122. {
  123. if (inlinedFramesBeingWalked)
  124. {
  125. inlinedFrameWalker.SetArgumentsObject(args);
  126. }
  127. else
  128. {
  129. this->SetCurrentNativeArgumentsObject(args);
  130. }
  131. }
  132. #endif
  133. }
  134. Var JavascriptStackWalker::GetPermanentArguments() const
  135. {
  136. Assert(IsJavascriptFrame());
  137. AssertMsg(this->GetCurrentFunction()->IsScriptFunction(), "GetPermanentArguments should not be called for non-script function as there is no slot allocated for it.");
  138. const uint32 paramCount = GetCallInfo().Count;
  139. if (paramCount == 0)
  140. {
  141. // glob function doesn't allocate ArgumentsObject slot on stack
  142. return nullptr;
  143. }
  144. // Get the heap-allocated args for this frame.
  145. Var args = this->GetCurrentArgumentsObject();
  146. if (args && ArgumentsObject::Is(args))
  147. {
  148. args = ((ArgumentsObject*)args)->GetHeapArguments();
  149. }
  150. return args;
  151. }
  152. BOOL JavascriptStackWalker::WalkToArgumentsFrame(ArgumentsObject *args)
  153. {
  154. // Move the walker up the stack until we find the given arguments object on the frame.
  155. while (this->Walk(/*includeInlineFrame*/ true))
  156. {
  157. if (this->IsJavascriptFrame())
  158. {
  159. Var currArgs = this->GetCurrentArgumentsObject();
  160. if (currArgs == args)
  161. {
  162. return TRUE;
  163. }
  164. }
  165. }
  166. return FALSE;
  167. }
  168. void JavascriptStackWalker::GetThis(Var* pVarThis, int moduleId) const
  169. {
  170. #if ENABLE_NATIVE_CODEGEN
  171. if (inlinedFramesBeingWalked)
  172. {
  173. if (inlinedFrameWalker.GetArgc() == 0)
  174. {
  175. *pVarThis = JavascriptOperators::OP_GetThis(this->scriptContext->GetLibrary()->GetUndefined(), moduleId, scriptContext);
  176. }
  177. else
  178. {
  179. *pVarThis = inlinedFrameWalker.GetThisObject();
  180. Assert(*pVarThis);
  181. }
  182. }
  183. else
  184. #endif
  185. {
  186. const CallInfo callInfo = this->GetCallInfo();
  187. if (callInfo.Count == 0)
  188. {
  189. *pVarThis = JavascriptOperators::OP_GetThis(scriptContext->GetLibrary()->GetUndefined(), moduleId, scriptContext);
  190. }
  191. else
  192. {
  193. *pVarThis = this->GetThisFromFrame();
  194. }
  195. }
  196. if (*pVarThis == nullptr)
  197. {
  198. *pVarThis = this->scriptContext->GetLibrary()->GetNull();
  199. }
  200. }
  201. BOOL IsEval(CallInfo callInfo)
  202. {
  203. return (callInfo.Flags & CallFlags_Eval) != 0;
  204. }
  205. BOOL JavascriptStackWalker::IsCallerGlobalFunction() const
  206. {
  207. const CallInfo callInfo = this->GetCallInfo();
  208. JavascriptFunction* function = this->GetCurrentFunction();
  209. if (IsLibraryStackFrameEnabled(this->scriptContext) && !function->IsScriptFunction())
  210. {
  211. return false; // native library code can't be global function
  212. }
  213. FunctionInfo* funcInfo = function->GetFunctionInfo();
  214. if (funcInfo->HasParseableInfo())
  215. {
  216. return funcInfo->GetParseableFunctionInfo()->GetIsGlobalFunc() || IsEval(callInfo);
  217. }
  218. else
  219. {
  220. AssertMsg(FALSE, "Here we should only have script functions which were already parsed/deserialized.");
  221. return callInfo.Count == 0 || IsEval(callInfo);
  222. }
  223. }
  224. BOOL JavascriptStackWalker::IsEvalCaller() const
  225. {
  226. const CallInfo callInfo = this->GetCallInfo();
  227. return (callInfo.Flags & CallFlags_Eval) != 0;
  228. }
  229. Var JavascriptStackWalker::GetCurrentNativeArgumentsObject() const
  230. {
  231. Assert(this->IsJavascriptFrame() && this->interpreterFrame == nullptr);
  232. return this->GetCurrentArgv()[JavascriptFunctionArgIndex_ArgumentsObject];
  233. }
  234. void JavascriptStackWalker::SetCurrentNativeArgumentsObject(Var args)
  235. {
  236. Assert(this->IsJavascriptFrame() && this->interpreterFrame == nullptr);
  237. this->GetCurrentArgv()[JavascriptFunctionArgIndex_ArgumentsObject] = args;
  238. }
  239. Js::Var * JavascriptStackWalker::GetJavascriptArgs(bool boxArgsAndDeepCopy) const
  240. {
  241. Assert(this->IsJavascriptFrame());
  242. #if ENABLE_NATIVE_CODEGEN
  243. if (inlinedFramesBeingWalked)
  244. {
  245. return inlinedFrameWalker.GetArgv(/* includeThis */ false, boxArgsAndDeepCopy);
  246. }
  247. else
  248. #endif
  249. if (this->GetCurrentFunction()->GetFunctionInfo()->IsCoroutine())
  250. {
  251. JavascriptGenerator* gen = JavascriptGenerator::FromVar(this->GetCurrentArgv()[JavascriptFunctionArgIndex_This]);
  252. return gen->GetArguments().Values;
  253. }
  254. else
  255. {
  256. return &this->GetCurrentArgv()[JavascriptFunctionArgIndex_SecondScriptArg];
  257. }
  258. }
  259. uint32 JavascriptStackWalker::GetByteCodeOffset() const
  260. {
  261. uint32 offset = 0;
  262. if (this->IsJavascriptFrame())
  263. {
  264. if (this->interpreterFrame)
  265. {
  266. if (this->TryGetByteCodeOffsetFromInterpreterFrame(offset))
  267. {
  268. return offset;
  269. }
  270. }
  271. #if ENABLE_NATIVE_CODEGEN
  272. if (TryGetByteCodeOffsetFromNativeFrame(offset))
  273. {
  274. return offset;
  275. }
  276. #endif
  277. }
  278. return offset;
  279. }
  280. bool JavascriptStackWalker::TryGetByteCodeOffsetFromInterpreterFrame(uint32& offset) const
  281. {
  282. #if ENABLE_NATIVE_CODEGEN
  283. if (this->lastInternalFrameInfo.codeAddress != nullptr)
  284. {
  285. return false;
  286. }
  287. #endif
  288. offset = this->interpreterFrame->GetReader()->GetCurrentOffset();
  289. if (offset == 0)
  290. {
  291. // This will be the case when we are broken on the debugger on very first statement (due to async break).
  292. // Or the interpreter loop can throw OOS on entrance before executing bytecode.
  293. }
  294. else
  295. {
  296. // Note : For many cases, we move the m_currentLocation of ByteCodeReader already to next available opcode.
  297. // This could create problem in binding the exception to proper line offset.
  298. // Reducing by 1 will make sure the current offset falls under, current executing opcode.
  299. offset--;
  300. }
  301. return true;
  302. }
  303. #if ENABLE_NATIVE_CODEGEN
  304. bool JavascriptStackWalker::TryGetByteCodeOffsetFromNativeFrame(uint32& offset) const
  305. {
  306. DWORD_PTR pCodeAddr;
  307. if (this->lastInternalFrameInfo.codeAddress != nullptr)
  308. {
  309. pCodeAddr = (DWORD_PTR)this->lastInternalFrameInfo.codeAddress;
  310. }
  311. else
  312. {
  313. pCodeAddr = (DWORD_PTR)this->GetCurrentCodeAddr();
  314. }
  315. // If the current instruction's return address is the beginning of the next statement then we will show error for the next line, which would be completely wrong.
  316. // The quick fix would be to look the address which is at least lesser than current return address.
  317. // Assert to verify at what places this can happen.
  318. Assert(pCodeAddr);
  319. if (pCodeAddr)
  320. {
  321. #if defined(_M_ARM)
  322. // Note that DWORD_PTR is not actually a pointer type (!) but is simple unsigned long/__int64 (see BaseTsd.h).
  323. // Thus, decrement would be by 1 byte and not 4 bytes as in pointer arithmetic. That's exactly what we need.
  324. // For ARM the 'return address' is always odd and is 'next instr addr' + 1 byte, so to get to the BLX instr, we need to subtract 2 bytes from it.
  325. AssertMsg(pCodeAddr % 2 == 1, "Got even number for pCodeAddr! It's expected to be return address, which should be odd.");
  326. pCodeAddr--;
  327. #endif
  328. pCodeAddr--;
  329. }
  330. bool usedInternalFrameInfo = false;
  331. uint loopNum = GetLoopNumber(usedInternalFrameInfo);
  332. JavascriptFunction *function = nullptr;
  333. FunctionBody *inlinee = nullptr;
  334. function = usedInternalFrameInfo ? this->GetCachedInternalFrameInfo().function : this->GetCurrentFunctionFromPhysicalFrame();
  335. // If there are inlined frames on the stack, we have to be able to return the byte code offsets of those inlined calls
  336. // from their respective callers. But, we can use the current native address as IP for only the topmost inlined frame.
  337. // TryGetByteCodeOffsetOfInlinee takes care of these conditions and sets up the offset of an inlinee in 'offset', if the
  338. // current inlinee frame is not the topmost of the inlinee frames.
  339. if (HasInlinedFramesOnStack() && TryGetByteCodeOffsetOfInlinee(function, loopNum, pCodeAddr, &inlinee, offset, usedInternalFrameInfo))
  340. {
  341. return true;
  342. }
  343. StatementData data;
  344. if (function->GetFunctionBody() && function->GetFunctionBody()->GetMatchingStatementMapFromNativeAddress(pCodeAddr, data, loopNum, inlinee))
  345. {
  346. offset = data.bytecodeBegin;
  347. return true;
  348. }
  349. return false;
  350. }
  351. uint JavascriptStackWalker::GetLoopNumber(bool& usedInternalFrameInfo) const
  352. {
  353. uint loopNum = LoopHeader::NoLoop;
  354. if (this->lastInternalFrameInfo.codeAddress != nullptr)
  355. {
  356. if (this->lastInternalFrameInfo.frameType == InternalFrameType_LoopBody)
  357. {
  358. AnalysisAssert(this->interpreterFrame);
  359. loopNum = this->interpreterFrame->GetCurrentLoopNum();
  360. Assert(loopNum != LoopHeader::NoLoop);
  361. usedInternalFrameInfo = true;
  362. }
  363. }
  364. else
  365. {
  366. if (this->IsCurrentPhysicalFrameForLoopBody())
  367. {
  368. // Internal frame but codeAddress on lastInternalFrameInfo not set. We must be in an inlined frame in the loop body.
  369. Assert(this->tempInterpreterFrame);
  370. loopNum = this->tempInterpreterFrame->GetCurrentLoopNum();
  371. Assert(loopNum != LoopHeader::NoLoop);
  372. usedInternalFrameInfo = false;
  373. }
  374. }
  375. return loopNum;
  376. }
  377. bool JavascriptStackWalker::TryGetByteCodeOffsetOfInlinee(Js::JavascriptFunction* parentFunction, uint loopNum, DWORD_PTR pCodeAddr, Js::FunctionBody** inlinee, uint32& offset, bool useInternalFrameInfo) const
  378. {
  379. // For inlined frames, translation from native offset -> source code happens in two steps.
  380. // The native offset is first translated into a statement index using the physical frame's
  381. // source context info. This statement index is then looked up in the *inlinee*'s source
  382. // context info to get the bytecode offset.
  383. //
  384. // For all inlined frames contained within a physical frame we have only one offset == (IP - entry).
  385. // Since we can't use that to get the other inlined callers' IPs, we save the IP of all inlined
  386. // callers in their "callinfo" (See InlineeCallInfo). The top most inlined frame uses the IP
  387. // of the physical frame. All other inlined frames use the InlineeStartOffset stored in their call info
  388. // to calculate the byte code offset of the callsite of the inlinee they called.
  389. StatementData data;
  390. uint32 inlineeOffset = 0;
  391. *inlinee = InlinedFramesBeingWalked() ? inlinedFrameWalker.GetFunctionObject()->GetFunctionBody() : nullptr;
  392. InlinedFrameWalker tmpFrameWalker;
  393. if (InlinedFramesBeingWalked())
  394. {
  395. // Inlined frames are being walked right now. The top most frame is where the IP is.
  396. if (!inlinedFrameWalker.IsTopMostFrame())
  397. {
  398. inlineeOffset = inlinedFrameWalker.GetCurrentInlineeOffset();
  399. }
  400. }
  401. else if (ScriptFunction::Test(parentFunction) && HasInlinedFramesOnStack())
  402. {
  403. // Inlined frames are not being walked right now. However, if there
  404. // are inlined frames on the stack the InlineeCallInfo of the first inlined frame
  405. // has the native offset of the current physical frame.
  406. Assert(!*inlinee);
  407. InlinedFrameWalker::FromPhysicalFrame(tmpFrameWalker, currentFrame, ScriptFunction::FromVar(parentFunction), PreviousInterpreterFrameIsFromBailout(), loopNum, this, useInternalFrameInfo, false /*noAlloc*/);
  408. inlineeOffset = tmpFrameWalker.GetBottomMostInlineeOffset();
  409. tmpFrameWalker.Close();
  410. }
  411. if (inlineeOffset != 0 &&
  412. parentFunction->GetFunctionBody()->GetMatchingStatementMapFromNativeOffset(pCodeAddr, inlineeOffset, data, loopNum, *inlinee))
  413. {
  414. offset = data.bytecodeBegin;
  415. return true;
  416. }
  417. return false;
  418. }
  419. bool JavascriptStackWalker::PreviousInterpreterFrameIsFromBailout() const
  420. {
  421. if (lastInternalFrameInfo.codeAddress)
  422. {
  423. return lastInternalFrameInfo.previousInterpreterFrameIsFromBailout;
  424. }
  425. return this->previousInterpreterFrameIsFromBailout;
  426. }
  427. bool JavascriptStackWalker::InlinedFramesBeingWalked() const
  428. {
  429. if (lastInternalFrameInfo.codeAddress)
  430. {
  431. return false;
  432. }
  433. return this->inlinedFramesBeingWalked;
  434. }
  435. bool JavascriptStackWalker::HasInlinedFramesOnStack() const
  436. {
  437. if (lastInternalFrameInfo.codeAddress)
  438. {
  439. return lastInternalFrameInfo.hasInlinedFramesOnStack;
  440. }
  441. return this->hasInlinedFramesOnStack;
  442. }
  443. #endif
  444. bool JavascriptStackWalker::GetSourcePosition(const WCHAR** sourceFileName, ULONG* line, LONG* column)
  445. {
  446. uint byteCodeoffset = this->GetByteCodeOffset();
  447. if(byteCodeoffset)
  448. {
  449. Js::FunctionBody* functionBody = this->GetCurrentFunction()->GetFunctionBody();
  450. if (functionBody->GetLineCharOffset(byteCodeoffset, line, column))
  451. {
  452. if(functionBody->GetUtf8SourceInfo()->IsDynamic())
  453. {
  454. *sourceFileName = _u("Dynamic Code");
  455. }
  456. else
  457. {
  458. *sourceFileName = functionBody->GetUtf8SourceInfo()->GetSrcInfo()->sourceContextInfo->url;
  459. }
  460. return true;
  461. }
  462. }
  463. return false;
  464. }
  465. Js::JavascriptFunction * JavascriptStackWalker::UpdateFrame(bool includeInlineFrames)
  466. {
  467. this->isJavascriptFrame = this->CheckJavascriptFrame(includeInlineFrames);
  468. if (this->IsJavascriptFrame())
  469. {
  470. // In case we have a cross site thunk, update the script context
  471. Js::JavascriptFunction *function = this->GetCurrentFunction();
  472. #if ENABLE_NATIVE_CODEGEN
  473. bool isCurrentPhysicalFrameForLoopBody = this->IsCurrentPhysicalFrameForLoopBody();
  474. #endif
  475. if (this->interpreterFrame)
  476. {
  477. #if ENABLE_NATIVE_CODEGEN
  478. if (lastInternalFrameInfo.codeAddress != nullptr)
  479. {
  480. this->previousInterpreterFrameIsForLoopBody = true;
  481. }
  482. #endif
  483. // We might've bailed out of an inlinee, so check if there were any inlinees.
  484. if (this->interpreterFrame->TestFlags(InterpreterStackFrameFlags_FromBailOut))
  485. {
  486. previousInterpreterFrameIsFromBailout = true;
  487. #if ENABLE_NATIVE_CODEGEN
  488. Assert(!inlinedFramesBeingWalked);
  489. if (includeInlineFrames)
  490. {
  491. int loopNum = -1;
  492. if (isCurrentPhysicalFrameForLoopBody)
  493. {
  494. loopNum = this->tempInterpreterFrame->GetCurrentLoopNum();
  495. }
  496. bool hasInlinedFramesOnStack = InlinedFrameWalker::FromPhysicalFrame(inlinedFrameWalker, currentFrame,
  497. ScriptFunction::FromVar(function), true /*fromBailout*/, loopNum, this, false /*useInternalFrameInfo*/, false /*noAlloc*/);
  498. if (hasInlinedFramesOnStack)
  499. {
  500. // We're now back in the state where currentFrame == physical frame of the inliner, but
  501. // since interpreterFrame != null, we'll pick values from the interpreterFrame (the bailout
  502. // frame of the inliner). Set a flag to tell the stack walker that it needs to start from the
  503. // inlinee frames on the stack when Walk() is called.
  504. this->inlinedFramesBeingWalked = inlinedFrameWalker.Next(inlinedFrameCallInfo);
  505. this->hasInlinedFramesOnStack = hasInlinedFramesOnStack;
  506. Assert(inlinedFramesBeingWalked);
  507. Assert(StackScriptFunction::GetCurrentFunctionObject(this->interpreterFrame->GetJavascriptFunction()) == inlinedFrameWalker.GetFunctionObject());
  508. }
  509. else
  510. {
  511. Assert(!isCurrentPhysicalFrameForLoopBody);
  512. }
  513. }
  514. else if (isCurrentPhysicalFrameForLoopBody)
  515. {
  516. // Getting here is only possible when the current interpreterFrame is for a function which
  517. // encountered a bailout after getting inlined in a jitted loop body. If we are not including
  518. // inlined frames in the stack walk, we need to set the codeAddress on lastInternalFrameInfo,
  519. // which would have otherwise been set upon closing the inlinedFrameWalker, now.
  520. // Note that we already have an assert in CheckJavascriptFrame to ensure this.
  521. SetCachedInternalFrameInfo(InternalFrameType_LoopBody, function, false /*hasInlinedFramesOnStack*/, true /*previousInterpreterFrameIsFromBailout*/);
  522. }
  523. #else
  524. // How did we bail out when JIT was disabled?
  525. Assert(false);
  526. #endif
  527. }
  528. else
  529. {
  530. Assert(StackScriptFunction::GetCurrentFunctionObject(this->interpreterFrame->GetJavascriptFunction()) == function);
  531. previousInterpreterFrameIsFromBailout = false;
  532. }
  533. }
  534. else if (!this->isNativeLibraryFrame)
  535. {
  536. #if ENABLE_NATIVE_CODEGEN
  537. Assert(!HasInlinedFramesOnStack() || (includeInlineFrames && isCurrentPhysicalFrameForLoopBody));
  538. if (!HasInlinedFramesOnStack() && includeInlineFrames)
  539. {
  540. // Check whether there are inlined frames nested in this native frame. The corresponding check for
  541. // a jitted loop body frame should have been done in CheckJavascriptFrame
  542. Assert(lastInternalFrameInfo.codeAddress == nullptr);
  543. bool inlinedFramesFound = InlinedFrameWalker::FromPhysicalFrame(
  544. inlinedFrameWalker,
  545. currentFrame,
  546. ScriptFunction::FromVar(function),
  547. false, // fromBailout
  548. -1, // loopNum
  549. nullptr,// walker
  550. false, // useInternalFrameInfo
  551. false // noAlloc
  552. );
  553. if (inlinedFramesFound)
  554. {
  555. this->inlinedFramesBeingWalked = inlinedFrameWalker.Next(inlinedFrameCallInfo);
  556. this->hasInlinedFramesOnStack = true;
  557. Assert(inlinedFramesBeingWalked);
  558. }
  559. }
  560. #endif
  561. }
  562. this->scriptContext = function->GetScriptContext();
  563. return function;
  564. }
  565. return nullptr;
  566. }
  567. #if ENABLE_NATIVE_CODEGEN
  568. void JavascriptStackWalker::WalkAndClearInlineeFrameCallInfoOnException(void *tryHandlerAddrOfReturnAddr)
  569. {
  570. // Walk the stack and when we find the first native frame, we clear the inlinee's callinfo for this frame
  571. // It is sufficient we stop at the first native frame which had the enclosing try-catch
  572. // TODO : Revisit when we start inlining functions with try-catch/try-finally
  573. while (this->Walk(true))
  574. {
  575. if (JavascriptFunction::IsNativeAddress(this->scriptContext, this->currentFrame.GetInstructionPointer()))
  576. {
  577. if (HasInlinedFramesOnStack())
  578. {
  579. for (int index = inlinedFrameWalker.GetFrameCount() - 1; index >= 0; index--)
  580. {
  581. auto inlinedFrame = inlinedFrameWalker.GetFrameAtIndex(index);
  582. inlinedFrame->callInfo.Clear();
  583. }
  584. }
  585. }
  586. if (this->currentFrame.GetAddressOfReturnAddress() == tryHandlerAddrOfReturnAddr)
  587. {
  588. break;
  589. }
  590. }
  591. }
  592. #endif
  593. // Note: noinline is to make sure that when we unwind to the unwindToAddress, there is at least one frame to unwind.
  594. _NOINLINE
  595. JavascriptStackWalker::JavascriptStackWalker(ScriptContext * scriptContext, bool useEERContext, PVOID returnAddress, bool _forceFullWalk /*=false*/) :
  596. inlinedFrameCallInfo(CallFlags_None, 0), shouldDetectPartiallyInitializedInterpreterFrame(true), forceFullWalk(_forceFullWalk),
  597. previousInterpreterFrameIsFromBailout(false), previousInterpreterFrameIsForLoopBody(false), hasInlinedFramesOnStack(false)
  598. {
  599. if (scriptContext == NULL)
  600. {
  601. Throw::InternalError();
  602. }
  603. this->scriptContext = scriptContext;
  604. // Pull the current script state from the thread context.
  605. ThreadContext * threadContext = scriptContext->GetThreadContext();
  606. this->entryExitRecord = threadContext->GetScriptEntryExit();
  607. this->nativeLibraryEntry = threadContext->PeekNativeLibraryEntry();
  608. this->prevNativeLibraryEntry = nullptr;
  609. this->interpreterFrame = NULL;
  610. this->isJavascriptFrame = false;
  611. this->isNativeLibraryFrame = false;
  612. if (entryExitRecord->frameIdOfScriptExitFunction != NULL)
  613. {
  614. // We're currently outside the script, so grab the frame from which we left.
  615. this->scriptContext = entryExitRecord->scriptContext;
  616. this->isInitialFrame = this->currentFrame.InitializeByFrameId(entryExitRecord->frameIdOfScriptExitFunction, this->scriptContext);
  617. }
  618. else
  619. {
  620. // Just start with the caller
  621. this->isInitialFrame = this->currentFrame.InitializeByReturnAddress(_ReturnAddress(), this->scriptContext);
  622. }
  623. if (useEERContext)
  624. {
  625. this->tempInterpreterFrame = this->scriptContext->GetThreadContext()->GetLeafInterpreterFrame();
  626. }
  627. else
  628. {
  629. // We need to generate stack for the passed script context, so use the leaf interpreter frame for passed script context
  630. this->tempInterpreterFrame = scriptContext->GetThreadContext()->GetLeafInterpreterFrame();
  631. }
  632. inlinedFramesBeingWalked = false;
  633. }
  634. BOOL JavascriptStackWalker::Walk(bool includeInlineFrames)
  635. {
  636. // Walk one frame up the call stack.
  637. this->interpreterFrame = NULL;
  638. #if ENABLE_NATIVE_CODEGEN
  639. if (lastInternalFrameInfo.codeAddress != nullptr && this->previousInterpreterFrameIsForLoopBody)
  640. {
  641. this->previousInterpreterFrameIsForLoopBody = false;
  642. ClearCachedInternalFrameInfo();
  643. }
  644. if (inlinedFramesBeingWalked)
  645. {
  646. Assert(includeInlineFrames);
  647. inlinedFramesBeingWalked = inlinedFrameWalker.Next(inlinedFrameCallInfo);
  648. if (!inlinedFramesBeingWalked)
  649. {
  650. inlinedFrameWalker.Close();
  651. if ((this->IsCurrentPhysicalFrameForLoopBody()))
  652. {
  653. // Done walking inlined frames in a loop body, cache the native code address now
  654. // in order to skip the loop body frame.
  655. this->SetCachedInternalFrameInfo(InternalFrameType_LoopBody, this->GetCurrentFunctionFromPhysicalFrame(), true /*hasInlinedFramesOnStack*/, previousInterpreterFrameIsFromBailout);
  656. isJavascriptFrame = false;
  657. }
  658. }
  659. return true;
  660. }
  661. #endif
  662. this->hasInlinedFramesOnStack = false;
  663. if (this->isInitialFrame)
  664. {
  665. this->isInitialFrame = false; // Only walk initial frame once
  666. }
  667. else if (!this->currentFrame.Next())
  668. {
  669. this->isJavascriptFrame = false;
  670. return false;
  671. }
  672. // If we're at the entry from a host frame, hop to the frame from which we left the script.
  673. if (AlignAndCheckAddressOfReturnAddressMatch(this->currentFrame.GetAddressOfInstructionPointer(), this->entryExitRecord->addrOfReturnAddrOfScriptEntryFunction))
  674. {
  675. BOOL hasCaller = this->entryExitRecord->hasCaller || this->forceFullWalk;
  676. #ifdef CHECK_STACKWALK_EXCEPTION
  677. BOOL ignoreStackWalkException = this->entryExitRecord->ignoreStackWalkException;
  678. #endif
  679. this->entryExitRecord = this->entryExitRecord->next;
  680. if (this->entryExitRecord == NULL)
  681. {
  682. this->isJavascriptFrame = false;
  683. return false;
  684. }
  685. if (!hasCaller && !this->scriptContext->IsDiagnosticsScriptContext())
  686. {
  687. #ifdef CHECK_STACKWALK_EXCEPTION
  688. if (!ignoreStackWalkException)
  689. {
  690. AssertMsg(false, "walk pass no caller frame");
  691. }
  692. #endif
  693. this->isJavascriptFrame = false;
  694. return false;
  695. }
  696. this->scriptContext = this->entryExitRecord->scriptContext;
  697. this->currentFrame.SkipToFrame(this->entryExitRecord->frameIdOfScriptExitFunction);
  698. }
  699. this->UpdateFrame(includeInlineFrames);
  700. return true;
  701. }
  702. BOOL JavascriptStackWalker::GetCallerWithoutInlinedFrames(_Out_opt_ JavascriptFunction ** ppFunc)
  703. {
  704. return GetCaller(ppFunc, /*includeInlineFrames*/ false);
  705. }
  706. BOOL JavascriptStackWalker::GetCaller(_Out_opt_ JavascriptFunction ** ppFunc, bool includeInlineFrames)
  707. {
  708. while (this->Walk(includeInlineFrames))
  709. {
  710. if (this->IsJavascriptFrame())
  711. {
  712. Assert(entryExitRecord != NULL);
  713. if (ppFunc)
  714. {
  715. *ppFunc = this->GetCurrentFunction();
  716. }
  717. AssertMsg(!this->shouldDetectPartiallyInitializedInterpreterFrame, "must have skipped first frame if needed");
  718. return true;
  719. }
  720. }
  721. if (ppFunc)
  722. {
  723. *ppFunc = nullptr;
  724. }
  725. return false;
  726. }
  727. BOOL JavascriptStackWalker::GetNonLibraryCodeCaller(_Out_opt_ JavascriptFunction ** ppFunc)
  728. {
  729. while (this->GetCaller(ppFunc))
  730. {
  731. Assert(ppFunc != nullptr);
  732. __analysis_assume(ppFunc != nullptr);
  733. if (!(*ppFunc)->IsLibraryCode())
  734. {
  735. return true;
  736. }
  737. }
  738. return false;
  739. }
  740. /*static*/
  741. bool JavascriptStackWalker::IsLibraryStackFrameEnabled(Js::ScriptContext * scriptContext)
  742. {
  743. Assert(scriptContext != nullptr);
  744. return CONFIG_FLAG(LibraryStackFrame);
  745. }
  746. // Check if a function is a display caller: user code, or native library / boundary script library code
  747. bool JavascriptStackWalker::IsDisplayCaller(JavascriptFunction* func)
  748. {
  749. FunctionBody* body = func->GetFunctionBody();
  750. if (IsLibraryStackFrameEnabled(func->GetScriptContext()))
  751. {
  752. return !func->IsScriptFunction() || !body->GetUtf8SourceInfo()->GetIsLibraryCode() || body->IsPublicLibraryCode();
  753. }
  754. else
  755. {
  756. return !body->GetUtf8SourceInfo()->GetIsLibraryCode();
  757. }
  758. }
  759. bool JavascriptStackWalker::GetDisplayCaller(_Out_opt_ JavascriptFunction ** ppFunc)
  760. {
  761. while (this->GetCaller(ppFunc))
  762. {
  763. Assert(ppFunc != nullptr);
  764. __analysis_assume(ppFunc != nullptr);
  765. if (IsDisplayCaller(*ppFunc))
  766. {
  767. return true;
  768. }
  769. }
  770. return false;
  771. }
  772. PCWSTR JavascriptStackWalker::GetCurrentNativeLibraryEntryName() const
  773. {
  774. Assert(IsLibraryStackFrameEnabled(this->scriptContext)
  775. && this->prevNativeLibraryEntry
  776. && this->prevNativeLibraryEntry->next == this->nativeLibraryEntry);
  777. return this->prevNativeLibraryEntry->name;
  778. }
  779. // WalkToTarget skips internal frames
  780. BOOL JavascriptStackWalker::WalkToTarget(JavascriptFunction * funcTarget)
  781. {
  782. // Walk up the call stack until we find the frame that belongs to the given function.
  783. while (this->Walk(/*includeInlineFrames*/ true))
  784. {
  785. if (this->IsJavascriptFrame() && this->GetCurrentFunction() == funcTarget)
  786. {
  787. // Skip internal names
  788. Assert( !(this->GetCallInfo().Flags & CallFlags_InternalFrame) );
  789. return true;
  790. }
  791. }
  792. return false;
  793. }
  794. bool JavascriptStackWalker::AlignAndCheckAddressOfReturnAddressMatch(void* addressOfReturnAddress, void* nativeLibraryEntryAddress)
  795. {
  796. return addressOfReturnAddress == nativeLibraryEntryAddress
  797. #if defined(_M_IX86)
  798. // Under some odd cases on x86, addressOfReturnAddress and stashed entry address need to be aligned.
  799. // This happens when code is generated using two stack pointers. One or both have the address of
  800. // return address offset by 4, 8, or 12.
  801. || (((uint)nativeLibraryEntryAddress - (uint)addressOfReturnAddress < 0x10) &&
  802. *(void**)addressOfReturnAddress == *(void**)nativeLibraryEntryAddress
  803. )
  804. #endif
  805. ;
  806. }
  807. void ** JavascriptStackWalker::GetCurrentArgv() const
  808. {
  809. Assert(this->IsJavascriptFrame());
  810. Assert(this->interpreterFrame != nullptr ||
  811. (this->prevNativeLibraryEntry && AlignAndCheckAddressOfReturnAddressMatch(this->currentFrame.GetAddressOfReturnAddress(), this->prevNativeLibraryEntry->addr)) ||
  812. JavascriptFunction::IsNativeAddress(this->scriptContext, (void*)this->currentFrame.GetInstructionPointer()));
  813. bool isNativeAddr = (this->interpreterFrame == nullptr) &&
  814. (!this->prevNativeLibraryEntry || !AlignAndCheckAddressOfReturnAddressMatch(this->currentFrame.GetAddressOfReturnAddress(), this->prevNativeLibraryEntry->addr));
  815. void ** argv = currentFrame.GetArgv(isNativeAddr, false /*shouldCheckForNativeAddr*/);
  816. Assert(argv);
  817. return argv;
  818. }
  819. bool JavascriptStackWalker::CheckJavascriptFrame(bool includeInlineFrames)
  820. {
  821. this->isNativeLibraryFrame = false; // Clear previous result
  822. void * codeAddr = this->currentFrame.GetInstructionPointer();
  823. if (this->tempInterpreterFrame && codeAddr == this->tempInterpreterFrame->GetReturnAddress())
  824. {
  825. bool isBailoutInterpreter = this->tempInterpreterFrame->TestFlags(Js::InterpreterStackFrameFlags_FromBailOut);
  826. // We need to skip over the first interpreter frame on the stack if it is the partially initialized frame
  827. // otherwise it is a real frame and we should continue.
  828. // For fully initialized frames (PushPopHelper was called) the thunk stack addr is equal or below addressOfReturnAddress
  829. // as the latter one is obtained in InterpreterStackFrame::InterpreterThunk called by the thunk.
  830. bool isPartiallyInitializedFrame = this->shouldDetectPartiallyInitializedInterpreterFrame &&
  831. this->currentFrame.GetAddressOfReturnAddress(isBailoutInterpreter /*isCurrentContextNative*/, false /*shouldCheckForNativeAddr*/) < this->tempInterpreterFrame->GetAddressOfReturnAddress();
  832. this->shouldDetectPartiallyInitializedInterpreterFrame = false;
  833. if (isPartiallyInitializedFrame)
  834. {
  835. return false; // Skip it.
  836. }
  837. void ** argv = this->currentFrame.GetArgv(isBailoutInterpreter /*isCurrentContextNative*/, false /*shouldCheckForNativeAddr*/);
  838. if (argv == nullptr)
  839. {
  840. // NOTE: When we switch to walking the stack ourselves and skip non engine frames, this should never happen.
  841. return false;
  842. }
  843. this->interpreterFrame = this->tempInterpreterFrame;
  844. this->tempInterpreterFrame = this->interpreterFrame->GetPreviousFrame();
  845. #if ENABLE_NATIVE_CODEGEN
  846. #if DBG
  847. if (((CallInfo const *)&argv[JavascriptFunctionArgIndex_CallInfo])->Flags & CallFlags_InternalFrame)
  848. {
  849. // The return address of the interpreterFrame is the same as the entryPoint for a jitted loop body.
  850. // This can only ever happen when we have bailed out from a function inlined in the loop body. We
  851. // wouldn't have created a new interpreterFrame if the bailout were from the loop body itself.
  852. Assert(this->interpreterFrame->TestFlags(Js::InterpreterStackFrameFlags_FromBailOut));
  853. InlinedFrameWalker tmpFrameWalker;
  854. Assert(InlinedFrameWalker::FromPhysicalFrame(tmpFrameWalker, currentFrame, Js::ScriptFunction::FromVar(argv[JavascriptFunctionArgIndex_Function]),
  855. true /*fromBailout*/, this->tempInterpreterFrame->GetCurrentLoopNum(), this, false /*useInternalFrameInfo*/, true /*noAlloc*/));
  856. tmpFrameWalker.Close();
  857. }
  858. #endif //DBG
  859. #endif //ENABLE_NATIVE_CODEGEN
  860. return true;
  861. }
  862. if (IsLibraryStackFrameEnabled(this->scriptContext) && this->nativeLibraryEntry)
  863. {
  864. void* addressOfReturnAddress = this->currentFrame.GetAddressOfReturnAddress();
  865. void* nativeLibraryEntryAddress = this->nativeLibraryEntry->addr;
  866. AssertMsg(addressOfReturnAddress <= nativeLibraryEntryAddress, "Missed matching native library entry?");
  867. if (AlignAndCheckAddressOfReturnAddressMatch(addressOfReturnAddress, nativeLibraryEntryAddress))
  868. {
  869. this->isNativeLibraryFrame = true;
  870. this->shouldDetectPartiallyInitializedInterpreterFrame = false;
  871. this->prevNativeLibraryEntry = this->nativeLibraryEntry; // Saves match in prevNativeLibraryEntry
  872. this->nativeLibraryEntry = this->nativeLibraryEntry->next;
  873. return true;
  874. }
  875. }
  876. #if ENABLE_NATIVE_CODEGEN
  877. BOOL isNativeAddr = JavascriptFunction::IsNativeAddress(this->scriptContext, codeAddr);
  878. if (isNativeAddr)
  879. {
  880. this->shouldDetectPartiallyInitializedInterpreterFrame = false;
  881. void ** argv = this->currentFrame.GetArgv(true /*isCurrentContextNative*/, false /*shouldCheckForNativeAddr*/);
  882. if (argv == nullptr)
  883. {
  884. // NOTE: When we switch to walking the stack ourselves and skip non engine frames, this should never happen.
  885. return false;
  886. }
  887. ScriptFunction* funcObj = Js::ScriptFunction::FromVar(argv[JavascriptFunctionArgIndex_Function]);
  888. if (funcObj->GetFunctionBody()->GetIsAsmjsMode())
  889. {
  890. return false;
  891. }
  892. // Note: this check has to happen after asm.js check, because call info is not valid for asm.js
  893. if (((CallInfo const *)&argv[JavascriptFunctionArgIndex_CallInfo])->Flags & CallFlags_InternalFrame)
  894. {
  895. if (includeInlineFrames &&
  896. InlinedFrameWalker::FromPhysicalFrame(inlinedFrameWalker, currentFrame, Js::ScriptFunction::FromVar(argv[JavascriptFunctionArgIndex_Function]),
  897. false /*fromBailout*/, this->tempInterpreterFrame->GetCurrentLoopNum(), this, false /*useInternalFrameInfo*/, false /*noAlloc*/))
  898. {
  899. // Found inlined frames in a jitted loop body. We dont want to skip the inlined frames; walk all of them before setting codeAddress on lastInternalFrameInfo.
  900. // DeepCopy here because, if there is an inlinee in a loop body, FromPhysicalFrame won't be called from UpdateFrame
  901. this->inlinedFramesBeingWalked = inlinedFrameWalker.Next(inlinedFrameCallInfo);
  902. this->hasInlinedFramesOnStack = true;
  903. Assert(inlinedFramesBeingWalked);
  904. return true;
  905. }
  906. SetCachedInternalFrameInfo(InternalFrameType_LoopBody, funcObj, false /*hasInlinedFramesOnStack*/, previousInterpreterFrameIsFromBailout);
  907. return false;
  908. }
  909. return true;
  910. }
  911. #endif
  912. return false;
  913. }
  914. void * JavascriptStackWalker::GetCurrentCodeAddr() const
  915. {
  916. return this->currentFrame.GetInstructionPointer();
  917. }
  918. JavascriptFunction * JavascriptStackWalker::GetCurrentFunction(bool includeInlinedFrames /* = true */) const
  919. {
  920. Assert(this->IsJavascriptFrame());
  921. #if ENABLE_NATIVE_CODEGEN
  922. if (includeInlinedFrames && inlinedFramesBeingWalked)
  923. {
  924. return inlinedFrameWalker.GetFunctionObject();
  925. }
  926. else
  927. #endif
  928. if (this->isNativeLibraryFrame)
  929. {
  930. // Return saved function. Do not read from stack as compiler may stackpack/optimize args.
  931. return JavascriptFunction::FromVar(this->prevNativeLibraryEntry->function);
  932. }
  933. else
  934. {
  935. return StackScriptFunction::GetCurrentFunctionObject((JavascriptFunction *)this->GetCurrentArgv()[JavascriptFunctionArgIndex_Function]);
  936. }
  937. }
  938. void JavascriptStackWalker::SetCurrentFunction(JavascriptFunction * function)
  939. {
  940. Assert(this->IsJavascriptFrame());
  941. #if ENABLE_NATIVE_CODEGEN
  942. if (inlinedFramesBeingWalked)
  943. {
  944. inlinedFrameWalker.SetFunctionObject(function);
  945. }
  946. else
  947. #endif
  948. {
  949. this->GetCurrentArgv()[JavascriptFunctionArgIndex_Function] = function;
  950. }
  951. }
  952. JavascriptFunction *JavascriptStackWalker::GetCurrentFunctionFromPhysicalFrame() const
  953. {
  954. return GetCurrentFunction(false);
  955. }
  956. CallInfo JavascriptStackWalker::GetCallInfo(bool includeInlinedFrames /* = true */) const
  957. {
  958. Assert(this->IsJavascriptFrame());
  959. CallInfo callInfo;
  960. if (includeInlinedFrames && inlinedFramesBeingWalked)
  961. {
  962. // Since we don't support inlining constructors yet, its questionable if we should handle the
  963. // hidden frame display here?
  964. callInfo = inlinedFrameCallInfo;
  965. }
  966. else if (this->GetCurrentFunction()->GetFunctionInfo()->IsCoroutine())
  967. {
  968. JavascriptGenerator* gen = JavascriptGenerator::FromVar(this->GetCurrentArgv()[JavascriptFunctionArgIndex_This]);
  969. callInfo = gen->GetArguments().Info;
  970. }
  971. else if (this->isNativeLibraryFrame)
  972. {
  973. // Return saved callInfo. Do not read from stack as compiler may stackpack/optimize args.
  974. callInfo = this->prevNativeLibraryEntry->callInfo;
  975. }
  976. else
  977. {
  978. callInfo = *(CallInfo const *)&this->GetCurrentArgv()[JavascriptFunctionArgIndex_CallInfo];
  979. }
  980. if (callInfo.Flags & Js::CallFlags_ExtraArg)
  981. {
  982. callInfo.Flags = (CallFlags)(callInfo.Flags & ~Js::CallFlags_ExtraArg);
  983. }
  984. return callInfo;
  985. }
  986. CallInfo JavascriptStackWalker::GetCallInfoFromPhysicalFrame() const
  987. {
  988. return GetCallInfo(false);
  989. }
  990. Var JavascriptStackWalker::GetThisFromFrame() const
  991. {
  992. Assert(!inlinedFramesBeingWalked);
  993. Assert(this->IsJavascriptFrame());
  994. if (this->GetCurrentFunction()->GetFunctionInfo()->IsCoroutine())
  995. {
  996. JavascriptGenerator* gen = JavascriptGenerator::FromVar(this->GetCurrentArgv()[JavascriptFunctionArgIndex_This]);
  997. return gen->GetArguments()[0];
  998. }
  999. return this->GetCurrentArgv()[JavascriptFunctionArgIndex_This];
  1000. }
  1001. #if ENABLE_NATIVE_CODEGEN
  1002. void JavascriptStackWalker::ClearCachedInternalFrameInfo()
  1003. {
  1004. this->lastInternalFrameInfo.Clear();
  1005. }
  1006. void JavascriptStackWalker::SetCachedInternalFrameInfo(InternalFrameType frameType, JavascriptFunction* function, bool hasInlinedFramesOnStack, bool previousInterpreterFrameIsFromBailout)
  1007. {
  1008. if (!this->lastInternalFrameInfo.codeAddress)
  1009. {
  1010. this->lastInternalFrameInfo.Set(
  1011. this->GetCurrentCodeAddr(),
  1012. this->currentFrame.GetFrame(),
  1013. this->currentFrame.GetStackCheckCodeHeight(),
  1014. frameType,
  1015. function,
  1016. hasInlinedFramesOnStack,
  1017. previousInterpreterFrameIsFromBailout);
  1018. }
  1019. }
  1020. #endif
  1021. bool JavascriptStackWalker::IsCurrentPhysicalFrameForLoopBody() const
  1022. {
  1023. return !!(this->GetCallInfoFromPhysicalFrame().Flags & CallFlags_InternalFrame);
  1024. }
  1025. bool JavascriptStackWalker::IsWalkable(ScriptContext *scriptContext)
  1026. {
  1027. if (scriptContext == NULL)
  1028. {
  1029. return false;
  1030. }
  1031. ThreadContext *threadContext = scriptContext->GetThreadContext();
  1032. if (threadContext == NULL)
  1033. {
  1034. return false;
  1035. }
  1036. return (threadContext->GetScriptEntryExit() != NULL);
  1037. }
  1038. BOOL JavascriptStackWalker::GetCaller(_Out_opt_ JavascriptFunction** ppFunc, ScriptContext* scriptContext)
  1039. {
  1040. if (!IsWalkable(scriptContext))
  1041. {
  1042. if (ppFunc)
  1043. {
  1044. *ppFunc = nullptr;
  1045. }
  1046. return FALSE;
  1047. }
  1048. JavascriptStackWalker walker(scriptContext);
  1049. return walker.GetCaller(ppFunc);
  1050. }
  1051. BOOL JavascriptStackWalker::GetCaller(_Out_opt_ JavascriptFunction** ppFunc, uint32* byteCodeOffset, ScriptContext* scriptContext)
  1052. {
  1053. JavascriptStackWalker walker(scriptContext);
  1054. if (walker.GetCaller(ppFunc))
  1055. {
  1056. *byteCodeOffset = walker.GetByteCodeOffset();
  1057. return TRUE;
  1058. }
  1059. return FALSE;
  1060. }
  1061. void JavascriptStackWalker::GetThis(Var* pThis, int moduleId, ScriptContext* scriptContext)
  1062. {
  1063. JavascriptStackWalker walker(scriptContext);
  1064. JavascriptFunction* caller;
  1065. if (walker.GetCaller(&caller))
  1066. {
  1067. walker.GetThis(pThis, moduleId);
  1068. }
  1069. }
  1070. void JavascriptStackWalker::GetThis(Var* pThis, int moduleId, JavascriptFunction* func, ScriptContext* scriptContext)
  1071. {
  1072. JavascriptStackWalker walker(scriptContext);
  1073. JavascriptFunction* caller;
  1074. while (walker.GetCaller(&caller))
  1075. {
  1076. if (caller == func)
  1077. {
  1078. walker.GetThis(pThis, moduleId);
  1079. return;
  1080. }
  1081. }
  1082. }
  1083. // Try to see whether there is a top-most javascript frame, and if there is return true if it's native.
  1084. // Returns true if top most frame is javascript frame, in this case the isNative parameter receives true
  1085. // when top-most frame is native, false otherwise.
  1086. // Returns false if top most frame is not a JavaScript frame.
  1087. /* static */
  1088. bool JavascriptStackWalker::TryIsTopJavaScriptFrameNative(ScriptContext* scriptContext, bool* isNative, bool ignoreLibraryCode /* = false */)
  1089. {
  1090. Assert(scriptContext);
  1091. Assert(isNative);
  1092. Js::JavascriptFunction* caller;
  1093. Js::JavascriptStackWalker walker(scriptContext);
  1094. BOOL isSuccess;
  1095. if (ignoreLibraryCode)
  1096. {
  1097. isSuccess = walker.GetNonLibraryCodeCaller(&caller);
  1098. }
  1099. else
  1100. {
  1101. isSuccess = walker.GetCaller(&caller);
  1102. }
  1103. if (isSuccess)
  1104. {
  1105. *isNative = (walker.GetCurrentInterpreterFrame() == NULL);
  1106. return true;
  1107. }
  1108. return false;
  1109. }
  1110. #if ENABLE_NATIVE_CODEGEN
  1111. bool InlinedFrameWalker::FromPhysicalFrame(InlinedFrameWalker& self, StackFrame& physicalFrame, Js::ScriptFunction *parent, bool fromBailout,
  1112. int loopNum, const JavascriptStackWalker * const stackWalker, bool useInternalFrameInfo, bool noAlloc)
  1113. {
  1114. bool inlinedFramesFound = false;
  1115. FunctionBody* parentFunctionBody = parent->GetFunctionBody();
  1116. EntryPointInfo *entryPointInfo;
  1117. if (loopNum != -1)
  1118. {
  1119. Assert(stackWalker);
  1120. }
  1121. void *nativeCodeAddress = nullptr;
  1122. void *framePointer = nullptr;
  1123. if (loopNum != -1 && useInternalFrameInfo)
  1124. {
  1125. Assert(stackWalker->GetCachedInternalFrameInfo().codeAddress != nullptr);
  1126. InternalFrameInfo lastInternalFrameInfo = stackWalker->GetCachedInternalFrameInfo();
  1127. nativeCodeAddress = lastInternalFrameInfo.codeAddress;
  1128. framePointer = lastInternalFrameInfo.framePointer;
  1129. }
  1130. else
  1131. {
  1132. nativeCodeAddress = physicalFrame.GetInstructionPointer();
  1133. framePointer = physicalFrame.GetFrame();
  1134. }
  1135. if (loopNum != -1)
  1136. {
  1137. entryPointInfo = (Js::EntryPointInfo*)parentFunctionBody->GetLoopEntryPointInfoFromNativeAddress((DWORD_PTR)nativeCodeAddress, loopNum);
  1138. }
  1139. else
  1140. {
  1141. entryPointInfo = (Js::EntryPointInfo*)parentFunctionBody->GetEntryPointFromNativeAddress((DWORD_PTR)nativeCodeAddress);
  1142. }
  1143. AssertMsg(entryPointInfo != nullptr, "Inlined frame should resolve to the right parent address");
  1144. if (entryPointInfo->HasInlinees())
  1145. {
  1146. void *entry = reinterpret_cast<void*>(entryPointInfo->GetNativeAddress());
  1147. InlinedFrameWalker::InlinedFrame *outerMostFrame = InlinedFrame::FromPhysicalFrame(physicalFrame, stackWalker, entry, entryPointInfo, useInternalFrameInfo);
  1148. if (!outerMostFrame)
  1149. {
  1150. return inlinedFramesFound;
  1151. }
  1152. if (!fromBailout)
  1153. {
  1154. InlineeFrameRecord* record = entryPointInfo->FindInlineeFrame((void*)nativeCodeAddress);
  1155. if (record)
  1156. {
  1157. record->RestoreFrames(parent->GetFunctionBody(), outerMostFrame, JavascriptCallStackLayout::FromFramePointer(framePointer), false /* boxValues */);
  1158. }
  1159. }
  1160. if (outerMostFrame->callInfo.Count)
  1161. {
  1162. inlinedFramesFound = true;
  1163. if (noAlloc)
  1164. {
  1165. return inlinedFramesFound;
  1166. }
  1167. int32 frameCount = 0;
  1168. InlinedFrameWalker::InlinedFrame *frameIterator = outerMostFrame;
  1169. while (frameIterator->callInfo.Count)
  1170. {
  1171. frameCount++;
  1172. frameIterator = frameIterator->Next();
  1173. }
  1174. InlinedFrameWalker::InlinedFrame **frames = HeapNewArray(InlinedFrameWalker::InlinedFrame*, frameCount);
  1175. frameIterator = outerMostFrame;
  1176. for (int index = frameCount - 1; index >= 0; index--)
  1177. {
  1178. Assert(frameIterator);
  1179. frames[index] = frameIterator;
  1180. frameIterator = frameIterator->Next();
  1181. }
  1182. self.Initialize(frameCount, frames, parent);
  1183. }
  1184. }
  1185. return inlinedFramesFound;
  1186. }
  1187. void InlinedFrameWalker::Close()
  1188. {
  1189. parentFunction = nullptr;
  1190. HeapDeleteArray(frameCount, frames);
  1191. frames = nullptr;
  1192. currentIndex = -1;
  1193. frameCount = 0;
  1194. }
  1195. bool InlinedFrameWalker::Next(CallInfo& callInfo)
  1196. {
  1197. MoveNext();
  1198. InlinedFrameWalker::InlinedFrame *const currentFrame = GetCurrentFrame();
  1199. if (currentFrame)
  1200. {
  1201. callInfo.Flags = CallFlags_None;
  1202. callInfo.Count = (currentFrame->callInfo.Count & 0xFFFF);
  1203. }
  1204. return currentFrame != nullptr;
  1205. }
  1206. size_t InlinedFrameWalker::GetArgc() const
  1207. {
  1208. InlinedFrameWalker::InlinedFrame *const currentFrame = GetCurrentFrame();
  1209. Assert(currentFrame);
  1210. return currentFrame->callInfo.Count;
  1211. }
  1212. // Note: the boxArgsAndDeepCopy parameter should be true when a copy of the JS args must be ensured to
  1213. // be on the heap. This results in a new array of Vars with deep copied boxed values (where
  1214. // appropriate).
  1215. // Otherwise, this parameter should be false. For instance, if the args will only be used
  1216. // internally to gather type info, the values are not boxed (so, some Vars may still be on
  1217. // the stack) and the array of the current frame is returned.
  1218. Js::Var *InlinedFrameWalker::GetArgv(bool includeThis, bool boxArgsAndDeepCopy) const
  1219. {
  1220. InlinedFrameWalker::InlinedFrame *const currentFrame = GetCurrentFrame();
  1221. Assert(currentFrame);
  1222. uint firstArg = includeThis ? InlinedFrameArgIndex_This : InlinedFrameArgIndex_SecondScriptArg;
  1223. size_t argCount = this->GetArgc() - firstArg;
  1224. Js::Var *args;
  1225. if (!boxArgsAndDeepCopy)
  1226. {
  1227. args = &currentFrame->argv[firstArg];
  1228. }
  1229. else
  1230. {
  1231. args = RecyclerNewArray(parentFunction->GetScriptContext()->GetRecycler(), Js::Var, argCount);
  1232. for (size_t i = 0; i < argCount; i++)
  1233. {
  1234. args[i] = currentFrame->argv[firstArg + i];
  1235. }
  1236. this->FinalizeStackValues(args, argCount, true /*deepCopy*/);
  1237. }
  1238. return args;
  1239. }
  1240. void InlinedFrameWalker::FinalizeStackValues(__in_ecount(argCount) Js::Var args[], size_t argCount, bool deepCopy) const
  1241. {
  1242. ScriptContext *scriptContext = this->GetFunctionObject()->GetScriptContext();
  1243. for (size_t i = 0; i < argCount; i++)
  1244. {
  1245. args[i] = Js::JavascriptOperators::BoxStackInstance(args[i], scriptContext, false /*allowStackFunction*/, deepCopy);
  1246. }
  1247. }
  1248. Js::JavascriptFunction *InlinedFrameWalker::GetFunctionObject() const
  1249. {
  1250. InlinedFrameWalker::InlinedFrame *const currentFrame = GetCurrentFrame();
  1251. Assert(currentFrame);
  1252. return StackScriptFunction::GetCurrentFunctionObject(currentFrame->function);
  1253. }
  1254. void InlinedFrameWalker::SetFunctionObject(Js::JavascriptFunction * function)
  1255. {
  1256. InlinedFrameWalker::InlinedFrame *const currentFrame = GetCurrentFrame();
  1257. Assert(currentFrame);
  1258. currentFrame->function = function;
  1259. }
  1260. Js::Var InlinedFrameWalker::GetArgumentsObject() const
  1261. {
  1262. InlinedFrameWalker::InlinedFrame *const currentFrame = GetCurrentFrame();
  1263. Assert(currentFrame);
  1264. return currentFrame->arguments;
  1265. }
  1266. void InlinedFrameWalker::SetArgumentsObject(Js::Var arguments)
  1267. {
  1268. InlinedFrameWalker::InlinedFrame *currentFrame = (InlinedFrameWalker::InlinedFrame *)GetCurrentFrame();
  1269. Assert(currentFrame);
  1270. currentFrame->arguments = arguments;
  1271. }
  1272. Js::Var InlinedFrameWalker::GetThisObject() const
  1273. {
  1274. InlinedFrameWalker::InlinedFrame *const currentFrame = GetCurrentFrame();
  1275. Assert(currentFrame);
  1276. return currentFrame->argv[InlinedFrameArgIndex_This];
  1277. }
  1278. bool InlinedFrameWalker::IsCallerPhysicalFrame() const
  1279. {
  1280. return currentIndex == (frameCount - 1);
  1281. }
  1282. bool InlinedFrameWalker::IsTopMostFrame() const
  1283. {
  1284. return currentIndex == 0;
  1285. }
  1286. uint32 InlinedFrameWalker::GetCurrentInlineeOffset() const
  1287. {
  1288. Assert(!IsTopMostFrame());
  1289. Assert(currentIndex);
  1290. return GetFrameAtIndex(currentIndex - 1)->callInfo.InlineeStartOffset;
  1291. }
  1292. uint32 InlinedFrameWalker::GetBottomMostInlineeOffset() const
  1293. {
  1294. Assert(frameCount);
  1295. return GetFrameAtIndex(frameCount - 1)->callInfo.InlineeStartOffset;
  1296. }
  1297. Js::JavascriptFunction *InlinedFrameWalker::GetBottomMostFunctionObject() const
  1298. {
  1299. Assert(frameCount);
  1300. return GetFrameAtIndex(frameCount - 1)->function;
  1301. }
  1302. InlinedFrameWalker::InlinedFrame *const InlinedFrameWalker::GetCurrentFrame() const
  1303. {
  1304. return GetFrameAtIndex(currentIndex);
  1305. }
  1306. InlinedFrameWalker::InlinedFrame *const InlinedFrameWalker::GetFrameAtIndex(signed index) const
  1307. {
  1308. Assert(frames);
  1309. Assert(frameCount);
  1310. InlinedFrameWalker::InlinedFrame *frame = nullptr;
  1311. if (index < frameCount)
  1312. {
  1313. frame = frames[index];
  1314. }
  1315. return frame;
  1316. }
  1317. void InlinedFrameWalker::MoveNext()
  1318. {
  1319. currentIndex++;
  1320. }
  1321. void InlinedFrameWalker::Initialize(int32 frameCount, __in_ecount(frameCount) InlinedFrame **frames, Js::ScriptFunction *parent)
  1322. {
  1323. Assert(!parentFunction);
  1324. Assert(!this->frames);
  1325. Assert(!this->frameCount);
  1326. Assert(currentIndex == -1);
  1327. this->parentFunction = parent;
  1328. this->frames = frames;
  1329. this->frameCount = frameCount;
  1330. this->currentIndex = -1;
  1331. }
  1332. InlinedFrameWalker::InlinedFrame* InlinedFrameWalker::InlinedFrame::FromPhysicalFrame(StackFrame& currentFrame, const JavascriptStackWalker * const stackWalker, void *entry, EntryPointInfo* entryPointInfo, bool useInternalFrameInfo)
  1333. {
  1334. // If the current javascript frame is a native frame, get the inlined frame from it, otherwise
  1335. // it may be possible that current frame is the interpreter frame for a jitted loop body
  1336. // If the loop body had some inlinees in it, retrieve the inlined frame using the cached info,
  1337. // viz. instruction pointer, frame pointer, and stackCheckCodeHeight, about the loop body frame.
  1338. struct InlinedFrame *inlinedFrame = nullptr;
  1339. void *codeAddr, *framePointer;
  1340. size_t stackCheckCodeHeight;
  1341. if (useInternalFrameInfo)
  1342. {
  1343. codeAddr = stackWalker->GetCachedInternalFrameInfo().codeAddress;
  1344. framePointer = stackWalker->GetCachedInternalFrameInfo().framePointer;
  1345. stackCheckCodeHeight = stackWalker->GetCachedInternalFrameInfo().stackCheckCodeHeight;
  1346. }
  1347. else
  1348. {
  1349. codeAddr = currentFrame.GetInstructionPointer();
  1350. framePointer = currentFrame.GetFrame();
  1351. stackCheckCodeHeight = currentFrame.GetStackCheckCodeHeight();
  1352. }
  1353. if (!StackFrame::IsInStackCheckCode(entry, codeAddr, stackCheckCodeHeight))
  1354. {
  1355. inlinedFrame = (struct InlinedFrame *)(((uint8 *)framePointer) - entryPointInfo->GetFrameHeight());
  1356. }
  1357. return inlinedFrame;
  1358. }
  1359. void InternalFrameInfo::Set(
  1360. void *codeAddress,
  1361. void *framePointer,
  1362. size_t stackCheckCodeHeight,
  1363. InternalFrameType frameType,
  1364. JavascriptFunction* function,
  1365. bool hasInlinedFramesOnStack,
  1366. bool previousInterpreterFrameIsFromBailout)
  1367. {
  1368. // We skip a jitted loop body's native frame when walking the stack and refer to the loop body's interpreter frame to get the function.
  1369. // However, if the loop body has inlinees, to retrieve inlinee frames we need to cache some info about the loop body's native frame.
  1370. this->codeAddress = codeAddress;
  1371. this->framePointer = framePointer;
  1372. this->stackCheckCodeHeight = stackCheckCodeHeight;
  1373. this->frameType = frameType;
  1374. this->function = function;
  1375. this->hasInlinedFramesOnStack = hasInlinedFramesOnStack;
  1376. this->previousInterpreterFrameIsFromBailout = previousInterpreterFrameIsFromBailout;
  1377. }
  1378. void InternalFrameInfo::Clear()
  1379. {
  1380. this->codeAddress = nullptr;
  1381. this->framePointer = nullptr;
  1382. this->stackCheckCodeHeight = (uint)-1;
  1383. this->frameType = InternalFrameType_None;
  1384. this->function = nullptr;
  1385. this->hasInlinedFramesOnStack = false;
  1386. this->previousInterpreterFrameIsFromBailout = false;
  1387. }
  1388. #endif
  1389. #if DBG
  1390. // Force a stack walk which till we find an interpreter frame
  1391. // This will ensure inlined frames are decoded.
  1392. bool JavascriptStackWalker::ValidateTopJitFrame(Js::ScriptContext* scriptContext)
  1393. {
  1394. if (!Configuration::Global.flags.ValidateInlineStack)
  1395. {
  1396. return true;
  1397. }
  1398. Js::JavascriptStackWalker walker(scriptContext);
  1399. Js::JavascriptFunction* function;
  1400. while (walker.GetCaller(&function))
  1401. {
  1402. Assert(function);
  1403. if (walker.GetCurrentInterpreterFrame() != nullptr)
  1404. {
  1405. break;
  1406. }
  1407. }
  1408. // If no asserts have fired yet - we should have succeeded.
  1409. return true;
  1410. }
  1411. #endif
  1412. }