text: //-------------------------------------------------------------------------------------------------------
  // Copyright (C) Microsoft. All rights reserved.
  // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  //-------------------------------------------------------------------------------------------------------
  #include "RuntimeLanguagePch.h"
  #include "Language/JavascriptFunctionArgIndex.h"
  #include "Language/InterpreterStackFrame.h"
  
  #define FAligned(VALUE, TYPE) ((((LONG_PTR)VALUE) & (sizeof(TYPE)-1)) == 0)
  
  #define AlignIt(VALUE, TYPE) (~(~((LONG_PTR)(VALUE) + (sizeof(TYPE)-1)) | (sizeof(TYPE)-1)))
  
  namespace Js
  {
      Js::ArgumentsObject * JavascriptCallStackLayout::GetArgumentsObject() const
      {
          return (Js::ArgumentsObject *)((void **)this)[JavascriptFunctionArgIndex_ArgumentsObject];
      }
  
      Js::Var* JavascriptCallStackLayout::GetArgumentsObjectLocation() const
      {
          return (Js::Var *)&((void **)this)[JavascriptFunctionArgIndex_ArgumentsObject];
      }
  
      void JavascriptCallStackLayout::SetArgumentsObject(Js::ArgumentsObject * obj)
      {
          ((void **)this)[JavascriptFunctionArgIndex_ArgumentsObject] =  obj;
      }
  
      Js::Var JavascriptCallStackLayout::GetOffset(int offset) const
      {
          Js::Var *varPtr = (Js::Var *)(((char *)this) + offset);
          Assert(FAligned(varPtr, Js::Var));
          return *varPtr;
      }
      double JavascriptCallStackLayout::GetDoubleAtOffset(int offset) const
      {
          double *dblPtr = (double *)(((char *)this) + offset);
  #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
          if (Js::Configuration::Global.flags.IsEnabled(Js::CheckAlignmentFlag))
          {
              Assert(FAligned(dblPtr, double));
          }
  #endif
          return *dblPtr;
      }
  
      int32 JavascriptCallStackLayout::GetInt32AtOffset(int offset) const
      {
          int32 *intPtr = (int32 *)(((char *)this) + offset);
  #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
          if (Js::Configuration::Global.flags.IsEnabled(Js::CheckAlignmentFlag))
          {
              Assert(FAligned(intPtr, int32));
          }
  #endif
          return *intPtr;
      }
  
      SIMDValue JavascriptCallStackLayout::GetSimdValueAtOffset(int offset) const
      {
          return  *((SIMDValue *)(((char *)this) + offset));
      }
  
      char * JavascriptCallStackLayout::GetValueChangeOffset(int offset) const
      {
          Js::Var *varPtr = (Js::Var *)(((char *)this) + offset);
          Assert(FAligned(varPtr, Js::Var));
          return (char *)varPtr;
      }
  
      ForInObjectEnumerator * JavascriptCallStackLayout::GetForInObjectEnumeratorArrayAtOffset(int offset) const
      {
          return (ForInObjectEnumerator *)(((char *)this) + offset);
      }
  
      JavascriptCallStackLayout *JavascriptCallStackLayout::FromFramePointer(void *const framePointer)
      {
          return
              reinterpret_cast<JavascriptCallStackLayout *>(
                  static_cast<void **>(framePointer) + (JavascriptFunctionArgIndex_Function - JavascriptFunctionArgIndex_Frame));
      }
  
  
      void* const JavascriptCallStackLayout::ToFramePointer(JavascriptCallStackLayout* callstackLayout)
      {
          return
              reinterpret_cast<void * const>(
                  reinterpret_cast<void **>(callstackLayout) - (JavascriptFunctionArgIndex_Function - JavascriptFunctionArgIndex_Frame));
      }
  
      Js::Var* JavascriptCallStackLayout::GetArgv() const
      {
          return const_cast<Js::Var*>(&this->args[0]);
      }
  
      ScriptContext* JavascriptStackWalker::GetCurrentScriptContext() const
      {
          return this->GetCurrentInterpreterFrame() ? this->GetCurrentInterpreterFrame()->GetScriptContext() : this->scriptContext;
      }
  
      Var JavascriptStackWalker::GetCurrentArgumentsObject() const
      {
  #if ENABLE_PROFILE_INFO
          if (interpreterFrame)
  #else
          Assert(interpreterFrame);
  #endif
          {
              return interpreterFrame->GetArgumentsObject();
          }
  #if ENABLE_NATIVE_CODEGEN
          else
          {
              if (inlinedFramesBeingWalked)
              {
                  return inlinedFrameWalker.GetArgumentsObject();
              }
              else
              {
                  return this->GetCurrentNativeArgumentsObject();
              }
          }
  #endif
      }
  
      void JavascriptStackWalker::SetCurrentArgumentsObject(Var args)
      {
  #if ENABLE_NATIVE_CODEGEN
          if (interpreterFrame)
  #else
          Assert(interpreterFrame);
  #endif
          {
              interpreterFrame->SetArgumentsObject(args);
          }
  #if ENABLE_NATIVE_CODEGEN
          else
          {
              if (inlinedFramesBeingWalked)
              {
                  inlinedFrameWalker.SetArgumentsObject(args);
              }
              else
              {
                  this->SetCurrentNativeArgumentsObject(args);
              }
          }
  #endif
      }
  
      Var JavascriptStackWalker::GetPermanentArguments() const
      {
          Assert(IsJavascriptFrame());
          AssertMsg(this->GetCurrentFunction()->IsScriptFunction(), "GetPermanentArguments should not be called for non-script function as there is no slot allocated for it.");
  
          const uint32 paramCount = GetCallInfo().Count;
          if (paramCount == 0)
          {
              // glob function doesn't allocate ArgumentsObject slot on stack
              return nullptr;
          }
  
          // Get the heap-allocated args for this frame.
          Var args = this->GetCurrentArgumentsObject();
          if (args && ArgumentsObject::Is(args))
          {
              args = ((ArgumentsObject*)args)->GetHeapArguments();
          }
          return args;
      }
  
      BOOL JavascriptStackWalker::WalkToArgumentsFrame(ArgumentsObject *args)
      {
          // Move the walker up the stack until we find the given arguments object on the frame.
          while (this->Walk(/*includeInlineFrame*/ true))
          {
              if (this->IsJavascriptFrame())
              {
                  Var currArgs = this->GetCurrentArgumentsObject();
                  if (currArgs == args)
                  {
                      return TRUE;
                  }
              }
          }
          return FALSE;
      }
  
      void JavascriptStackWalker::GetThis(Var* pVarThis, int moduleId) const
      {
  #if ENABLE_NATIVE_CODEGEN
          if (inlinedFramesBeingWalked)
          {
              if (inlinedFrameWalker.GetArgc() == 0)
              {
                  *pVarThis = JavascriptOperators::OP_GetThis(this->scriptContext->GetLibrary()->GetUndefined(), moduleId, scriptContext);
              }
              else
              {
                  *pVarThis = inlinedFrameWalker.GetThisObject();
                  Assert(*pVarThis);
              }
          }
          else
  #endif
          {
              const CallInfo callInfo = this->GetCallInfo();
              if (callInfo.Count == 0)
              {
                  *pVarThis = JavascriptOperators::OP_GetThis(scriptContext->GetLibrary()->GetUndefined(), moduleId, scriptContext);
              }
              else
              {
                  *pVarThis = this->GetThisFromFrame();
              }
          }
  
          if (*pVarThis == nullptr)
          {
              *pVarThis = this->scriptContext->GetLibrary()->GetNull();
          }
      }
  
      BOOL IsEval(CallInfo callInfo)
      {
          return (callInfo.Flags & CallFlags_Eval) != 0;
      }
  
      BOOL JavascriptStackWalker::IsCallerGlobalFunction() const
      {
          const CallInfo callInfo = this->GetCallInfo();
  
          JavascriptFunction* function = this->GetCurrentFunction();
          if (IsLibraryStackFrameEnabled(this->scriptContext) && !function->IsScriptFunction())
          {
              return false; // native library code can't be global function
          }
  
          FunctionInfo* funcInfo = function->GetFunctionInfo();
          if (funcInfo->HasParseableInfo())
          {
              return funcInfo->GetParseableFunctionInfo()->GetIsGlobalFunc() || IsEval(callInfo);
          }
          else
          {
              AssertMsg(FALSE, "Here we should only have script functions which were already parsed/deserialized.");
              return callInfo.Count == 0 || IsEval(callInfo);
          }
      }
  
      BOOL JavascriptStackWalker::IsEvalCaller() const
      {
          const CallInfo callInfo = this->GetCallInfo();
          return (callInfo.Flags & CallFlags_Eval) != 0;
      }
  
      Var JavascriptStackWalker::GetCurrentNativeArgumentsObject() const
      {
          Assert(this->IsJavascriptFrame() && this->interpreterFrame == nullptr);
          return this->GetCurrentArgv()[JavascriptFunctionArgIndex_ArgumentsObject];
      }
  
      void JavascriptStackWalker::SetCurrentNativeArgumentsObject(Var args)
      {
          Assert(this->IsJavascriptFrame() && this->interpreterFrame == nullptr);
          this->GetCurrentArgv()[JavascriptFunctionArgIndex_ArgumentsObject] = args;
      }
  
      Js::Var * JavascriptStackWalker::GetJavascriptArgs(bool boxArgsAndDeepCopy) const
      {
          Assert(this->IsJavascriptFrame());
  
  #if ENABLE_NATIVE_CODEGEN
          if (inlinedFramesBeingWalked)
          {
              return inlinedFrameWalker.GetArgv(/* includeThis */ false, boxArgsAndDeepCopy);
          }
          else
  #endif
              if (this->GetCurrentFunction()->GetFunctionInfo()->IsCoroutine())
          {
              JavascriptGenerator* gen = JavascriptGenerator::FromVar(this->GetCurrentArgv()[JavascriptFunctionArgIndex_This]);
              return gen->GetArguments().Values;
          }
          else
          {
              return &this->GetCurrentArgv()[JavascriptFunctionArgIndex_SecondScriptArg];
          }
      }
  
      uint32 JavascriptStackWalker::GetByteCodeOffset() const
      {
          uint32 offset = 0;
          if (this->IsJavascriptFrame())
          {
              if (this->interpreterFrame)
              {
                  if (this->TryGetByteCodeOffsetFromInterpreterFrame(offset))
                  {
                      return offset;
                  }
              }
  
  #if ENABLE_NATIVE_CODEGEN
              if (TryGetByteCodeOffsetFromNativeFrame(offset))
              {
                  return offset;
              }
  #endif
          }
          return offset;
      }
  
      bool JavascriptStackWalker::TryGetByteCodeOffsetFromInterpreterFrame(uint32& offset) const
      {
  #if ENABLE_NATIVE_CODEGEN
          if (this->lastInternalFrameInfo.codeAddress != nullptr)
          {
              return false;
          }
  #endif
          offset = this->interpreterFrame->GetReader()->GetCurrentOffset();
          if (offset == 0)
          {
              // This will be the case when we are broken on the debugger on very first statement (due to async break).
              // Or the interpreter loop can throw OOS on entrance before executing bytecode.
          }
          else
          {
              // Note : For many cases, we move the m_currentLocation of ByteCodeReader already to next available opcode.
              // This could create problem in binding the exception to proper line offset.
              // Reducing by 1 will make sure the current offset falls under, current executing opcode.
              offset--;
          }
          return true;
      }
  
  #if ENABLE_NATIVE_CODEGEN
      bool JavascriptStackWalker::TryGetByteCodeOffsetFromNativeFrame(uint32& offset) const
      {
          DWORD_PTR pCodeAddr;
          if (this->lastInternalFrameInfo.codeAddress != nullptr)
          {
              pCodeAddr = (DWORD_PTR)this->lastInternalFrameInfo.codeAddress;
          }
          else
          {
              pCodeAddr = (DWORD_PTR)this->GetCurrentCodeAddr();
          }
  
          // 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.
          // The quick fix would be to look the address which is at least lesser than current return address.
  
          // Assert to verify at what places this can happen.
          Assert(pCodeAddr);
  
          if (pCodeAddr)
          {
  #if defined(_M_ARM)
              // Note that DWORD_PTR is not actually a pointer type (!) but is simple unsigned long/__int64 (see BaseTsd.h).
              // Thus, decrement would be by 1 byte and not 4 bytes as in pointer arithmetic. That's exactly what we need.
              // 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.
              AssertMsg(pCodeAddr % 2 == 1, "Got even number for pCodeAddr! It's expected to be return address, which should be odd.");
              pCodeAddr--;
  #endif
              pCodeAddr--;
          }
  
          bool usedInternalFrameInfo = false;
          uint loopNum = GetLoopNumber(usedInternalFrameInfo);
  
          JavascriptFunction *function = nullptr;
          FunctionBody *inlinee = nullptr;
  
          function = usedInternalFrameInfo ? this->GetCachedInternalFrameInfo().function : this->GetCurrentFunctionFromPhysicalFrame();
  
          // If there are inlined frames on the stack, we have to be able to return the byte code offsets of those inlined calls
          // from their respective callers. But, we can use the current native address as IP for only the topmost inlined frame.
          // TryGetByteCodeOffsetOfInlinee takes care of these conditions and sets up the offset of an inlinee in 'offset', if the
          // current inlinee frame is not the topmost of the inlinee frames.
          if (HasInlinedFramesOnStack() && TryGetByteCodeOffsetOfInlinee(function, loopNum, pCodeAddr, &inlinee, offset, usedInternalFrameInfo))
          {
              return true;
          }
  
          StatementData data;
          if (function->GetFunctionBody() && function->GetFunctionBody()->GetMatchingStatementMapFromNativeAddress(pCodeAddr, data, loopNum, inlinee))
          {
              offset = data.bytecodeBegin;
              return true;
          }
  
          return false;
      }
  
      uint JavascriptStackWalker::GetLoopNumber(bool& usedInternalFrameInfo) const
      {
          uint loopNum = LoopHeader::NoLoop;
          if (this->lastInternalFrameInfo.codeAddress != nullptr)
          {
              if (this->lastInternalFrameInfo.frameType == InternalFrameType_LoopBody)
              {
                  AnalysisAssert(this->interpreterFrame);
                  loopNum = this->interpreterFrame->GetCurrentLoopNum();
                  Assert(loopNum != LoopHeader::NoLoop);
                  usedInternalFrameInfo = true;
              }
          }
          else
          {
              if (this->IsCurrentPhysicalFrameForLoopBody())
              {
                  // Internal frame but codeAddress on lastInternalFrameInfo not set. We must be in an inlined frame in the loop body.
                  Assert(this->tempInterpreterFrame);
                  loopNum = this->tempInterpreterFrame->GetCurrentLoopNum();
                  Assert(loopNum != LoopHeader::NoLoop);
                  usedInternalFrameInfo = false;
              }
          }
  
          return loopNum;
      }
  
      bool JavascriptStackWalker::TryGetByteCodeOffsetOfInlinee(Js::JavascriptFunction* parentFunction, uint loopNum, DWORD_PTR pCodeAddr, Js::FunctionBody** inlinee, uint32& offset, bool useInternalFrameInfo) const
      {
          // For inlined frames, translation from native offset -> source code happens in two steps.
          // The native offset is first translated into a statement index using the physical frame's
          // source context info. This statement index is then looked up in the *inlinee*'s source
          // context info to get the bytecode offset.
          //
          // For all inlined frames contained within a physical frame we have only one offset == (IP - entry).
          // Since we can't use that to get the other inlined callers' IPs, we save the IP of all inlined
          // callers in their "callinfo" (See InlineeCallInfo). The top most inlined frame uses the IP
          // of the physical frame. All other inlined frames use the InlineeStartOffset stored in their call info
          // to calculate the byte code offset of the callsite of the inlinee they called.
  
          StatementData data;
          uint32 inlineeOffset = 0;
          *inlinee = InlinedFramesBeingWalked() ? inlinedFrameWalker.GetFunctionObject()->GetFunctionBody() : nullptr;
  
          InlinedFrameWalker  tmpFrameWalker;
          if (InlinedFramesBeingWalked())
          {
              // Inlined frames are being walked right now. The top most frame is where the IP is.
              if (!inlinedFrameWalker.IsTopMostFrame())
              {
                  inlineeOffset = inlinedFrameWalker.GetCurrentInlineeOffset();
              }
          }
          else if (ScriptFunction::Test(parentFunction) && HasInlinedFramesOnStack())
          {
              // Inlined frames are not being walked right now. However, if there
              // are inlined frames on the stack the InlineeCallInfo of the first inlined frame
              // has the native offset of the current physical frame.
              Assert(!*inlinee);
              InlinedFrameWalker::FromPhysicalFrame(tmpFrameWalker, currentFrame, ScriptFunction::FromVar(parentFunction), PreviousInterpreterFrameIsFromBailout(), loopNum, this, useInternalFrameInfo, false /*noAlloc*/);
              inlineeOffset = tmpFrameWalker.GetBottomMostInlineeOffset();
              tmpFrameWalker.Close();
          }
  
          if (inlineeOffset != 0 &&
              parentFunction->GetFunctionBody()->GetMatchingStatementMapFromNativeOffset(pCodeAddr, inlineeOffset, data, loopNum, *inlinee))
          {
              offset = data.bytecodeBegin;
              return true;
          }
  
          return false;
      }
  
      bool JavascriptStackWalker::PreviousInterpreterFrameIsFromBailout() const
      {
          if (lastInternalFrameInfo.codeAddress)
          {
              return lastInternalFrameInfo.previousInterpreterFrameIsFromBailout;
          }
  
          return this->previousInterpreterFrameIsFromBailout;
      }
  
      bool JavascriptStackWalker::InlinedFramesBeingWalked() const
      {
          if (lastInternalFrameInfo.codeAddress)
          {
              return false;
          }
  
          return this->inlinedFramesBeingWalked;
      }
  
      bool JavascriptStackWalker::HasInlinedFramesOnStack() const
      {
          if (lastInternalFrameInfo.codeAddress)
          {
              return lastInternalFrameInfo.hasInlinedFramesOnStack;
          }
  
          return this->hasInlinedFramesOnStack;
      }
  #endif
  
      bool JavascriptStackWalker::GetSourcePosition(const WCHAR** sourceFileName, ULONG* line, LONG* column)
      {
          uint byteCodeoffset = this->GetByteCodeOffset();
          if(byteCodeoffset)
          {
              Js::FunctionBody* functionBody = this->GetCurrentFunction()->GetFunctionBody();
              if (functionBody->GetLineCharOffset(byteCodeoffset, line, column))
              {
                  if(functionBody->GetUtf8SourceInfo()->IsDynamic())
                  {
                      *sourceFileName = _u("Dynamic Code");
                  }
                  else
                  {
                      *sourceFileName = functionBody->GetUtf8SourceInfo()->GetSrcInfo()->sourceContextInfo->url;
                  }
                  return true;
              }
          }
          return false;
      }
  
      Js::JavascriptFunction * JavascriptStackWalker::UpdateFrame(bool includeInlineFrames)
      {
          this->isJavascriptFrame = this->CheckJavascriptFrame(includeInlineFrames);
  
          if (this->IsJavascriptFrame())
          {
              // In case we have a cross site thunk, update the script context
              Js::JavascriptFunction *function = this->GetCurrentFunction();
  
  #if ENABLE_NATIVE_CODEGEN
              bool isCurrentPhysicalFrameForLoopBody = this->IsCurrentPhysicalFrameForLoopBody();
  #endif
              if (this->interpreterFrame)
              {
  #if ENABLE_NATIVE_CODEGEN
                  if (lastInternalFrameInfo.codeAddress != nullptr)
                  {
                      this->previousInterpreterFrameIsForLoopBody = true;
                  }
  #endif
  
                  // We might've bailed out of an inlinee, so check if there were any inlinees.
                  if (this->interpreterFrame->TestFlags(InterpreterStackFrameFlags_FromBailOut))
                  {
                      previousInterpreterFrameIsFromBailout = true;
  
  #if ENABLE_NATIVE_CODEGEN
                      Assert(!inlinedFramesBeingWalked);
                      if (includeInlineFrames)
                      {
                          int loopNum = -1;
                          if (isCurrentPhysicalFrameForLoopBody)
                          {
                              loopNum = this->tempInterpreterFrame->GetCurrentLoopNum();
                          }
  
                          bool hasInlinedFramesOnStack = InlinedFrameWalker::FromPhysicalFrame(inlinedFrameWalker, currentFrame,
                              ScriptFunction::FromVar(function), true /*fromBailout*/, loopNum, this, false /*useInternalFrameInfo*/, false /*noAlloc*/);
  
                          if (hasInlinedFramesOnStack)
                          {
                              // We're now back in the state where currentFrame == physical frame of the inliner, but
                              // since interpreterFrame != null, we'll pick values from the interpreterFrame (the bailout
                              // frame of the inliner). Set a flag to tell the stack walker that it needs to start from the
                              // inlinee frames on the stack when Walk() is called.
                              this->inlinedFramesBeingWalked = inlinedFrameWalker.Next(inlinedFrameCallInfo);
                              this->hasInlinedFramesOnStack = hasInlinedFramesOnStack;
                              Assert(inlinedFramesBeingWalked);
                              Assert(StackScriptFunction::GetCurrentFunctionObject(this->interpreterFrame->GetJavascriptFunction()) == inlinedFrameWalker.GetFunctionObject());
                          }
                          else
                          {
                              Assert(!isCurrentPhysicalFrameForLoopBody);
                          }
                      }
                      else if (isCurrentPhysicalFrameForLoopBody)
                      {
                          // Getting here is only possible when the current interpreterFrame is for a function which
                          // encountered a bailout after getting inlined in a jitted loop body. If we are not including
                          // inlined frames in the stack walk, we need to set the codeAddress on lastInternalFrameInfo,
                          // which would have otherwise been set upon closing the inlinedFrameWalker, now.
                          // Note that we already have an assert in CheckJavascriptFrame to ensure this.
                          SetCachedInternalFrameInfo(InternalFrameType_LoopBody, function, false /*hasInlinedFramesOnStack*/, true /*previousInterpreterFrameIsFromBailout*/);
                      }
  #else
                      // How did we bail out when JIT was disabled?
                      Assert(false);
  #endif
                  }
                  else
                  {
                      Assert(StackScriptFunction::GetCurrentFunctionObject(this->interpreterFrame->GetJavascriptFunction()) == function);
                      previousInterpreterFrameIsFromBailout = false;
                  }
              }
              else if (!this->isNativeLibraryFrame)
              {
  #if ENABLE_NATIVE_CODEGEN
                  Assert(!HasInlinedFramesOnStack() || (includeInlineFrames && isCurrentPhysicalFrameForLoopBody));
  
                  if (!HasInlinedFramesOnStack() && includeInlineFrames)
                  {
                      // Check whether there are inlined frames nested in this native frame. The corresponding check for
                      // a jitted loop body frame should have been done in CheckJavascriptFrame
                      Assert(lastInternalFrameInfo.codeAddress == nullptr);
                      bool inlinedFramesFound = InlinedFrameWalker::FromPhysicalFrame(
                          inlinedFrameWalker,
                          currentFrame,
                          ScriptFunction::FromVar(function),
                          false,  // fromBailout
                          -1,     // loopNum
                          nullptr,// walker
                          false,  // useInternalFrameInfo
                          false   // noAlloc
                      );
                      if (inlinedFramesFound)
                      {
                          this->inlinedFramesBeingWalked = inlinedFrameWalker.Next(inlinedFrameCallInfo);
                          this->hasInlinedFramesOnStack = true;
                          Assert(inlinedFramesBeingWalked);
                      }
                  }
  #endif
              }
              this->scriptContext = function->GetScriptContext();
              return function;
          }
          return nullptr;
      }
  #if ENABLE_NATIVE_CODEGEN
      void JavascriptStackWalker::WalkAndClearInlineeFrameCallInfoOnException(void *tryHandlerAddrOfReturnAddr)
      {
          // Walk the stack and when we find the first native frame, we clear the inlinee's callinfo for this frame
          // It is sufficient we stop at the first native frame which had the enclosing try-catch
          // TODO : Revisit when we start inlining functions with try-catch/try-finally
          while (this->Walk(true))
          {
              if (JavascriptFunction::IsNativeAddress(this->scriptContext, this->currentFrame.GetInstructionPointer()))
              {
                  if (HasInlinedFramesOnStack())
                  {
                      for (int index = inlinedFrameWalker.GetFrameCount() - 1; index >= 0; index--)
                      {
                          auto inlinedFrame = inlinedFrameWalker.GetFrameAtIndex(index);
                          inlinedFrame->callInfo.Clear();
                      }
                  }
              }
              if (this->currentFrame.GetAddressOfReturnAddress() == tryHandlerAddrOfReturnAddr)
              {
                  break;
              }
          }
      }
  #endif
      // Note: noinline is to make sure that when we unwind to the unwindToAddress, there is at least one frame to unwind.
      _NOINLINE
      JavascriptStackWalker::JavascriptStackWalker(ScriptContext * scriptContext, bool useEERContext, PVOID returnAddress, bool _forceFullWalk /*=false*/) :
          inlinedFrameCallInfo(CallFlags_None, 0), shouldDetectPartiallyInitializedInterpreterFrame(true), forceFullWalk(_forceFullWalk),
          previousInterpreterFrameIsFromBailout(false), previousInterpreterFrameIsForLoopBody(false), hasInlinedFramesOnStack(false)
      {
          if (scriptContext == NULL)
          {
              Throw::InternalError();
          }
          this->scriptContext = scriptContext;
  
          // Pull the current script state from the thread context.
  
          ThreadContext * threadContext = scriptContext->GetThreadContext();
          this->entryExitRecord = threadContext->GetScriptEntryExit();
  
          this->nativeLibraryEntry = threadContext->PeekNativeLibraryEntry();
          this->prevNativeLibraryEntry = nullptr;
  
          this->interpreterFrame = NULL;
          this->isJavascriptFrame = false;
          this->isNativeLibraryFrame = false;
  
          if (entryExitRecord->frameIdOfScriptExitFunction != NULL)
          {
              // We're currently outside the script, so grab the frame from which we left.
              this->scriptContext = entryExitRecord->scriptContext;
              this->isInitialFrame = this->currentFrame.InitializeByFrameId(entryExitRecord->frameIdOfScriptExitFunction, this->scriptContext);
          }
          else
          {
              // Just start with the caller
              this->isInitialFrame = this->currentFrame.InitializeByReturnAddress(_ReturnAddress(), this->scriptContext);
          }
  
          if (useEERContext)
          {
              this->tempInterpreterFrame = this->scriptContext->GetThreadContext()->GetLeafInterpreterFrame();
          }
          else
          {
              // We need to generate stack for the passed script context, so use the leaf interpreter frame for passed script context
              this->tempInterpreterFrame = scriptContext->GetThreadContext()->GetLeafInterpreterFrame();
          }
  
          inlinedFramesBeingWalked = false;
      }
  
      BOOL JavascriptStackWalker::Walk(bool includeInlineFrames)
      {
          // Walk one frame up the call stack.
          this->interpreterFrame = NULL;
  
  #if ENABLE_NATIVE_CODEGEN
          if (lastInternalFrameInfo.codeAddress != nullptr && this->previousInterpreterFrameIsForLoopBody)
          {
              this->previousInterpreterFrameIsForLoopBody = false;
              ClearCachedInternalFrameInfo();
          }
  
          if (inlinedFramesBeingWalked)
          {
              Assert(includeInlineFrames);
              inlinedFramesBeingWalked = inlinedFrameWalker.Next(inlinedFrameCallInfo);
              if (!inlinedFramesBeingWalked)
              {
                  inlinedFrameWalker.Close();
                  if ((this->IsCurrentPhysicalFrameForLoopBody()))
                  {
                      // Done walking inlined frames in a loop body, cache the native code address now
                      // in order to skip the loop body frame.
                      this->SetCachedInternalFrameInfo(InternalFrameType_LoopBody, this->GetCurrentFunctionFromPhysicalFrame(), true /*hasInlinedFramesOnStack*/, previousInterpreterFrameIsFromBailout);
                      isJavascriptFrame = false;
                  }
              }
  
              return true;
          }
  #endif
          this->hasInlinedFramesOnStack = false;
          if (this->isInitialFrame)
          {
              this->isInitialFrame = false; // Only walk initial frame once
          }
          else if (!this->currentFrame.Next())
          {
              this->isJavascriptFrame = false;
              return false;
          }
  
          // If we're at the entry from a host frame, hop to the frame from which we left the script.
          if (AlignAndCheckAddressOfReturnAddressMatch(this->currentFrame.GetAddressOfInstructionPointer(), this->entryExitRecord->addrOfReturnAddrOfScriptEntryFunction))
          {
              BOOL hasCaller = this->entryExitRecord->hasCaller || this->forceFullWalk;
  
  #ifdef CHECK_STACKWALK_EXCEPTION
              BOOL ignoreStackWalkException = this->entryExitRecord->ignoreStackWalkException;
  #endif
  
              this->entryExitRecord = this->entryExitRecord->next;
              if (this->entryExitRecord == NULL)
              {
                  this->isJavascriptFrame = false;
                  return false;
              }
  
              if (!hasCaller && !this->scriptContext->IsDiagnosticsScriptContext())
              {
  #ifdef CHECK_STACKWALK_EXCEPTION
                  if (!ignoreStackWalkException)
                  {
                      AssertMsg(false, "walk pass no caller frame");
                  }
  #endif
                  this->isJavascriptFrame = false;
                  return false;
              }
  
              this->scriptContext = this->entryExitRecord->scriptContext;
              this->currentFrame.SkipToFrame(this->entryExitRecord->frameIdOfScriptExitFunction);
          }
  
          this->UpdateFrame(includeInlineFrames);
          return true;
      }
  
      BOOL JavascriptStackWalker::GetCallerWithoutInlinedFrames(_Out_opt_ JavascriptFunction ** ppFunc)
      {
          return GetCaller(ppFunc, /*includeInlineFrames*/ false);
      }
  
      BOOL JavascriptStackWalker::GetCaller(_Out_opt_ JavascriptFunction ** ppFunc, bool includeInlineFrames)
      {
          while (this->Walk(includeInlineFrames))
          {
              if (this->IsJavascriptFrame())
              {
                  Assert(entryExitRecord != NULL);
                  if (ppFunc)
                  {
                  *ppFunc = this->GetCurrentFunction();
                  }
                  AssertMsg(!this->shouldDetectPartiallyInitializedInterpreterFrame, "must have skipped first frame if needed");
                  return true;
              }
          }
          if (ppFunc)
          {
              *ppFunc = nullptr;
          }
          return false;
      }
  
      BOOL JavascriptStackWalker::GetNonLibraryCodeCaller(_Out_opt_ JavascriptFunction ** ppFunc)
      {
          while (this->GetCaller(ppFunc))
          {
              Assert(ppFunc != nullptr);
              __analysis_assume(ppFunc != nullptr);
              if (!(*ppFunc)->IsLibraryCode())
              {
                  return true;
              }
          }
          return false;
      }
  
      /*static*/
      bool JavascriptStackWalker::IsLibraryStackFrameEnabled(Js::ScriptContext * scriptContext)
      {
          Assert(scriptContext != nullptr);
          return CONFIG_FLAG(LibraryStackFrame);
      }
  
      // Check if a function is a display caller: user code, or native library / boundary script library code
      bool JavascriptStackWalker::IsDisplayCaller(JavascriptFunction* func)
      {
          FunctionBody* body = func->GetFunctionBody();
          if (IsLibraryStackFrameEnabled(func->GetScriptContext()))
          {
              return !func->IsScriptFunction() || !body->GetUtf8SourceInfo()->GetIsLibraryCode() || body->IsPublicLibraryCode();
          }
          else
          {
              return !body->GetUtf8SourceInfo()->GetIsLibraryCode();
          }
      }
  
      bool JavascriptStackWalker::GetDisplayCaller(_Out_opt_ JavascriptFunction ** ppFunc)
      {
          while (this->GetCaller(ppFunc))
          {
              Assert(ppFunc != nullptr);
              __analysis_assume(ppFunc != nullptr);
              if (IsDisplayCaller(*ppFunc))
              {
                  return true;
              }
          }
          return false;
      }
  
      PCWSTR JavascriptStackWalker::GetCurrentNativeLibraryEntryName() const
      {
          Assert(IsLibraryStackFrameEnabled(this->scriptContext)
              && this->prevNativeLibraryEntry
              && this->prevNativeLibraryEntry->next == this->nativeLibraryEntry);
          return this->prevNativeLibraryEntry->name;
      }
  
      // WalkToTarget skips internal frames
      BOOL JavascriptStackWalker::WalkToTarget(JavascriptFunction * funcTarget)
      {
          // Walk up the call stack until we find the frame that belongs to the given function.
  
          while (this->Walk(/*includeInlineFrames*/ true))
          {
              if (this->IsJavascriptFrame() && this->GetCurrentFunction() == funcTarget)
              {
                  // Skip internal names
                  Assert( !(this->GetCallInfo().Flags & CallFlags_InternalFrame) );
                  return true;
              }
          }
  
          return false;
      }
  
      bool JavascriptStackWalker::AlignAndCheckAddressOfReturnAddressMatch(void* addressOfReturnAddress, void* nativeLibraryEntryAddress)
      {
          return addressOfReturnAddress == nativeLibraryEntryAddress
  #if defined(_M_IX86)
              // Under some odd cases on x86, addressOfReturnAddress and stashed entry address need to be aligned.
              // This happens when code is generated using two stack pointers. One or both have the address of 
              // return address offset by 4, 8, or 12.
              || (((uint)nativeLibraryEntryAddress - (uint)addressOfReturnAddress < 0x10) &&
                  *(void**)addressOfReturnAddress == *(void**)nativeLibraryEntryAddress
                  )
  #endif
              ;
      }
  
      void ** JavascriptStackWalker::GetCurrentArgv() const
      {
          Assert(this->IsJavascriptFrame());
          Assert(this->interpreterFrame != nullptr ||
                 (this->prevNativeLibraryEntry && AlignAndCheckAddressOfReturnAddressMatch(this->currentFrame.GetAddressOfReturnAddress(), this->prevNativeLibraryEntry->addr)) ||
                 JavascriptFunction::IsNativeAddress(this->scriptContext, (void*)this->currentFrame.GetInstructionPointer()));
  
          bool isNativeAddr = (this->interpreterFrame == nullptr) &&
                              (!this->prevNativeLibraryEntry || !AlignAndCheckAddressOfReturnAddressMatch(this->currentFrame.GetAddressOfReturnAddress(), this->prevNativeLibraryEntry->addr));
          void ** argv = currentFrame.GetArgv(isNativeAddr, false /*shouldCheckForNativeAddr*/);
          Assert(argv);
          return argv;
      }
  
      bool JavascriptStackWalker::CheckJavascriptFrame(bool includeInlineFrames)
      {
          this->isNativeLibraryFrame = false; // Clear previous result
  
          void * codeAddr = this->currentFrame.GetInstructionPointer();
          if (this->tempInterpreterFrame && codeAddr == this->tempInterpreterFrame->GetReturnAddress())
          {
              bool isBailoutInterpreter = this->tempInterpreterFrame->TestFlags(Js::InterpreterStackFrameFlags_FromBailOut);
  
              // We need to skip over the first interpreter frame on the stack if it is the partially initialized frame
              // otherwise it is a real frame and we should continue.
              // For fully initialized frames (PushPopHelper was called) the thunk stack addr is equal or below addressOfReturnAddress
              // as the latter one is obtained in InterpreterStackFrame::InterpreterThunk called by the thunk.
              bool isPartiallyInitializedFrame = this->shouldDetectPartiallyInitializedInterpreterFrame &&
                  this->currentFrame.GetAddressOfReturnAddress(isBailoutInterpreter /*isCurrentContextNative*/, false /*shouldCheckForNativeAddr*/) < this->tempInterpreterFrame->GetAddressOfReturnAddress();
              this->shouldDetectPartiallyInitializedInterpreterFrame = false;
  
              if (isPartiallyInitializedFrame)
              {
                  return false; // Skip it.
              }
  
              void ** argv = this->currentFrame.GetArgv(isBailoutInterpreter /*isCurrentContextNative*/, false /*shouldCheckForNativeAddr*/);
              if (argv == nullptr)
              {
                  // NOTE: When we switch to walking the stack ourselves and skip non engine frames, this should never happen.
                  return false;
              }
  
              this->interpreterFrame = this->tempInterpreterFrame;
  
              this->tempInterpreterFrame = this->interpreterFrame->GetPreviousFrame();
  
  #if ENABLE_NATIVE_CODEGEN
  #if DBG
              if (((CallInfo const *)&argv[JavascriptFunctionArgIndex_CallInfo])->Flags & CallFlags_InternalFrame)
              {
                  // The return address of the interpreterFrame is the same as the entryPoint for a jitted loop body.
                  // This can only ever happen when we have bailed out from a function inlined in the loop body. We
                  // wouldn't have created a new interpreterFrame if the bailout were from the loop body itself.
                  Assert(this->interpreterFrame->TestFlags(Js::InterpreterStackFrameFlags_FromBailOut));
                  InlinedFrameWalker tmpFrameWalker;
                  Assert(InlinedFrameWalker::FromPhysicalFrame(tmpFrameWalker, currentFrame, Js::ScriptFunction::FromVar(argv[JavascriptFunctionArgIndex_Function]),
                      true /*fromBailout*/, this->tempInterpreterFrame->GetCurrentLoopNum(), this, false /*useInternalFrameInfo*/, true /*noAlloc*/));
                  tmpFrameWalker.Close();
              }
  #endif //DBG
  #endif //ENABLE_NATIVE_CODEGEN
  
              return true;
          }
  
          if (IsLibraryStackFrameEnabled(this->scriptContext) && this->nativeLibraryEntry)
          {
              void* addressOfReturnAddress = this->currentFrame.GetAddressOfReturnAddress();
              void* nativeLibraryEntryAddress = this->nativeLibraryEntry->addr;
              AssertMsg(addressOfReturnAddress <= nativeLibraryEntryAddress, "Missed matching native library entry?");
              if (AlignAndCheckAddressOfReturnAddressMatch(addressOfReturnAddress, nativeLibraryEntryAddress))
              {
                  this->isNativeLibraryFrame = true;
                  this->shouldDetectPartiallyInitializedInterpreterFrame = false;
                  this->prevNativeLibraryEntry = this->nativeLibraryEntry; // Saves match in prevNativeLibraryEntry
                  this->nativeLibraryEntry = this->nativeLibraryEntry->next;
                  return true;
              }
          }
  
  #if ENABLE_NATIVE_CODEGEN
          BOOL isNativeAddr = JavascriptFunction::IsNativeAddress(this->scriptContext, codeAddr);
          if (isNativeAddr)
          {
              this->shouldDetectPartiallyInitializedInterpreterFrame = false;
              void ** argv = this->currentFrame.GetArgv(true /*isCurrentContextNative*/, false /*shouldCheckForNativeAddr*/);
              if (argv == nullptr)
              {
                  // NOTE: When we switch to walking the stack ourselves and skip non engine frames, this should never happen.
                  return false;
              }
  
              ScriptFunction* funcObj = Js::ScriptFunction::FromVar(argv[JavascriptFunctionArgIndex_Function]);
              if (funcObj->GetFunctionBody()->GetIsAsmjsMode())
              {
                  return false;
              }
  
              // Note: this check has to happen after asm.js check, because call info is not valid for asm.js
              if (((CallInfo const *)&argv[JavascriptFunctionArgIndex_CallInfo])->Flags & CallFlags_InternalFrame)
              {
                  if (includeInlineFrames &&
                      InlinedFrameWalker::FromPhysicalFrame(inlinedFrameWalker, currentFrame, Js::ScriptFunction::FromVar(argv[JavascriptFunctionArgIndex_Function]),
                          false /*fromBailout*/, this->tempInterpreterFrame->GetCurrentLoopNum(), this, false /*useInternalFrameInfo*/, false /*noAlloc*/))
                  {
                      // 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.
                      // DeepCopy here because, if there is an inlinee in a loop body, FromPhysicalFrame won't be called from UpdateFrame
                      this->inlinedFramesBeingWalked = inlinedFrameWalker.Next(inlinedFrameCallInfo);
                      this->hasInlinedFramesOnStack = true;
                      Assert(inlinedFramesBeingWalked);
                      return true;
                  }
  
                  SetCachedInternalFrameInfo(InternalFrameType_LoopBody, funcObj, false /*hasInlinedFramesOnStack*/, previousInterpreterFrameIsFromBailout);
                  return false;
              }
  
              return true;
          }
  #endif
          return false;
      }
  
      void * JavascriptStackWalker::GetCurrentCodeAddr() const
      {
          return this->currentFrame.GetInstructionPointer();
      }
  
      JavascriptFunction * JavascriptStackWalker::GetCurrentFunction(bool includeInlinedFrames /* = true */) const
      {
          Assert(this->IsJavascriptFrame());
  
  #if ENABLE_NATIVE_CODEGEN
          if (includeInlinedFrames && inlinedFramesBeingWalked)
          {
              return inlinedFrameWalker.GetFunctionObject();
          }
          else
  #endif
              if (this->isNativeLibraryFrame)
          {
              // Return saved function. Do not read from stack as compiler may stackpack/optimize args.
              return JavascriptFunction::FromVar(this->prevNativeLibraryEntry->function);
          }
          else
          {
              return StackScriptFunction::GetCurrentFunctionObject((JavascriptFunction *)this->GetCurrentArgv()[JavascriptFunctionArgIndex_Function]);
          }
      }
  
      void JavascriptStackWalker::SetCurrentFunction(JavascriptFunction * function)
      {
          Assert(this->IsJavascriptFrame());
  #if ENABLE_NATIVE_CODEGEN
          if (inlinedFramesBeingWalked)
          {
              inlinedFrameWalker.SetFunctionObject(function);
          }
          else
  #endif
          {
              this->GetCurrentArgv()[JavascriptFunctionArgIndex_Function] = function;
          }
      }
  
      JavascriptFunction *JavascriptStackWalker::GetCurrentFunctionFromPhysicalFrame() const
      {
          return GetCurrentFunction(false);
      }
  
      CallInfo JavascriptStackWalker::GetCallInfo(bool includeInlinedFrames /* = true */) const
      {
          Assert(this->IsJavascriptFrame());
          CallInfo callInfo;
          if (includeInlinedFrames && inlinedFramesBeingWalked)
          {
              // Since we don't support inlining constructors yet, its questionable if we should handle the
              // hidden frame display here?
              callInfo = inlinedFrameCallInfo;
          }
          else if (this->GetCurrentFunction()->GetFunctionInfo()->IsCoroutine())
          {
              JavascriptGenerator* gen = JavascriptGenerator::FromVar(this->GetCurrentArgv()[JavascriptFunctionArgIndex_This]);
              callInfo = gen->GetArguments().Info;
          }
          else if (this->isNativeLibraryFrame)
          {
              // Return saved callInfo. Do not read from stack as compiler may stackpack/optimize args.
              callInfo = this->prevNativeLibraryEntry->callInfo;
          }
          else
          {
              callInfo = *(CallInfo const *)&this->GetCurrentArgv()[JavascriptFunctionArgIndex_CallInfo];
          }
  
          if (callInfo.Flags & Js::CallFlags_ExtraArg)
          {
              callInfo.Flags = (CallFlags)(callInfo.Flags & ~Js::CallFlags_ExtraArg);
          }
  
          return callInfo;
      }
  
      CallInfo JavascriptStackWalker::GetCallInfoFromPhysicalFrame() const
      {
          return GetCallInfo(false);
      }
  
      Var JavascriptStackWalker::GetThisFromFrame() const
      {
          Assert(!inlinedFramesBeingWalked);
          Assert(this->IsJavascriptFrame());
  
          if (this->GetCurrentFunction()->GetFunctionInfo()->IsCoroutine())
          {
              JavascriptGenerator* gen = JavascriptGenerator::FromVar(this->GetCurrentArgv()[JavascriptFunctionArgIndex_This]);
              return gen->GetArguments()[0];
          }
  
          return this->GetCurrentArgv()[JavascriptFunctionArgIndex_This];
      }
  
  #if ENABLE_NATIVE_CODEGEN
      void JavascriptStackWalker::ClearCachedInternalFrameInfo()
      {
          this->lastInternalFrameInfo.Clear();
      }
  
      void JavascriptStackWalker::SetCachedInternalFrameInfo(InternalFrameType frameType, JavascriptFunction* function, bool hasInlinedFramesOnStack, bool previousInterpreterFrameIsFromBailout)
      {
          if (!this->lastInternalFrameInfo.codeAddress)
          {
              this->lastInternalFrameInfo.Set(
                  this->GetCurrentCodeAddr(),
                  this->currentFrame.GetFrame(),
                  this->currentFrame.GetStackCheckCodeHeight(),
                  frameType,
                  function,
                  hasInlinedFramesOnStack,
                  previousInterpreterFrameIsFromBailout);
          }
      }
  #endif
  
      bool JavascriptStackWalker::IsCurrentPhysicalFrameForLoopBody() const
      {
          return !!(this->GetCallInfoFromPhysicalFrame().Flags & CallFlags_InternalFrame);
      }
  
      bool JavascriptStackWalker::IsWalkable(ScriptContext *scriptContext)
      {
          if (scriptContext == NULL)
          {
              return false;
          }
  
          ThreadContext *threadContext = scriptContext->GetThreadContext();
          if (threadContext == NULL)
          {
              return false;
          }
  
          return (threadContext->GetScriptEntryExit() != NULL);
      }
  
      BOOL JavascriptStackWalker::GetCaller(_Out_opt_ JavascriptFunction** ppFunc, ScriptContext* scriptContext)
      {
          if (!IsWalkable(scriptContext))
          {
              if (ppFunc)
              {
              *ppFunc = nullptr;
              }
              return FALSE;
          }
  
          JavascriptStackWalker walker(scriptContext);
          return walker.GetCaller(ppFunc);
      }
  
      BOOL JavascriptStackWalker::GetCaller(_Out_opt_ JavascriptFunction** ppFunc, uint32* byteCodeOffset, ScriptContext* scriptContext)
      {
          JavascriptStackWalker walker(scriptContext);
          if (walker.GetCaller(ppFunc))
          {
              *byteCodeOffset = walker.GetByteCodeOffset();
              return TRUE;
          }
          return FALSE;
      }
  
      void JavascriptStackWalker::GetThis(Var* pThis, int moduleId, ScriptContext* scriptContext)
      {
          JavascriptStackWalker walker(scriptContext);
          JavascriptFunction* caller;
          if (walker.GetCaller(&caller))
          {
              walker.GetThis(pThis, moduleId);
          }
      }
  
      void JavascriptStackWalker::GetThis(Var* pThis, int moduleId, JavascriptFunction* func, ScriptContext* scriptContext)
      {
          JavascriptStackWalker walker(scriptContext);
          JavascriptFunction* caller;
          while (walker.GetCaller(&caller))
          {
              if (caller == func)
              {
                  walker.GetThis(pThis, moduleId);
                  return;
              }
          }
      }
  
      // Try to see whether there is a top-most javascript frame, and if there is return true if it's native.
      // Returns true if top most frame is javascript frame, in this case the isNative parameter receives true
      // when top-most frame is native, false otherwise.
      // Returns false if top most frame is not a JavaScript frame.
  
      /* static */
      bool JavascriptStackWalker::TryIsTopJavaScriptFrameNative(ScriptContext* scriptContext, bool* isNative, bool ignoreLibraryCode /* = false */)
      {
          Assert(scriptContext);
          Assert(isNative);
  
          Js::JavascriptFunction* caller;
          Js::JavascriptStackWalker walker(scriptContext);
  
          BOOL isSuccess;
          if (ignoreLibraryCode)
          {
              isSuccess = walker.GetNonLibraryCodeCaller(&caller);
          }
          else
          {
              isSuccess = walker.GetCaller(&caller);
          }
  
          if (isSuccess)
          {
              *isNative = (walker.GetCurrentInterpreterFrame() == NULL);
              return true;
          }
          return false;
      }
  
  #if ENABLE_NATIVE_CODEGEN
      bool InlinedFrameWalker::FromPhysicalFrame(InlinedFrameWalker& self, StackFrame& physicalFrame, Js::ScriptFunction *parent, bool fromBailout,
          int loopNum, const JavascriptStackWalker * const stackWalker, bool useInternalFrameInfo, bool noAlloc)
      {
          bool inlinedFramesFound = false;
          FunctionBody* parentFunctionBody = parent->GetFunctionBody();
          EntryPointInfo *entryPointInfo;
  
          if (loopNum != -1)
          {
              Assert(stackWalker);
          }
  
          void *nativeCodeAddress = nullptr;
          void *framePointer = nullptr;
          if (loopNum != -1 && useInternalFrameInfo)
          {
              Assert(stackWalker->GetCachedInternalFrameInfo().codeAddress != nullptr);
              InternalFrameInfo lastInternalFrameInfo = stackWalker->GetCachedInternalFrameInfo();
  
              nativeCodeAddress = lastInternalFrameInfo.codeAddress;
              framePointer = lastInternalFrameInfo.framePointer;
          }
          else
          {
              nativeCodeAddress = physicalFrame.GetInstructionPointer();
              framePointer = physicalFrame.GetFrame();
          }
  
          if (loopNum != -1)
          {
              entryPointInfo = (Js::EntryPointInfo*)parentFunctionBody->GetLoopEntryPointInfoFromNativeAddress((DWORD_PTR)nativeCodeAddress, loopNum);
          }
          else
          {
              entryPointInfo = (Js::EntryPointInfo*)parentFunctionBody->GetEntryPointFromNativeAddress((DWORD_PTR)nativeCodeAddress);
          }
  
          AssertMsg(entryPointInfo != nullptr, "Inlined frame should resolve to the right parent address");
          if (entryPointInfo->HasInlinees())
          {
              void *entry = reinterpret_cast<void*>(entryPointInfo->GetNativeAddress());
              InlinedFrameWalker::InlinedFrame *outerMostFrame = InlinedFrame::FromPhysicalFrame(physicalFrame, stackWalker, entry, entryPointInfo, useInternalFrameInfo);
  
              if (!outerMostFrame)
              {
                  return inlinedFramesFound;
              }
  
              if (!fromBailout)
              {
                  InlineeFrameRecord* record = entryPointInfo->FindInlineeFrame((void*)nativeCodeAddress);
  
                  if (record)
                  {
                      record->RestoreFrames(parent->GetFunctionBody(), outerMostFrame, JavascriptCallStackLayout::FromFramePointer(framePointer), false /* boxValues */);
                  }
              }
  
              if (outerMostFrame->callInfo.Count)
              {
                  inlinedFramesFound = true;
                  if (noAlloc)
                  {
                      return inlinedFramesFound;
                  }
                  int32 frameCount = 0;
                  InlinedFrameWalker::InlinedFrame *frameIterator = outerMostFrame;
                  while (frameIterator->callInfo.Count)
                  {
                      frameCount++;
                      frameIterator = frameIterator->Next();
                  }
  
                  InlinedFrameWalker::InlinedFrame **frames = HeapNewArray(InlinedFrameWalker::InlinedFrame*, frameCount);
  
                  frameIterator = outerMostFrame;
                  for (int index = frameCount - 1; index >= 0; index--)
                  {
                      Assert(frameIterator);
                      frames[index] = frameIterator;
                      frameIterator = frameIterator->Next();
                  }
  
                  self.Initialize(frameCount, frames, parent);
              }
  
          }
  
          return inlinedFramesFound;
      }
  
      void InlinedFrameWalker::Close()
      {
          parentFunction = nullptr;
          HeapDeleteArray(frameCount, frames);
          frames = nullptr;
          currentIndex = -1;
          frameCount = 0;
      }
  
      bool InlinedFrameWalker::Next(CallInfo& callInfo)
      {
          MoveNext();
          InlinedFrameWalker::InlinedFrame *const currentFrame = GetCurrentFrame();
          if (currentFrame)
          {
              callInfo.Flags = CallFlags_None;
              callInfo.Count = (currentFrame->callInfo.Count & 0xFFFF);
          }
  
          return currentFrame != nullptr;
      }
  
      size_t InlinedFrameWalker::GetArgc() const
      {
          InlinedFrameWalker::InlinedFrame *const currentFrame = GetCurrentFrame();
          Assert(currentFrame);
  
          return currentFrame->callInfo.Count;
      }
  
      // Note: the boxArgsAndDeepCopy parameter should be true when a copy of the JS args must be ensured to
      // be on the heap. This results in a new array of Vars with deep copied boxed values (where
      // appropriate).
      // Otherwise, this parameter should be false. For instance, if the args will only be used
      // internally to gather type info, the values are not boxed (so, some Vars may still be on
      // the stack) and the array of the current frame is returned.
      Js::Var *InlinedFrameWalker::GetArgv(bool includeThis, bool boxArgsAndDeepCopy) const
      {
          InlinedFrameWalker::InlinedFrame *const currentFrame = GetCurrentFrame();
          Assert(currentFrame);
  
          uint firstArg = includeThis ? InlinedFrameArgIndex_This : InlinedFrameArgIndex_SecondScriptArg;
          size_t argCount = this->GetArgc() - firstArg;
          Js::Var *args;
          if (!boxArgsAndDeepCopy)
          {
              args = &currentFrame->argv[firstArg];
          }
          else
          {
              args = RecyclerNewArray(parentFunction->GetScriptContext()->GetRecycler(), Js::Var, argCount);
              for (size_t i = 0; i < argCount; i++)
              {
                  args[i] = currentFrame->argv[firstArg + i];
              }
  
              this->FinalizeStackValues(args, argCount, true /*deepCopy*/);
          }
  
          return args;
      }
  
      void InlinedFrameWalker::FinalizeStackValues(__in_ecount(argCount) Js::Var args[], size_t argCount, bool deepCopy) const
      {
          ScriptContext *scriptContext = this->GetFunctionObject()->GetScriptContext();
  
          for (size_t i = 0; i < argCount; i++)
          {
              args[i] = Js::JavascriptOperators::BoxStackInstance(args[i], scriptContext, false /*allowStackFunction*/, deepCopy);
          }
      }
  
      Js::JavascriptFunction *InlinedFrameWalker::GetFunctionObject() const
      {
          InlinedFrameWalker::InlinedFrame *const currentFrame = GetCurrentFrame();
          Assert(currentFrame);
  
          return StackScriptFunction::GetCurrentFunctionObject(currentFrame->function);
      }
  
      void InlinedFrameWalker::SetFunctionObject(Js::JavascriptFunction * function)
      {
          InlinedFrameWalker::InlinedFrame *const currentFrame = GetCurrentFrame();
          Assert(currentFrame);
  
          currentFrame->function = function;
      }
  
      Js::Var InlinedFrameWalker::GetArgumentsObject() const
      {
          InlinedFrameWalker::InlinedFrame *const currentFrame = GetCurrentFrame();
          Assert(currentFrame);
  
          return currentFrame->arguments;
      }
  
      void InlinedFrameWalker::SetArgumentsObject(Js::Var arguments)
      {
          InlinedFrameWalker::InlinedFrame *currentFrame = (InlinedFrameWalker::InlinedFrame *)GetCurrentFrame();
          Assert(currentFrame);
  
          currentFrame->arguments = arguments;
      }
  
      Js::Var InlinedFrameWalker::GetThisObject() const
      {
          InlinedFrameWalker::InlinedFrame *const currentFrame = GetCurrentFrame();
          Assert(currentFrame);
  
          return currentFrame->argv[InlinedFrameArgIndex_This];
      }
  
      bool InlinedFrameWalker::IsCallerPhysicalFrame() const
      {
          return currentIndex == (frameCount - 1);
      }
  
      bool InlinedFrameWalker::IsTopMostFrame() const
      {
          return currentIndex == 0;
      }
  
      uint32 InlinedFrameWalker::GetCurrentInlineeOffset() const
      {
          Assert(!IsTopMostFrame());
          Assert(currentIndex);
  
          return GetFrameAtIndex(currentIndex - 1)->callInfo.InlineeStartOffset;
      }
  
      uint32 InlinedFrameWalker::GetBottomMostInlineeOffset() const
      {
          Assert(frameCount);
  
          return GetFrameAtIndex(frameCount - 1)->callInfo.InlineeStartOffset;
      }
  
      Js::JavascriptFunction *InlinedFrameWalker::GetBottomMostFunctionObject() const
      {
          Assert(frameCount);
  
          return GetFrameAtIndex(frameCount - 1)->function;
      }
  
      InlinedFrameWalker::InlinedFrame *const InlinedFrameWalker::GetCurrentFrame() const
      {
          return GetFrameAtIndex(currentIndex);
      }
  
      InlinedFrameWalker::InlinedFrame *const InlinedFrameWalker::GetFrameAtIndex(signed index) const
      {
          Assert(frames);
          Assert(frameCount);
  
          InlinedFrameWalker::InlinedFrame *frame = nullptr;
          if (index < frameCount)
          {
              frame = frames[index];
          }
  
          return frame;
      }
  
      void InlinedFrameWalker::MoveNext()
      {
          currentIndex++;
      }
  
      void InlinedFrameWalker::Initialize(int32 frameCount, __in_ecount(frameCount) InlinedFrame **frames, Js::ScriptFunction *parent)
      {
          Assert(!parentFunction);
          Assert(!this->frames);
          Assert(!this->frameCount);
          Assert(currentIndex == -1);
  
          this->parentFunction = parent;
          this->frames         = frames;
          this->frameCount     = frameCount;
          this->currentIndex   = -1;
      }
  
      InlinedFrameWalker::InlinedFrame* InlinedFrameWalker::InlinedFrame::FromPhysicalFrame(StackFrame& currentFrame, const JavascriptStackWalker * const stackWalker, void *entry, EntryPointInfo* entryPointInfo, bool useInternalFrameInfo)
      {
          // If the current javascript frame is a native frame, get the inlined frame from it, otherwise
          // it may be possible that current frame is the interpreter frame for a jitted loop body
          // If the loop body had some inlinees in it, retrieve the inlined frame using the cached info,
          // viz. instruction pointer, frame pointer, and stackCheckCodeHeight, about the loop body frame.
          struct InlinedFrame *inlinedFrame = nullptr;
          void *codeAddr, *framePointer;
          size_t stackCheckCodeHeight;
  
          if (useInternalFrameInfo)
          {
              codeAddr = stackWalker->GetCachedInternalFrameInfo().codeAddress;
              framePointer = stackWalker->GetCachedInternalFrameInfo().framePointer;
              stackCheckCodeHeight = stackWalker->GetCachedInternalFrameInfo().stackCheckCodeHeight;
          }
          else
          {
              codeAddr = currentFrame.GetInstructionPointer();
              framePointer = currentFrame.GetFrame();
              stackCheckCodeHeight = currentFrame.GetStackCheckCodeHeight();
          }
  
          if (!StackFrame::IsInStackCheckCode(entry, codeAddr, stackCheckCodeHeight))
          {
              inlinedFrame = (struct InlinedFrame *)(((uint8 *)framePointer) - entryPointInfo->GetFrameHeight());
          }
  
          return inlinedFrame;
      }
  
      void InternalFrameInfo::Set(
          void *codeAddress,
          void *framePointer,
          size_t stackCheckCodeHeight,
          InternalFrameType frameType,
          JavascriptFunction* function,
          bool hasInlinedFramesOnStack,
          bool previousInterpreterFrameIsFromBailout)
      {
          // 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.
          // However, if the loop body has inlinees, to retrieve inlinee frames we need to cache some info about the loop body's native frame.
          this->codeAddress = codeAddress;
          this->framePointer = framePointer;
          this->stackCheckCodeHeight = stackCheckCodeHeight;
          this->frameType = frameType;
          this->function = function;
          this->hasInlinedFramesOnStack = hasInlinedFramesOnStack;
          this->previousInterpreterFrameIsFromBailout = previousInterpreterFrameIsFromBailout;
      }
  
      void InternalFrameInfo::Clear()
      {
          this->codeAddress = nullptr;
          this->framePointer = nullptr;
          this->stackCheckCodeHeight = (uint)-1;
          this->frameType = InternalFrameType_None;
          this->function = nullptr;
          this->hasInlinedFramesOnStack = false;
          this->previousInterpreterFrameIsFromBailout = false;
      }
  #endif
  
  #if DBG
      // Force a stack walk which till we find an interpreter frame
      // This will ensure inlined frames are decoded.
      bool JavascriptStackWalker::ValidateTopJitFrame(Js::ScriptContext* scriptContext)
      {
          if (!Configuration::Global.flags.ValidateInlineStack)
          {
              return true;
          }
          Js::JavascriptStackWalker walker(scriptContext);
          Js::JavascriptFunction* function;
          while (walker.GetCaller(&function))
          {
              Assert(function);
              if (walker.GetCurrentInterpreterFrame() != nullptr)
              {
                  break;
              }
          }
          // If no asserts have fired yet - we should have succeeded.
          return true;
      }
  #endif
  }
  