Hook up ShadowChicken to the debugger to show tail deleted frames
https://bugs.webkit.org/show_bug.cgi?id=156685
<rdar://problem/25770521>

Reviewed by Filip Pizlo and Mark Lam and Joseph Pecoraro.

Source/JavaScriptCore:

The heart of this patch hooks up ShadowChicken to DebuggerCallFrame to
allow the Web Inspector to display the ShadowChicken's shadow stack.
This means the Web Inspector can now display tail deleted frames.
To make this work, I made the necessary changes to ShadowChicken and
DebuggerCallFrame to allow DebuggerCallFrame to keep the same API
when representing both machine frames and tail deleted frames.

- ShadowChicken prologue packets now log the current scope. Tail packets
  log the current scope, the 'this' value, the CodeBlock, and the
  CallSiteIndex. This allows the inspector to not only show the
  tail deleted frame, but also show exactly where the tail call happened (line and column numbers),
  with which scope it executed, and with which 'this' value. This
  patch also allows DebuggerCallFrame to execute console statements
  in a tail deleted frame.

- I changed ShadowChicken's stack resizing algorithm. ShadowChicken
  now only keeps a maximum number of tail deleted frames in its shadow stack.
  It will happily represent all machine frames without limit. Right now, the
  maximum number of tail deleted frames I chose to keep alive is 128.
  We will keep frames alive starting from the top of the stack. This
  allows us to have a strong defense against runaway memory usage. We will only
  keep around at most 128 "shadow" frames that wouldn't have naturally been kept
  alive by the executing program. We can play around with this number
  if we find that 128 is either too many or too few frames.

- DebuggerCallFrame is no longer a cheap class to create. When it is created,
  we will eagerly create the entire virtual debugger stack. So I modified the
  existing code to lazily create DebuggerCallFrames only when necessary. We
  used to eagerly create them at each op_debug statement even though we would
  just throw them away if we didn't hit a breakpoint.

- A valid DebuggerCallFrame will always have a valid CallFrame* pointer
  into the stack. This pointer won't always refer to the logical frame
  that the DebuggerCallFrame represents because a DebuggerCallFrame can
  now represent a tail deleted frame. To do this, DebuggerCallFrame now
  has a ShadowChicken::Frame member variable. This allows DebuggerCallFrame
  to know when it represents a tail deleted frame and gives DebuggerCallFrame
  a mechanism to ask the tail deleted frame for interesting information
  (like its 'this' value, scope, CodeBlock, etc). A tail deleted frame's
  machine frame pointer will be the machine caller of the tail deleted frame
  (or the machine caller of the first of a series of consecutive tail calls).

- I added a new flag to UnlinkedCodeBlock to indicate when it is compiled
  with debugging opcodes. I did this because ShadowChicken may read a JSScope
  from the machine stack. This is only safe if the machine CodeBlock was
  compiled with debugging opcodes. This is safer than asking if the
  CodeBlock's global object has an interactive debugger enabled because
  it's theoretically possible for the debugger to be enabled while code
  compiled without a debugger is still live on the stack. This field is
  also now used to indicate to the DFGGraph that the interactive debugger
  is enabled.

- Finally, this patch adds a new field to the Inspector's CallFrame protocol
  object called 'isTailDeleted' to allow the Inspector to know when a
  CallFrame represents a tail deleted frame.

* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::findPC):
(JSC::CodeBlock::bytecodeOffsetFromCallSiteIndex):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::clearDebuggerRequests):
(JSC::CodeBlock::wasCompiledWithDebuggingOpcodes):
* bytecode/UnlinkedCodeBlock.cpp:
(JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):
* bytecode/UnlinkedCodeBlock.h:
(JSC::UnlinkedCodeBlock::wasCompiledWithDebuggingOpcodes):
(JSC::UnlinkedCodeBlock::finishCreation):
(JSC::UnlinkedGlobalCodeBlock::UnlinkedGlobalCodeBlock):
* bytecode/UnlinkedFunctionExecutable.cpp:
(JSC::generateUnlinkedFunctionCodeBlock):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::generate):
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitEnter):
(JSC::BytecodeGenerator::emitLogShadowChickenPrologueIfNecessary):
(JSC::BytecodeGenerator::emitLogShadowChickenTailIfNecessary):
(JSC::BytecodeGenerator::emitCallDefineProperty):
* debugger/Debugger.cpp:
(JSC::DebuggerPausedScope::DebuggerPausedScope):
(JSC::DebuggerPausedScope::~DebuggerPausedScope):
(JSC::Debugger::didReachBreakpoint):
(JSC::Debugger::currentDebuggerCallFrame):
* debugger/Debugger.h:
* debugger/DebuggerCallFrame.cpp:
(JSC::LineAndColumnFunctor::operator()):
(JSC::DebuggerCallFrame::create):
(JSC::DebuggerCallFrame::DebuggerCallFrame):
(JSC::DebuggerCallFrame::callerFrame):
(JSC::DebuggerCallFrame::globalExec):
(JSC::DebuggerCallFrame::vmEntryGlobalObject):
(JSC::DebuggerCallFrame::sourceID):
(JSC::DebuggerCallFrame::functionName):
(JSC::DebuggerCallFrame::scope):
(JSC::DebuggerCallFrame::type):
(JSC::DebuggerCallFrame::thisValue):
(JSC::DebuggerCallFrame::evaluateWithScopeExtension):
(JSC::DebuggerCallFrame::invalidate):
(JSC::DebuggerCallFrame::currentPosition):
(JSC::DebuggerCallFrame::positionForCallFrame):
(JSC::DebuggerCallFrame::sourceIDForCallFrame):
(JSC::FindCallerMidStackFunctor::FindCallerMidStackFunctor): Deleted.
(JSC::FindCallerMidStackFunctor::operator()): Deleted.
(JSC::FindCallerMidStackFunctor::getCallerFrame): Deleted.
(JSC::DebuggerCallFrame::thisValueForCallFrame): Deleted.
* debugger/DebuggerCallFrame.h:
(JSC::DebuggerCallFrame::isValid):
(JSC::DebuggerCallFrame::isTailDeleted):
(JSC::DebuggerCallFrame::create): Deleted.
(JSC::DebuggerCallFrame::exec): Deleted.
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::Graph):
(JSC::DFG::Graph::~Graph):
* dfg/DFGJITCompiler.h:
(JSC::DFG::JITCompiler::addCallSite):
(JSC::DFG::JITCompiler::emitStoreCodeOrigin):
(JSC::DFG::JITCompiler::emitStoreCallSiteIndex):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLAbstractHeapRepository.h:
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenPrologue):
(JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenTail):
(JSC::FTL::DFG::LowerDFGToB3::compileRecordRegExpCachedResult):
(JSC::FTL::DFG::LowerDFGToB3::allocateJSArray):
(JSC::FTL::DFG::LowerDFGToB3::ensureShadowChickenPacket):
(JSC::FTL::DFG::LowerDFGToB3::setupShadowChickenPacket): Deleted.
* inspector/InjectedScriptSource.js:
(InjectedScript.CallFrameProxy):
* inspector/JSJavaScriptCallFrame.cpp:
(Inspector::JSJavaScriptCallFrame::thisObject):
(Inspector::JSJavaScriptCallFrame::isTailDeleted):
(Inspector::JSJavaScriptCallFrame::type):
* inspector/JSJavaScriptCallFrame.h:
* inspector/JSJavaScriptCallFramePrototype.cpp:
(Inspector::JSJavaScriptCallFramePrototype::finishCreation):
(Inspector::jsJavaScriptCallFramePrototypeFunctionEvaluateWithScopeExtension):
(Inspector::jsJavaScriptCallFrameAttributeType):
(Inspector::jsJavaScriptCallFrameIsTailDeleted):
* inspector/JavaScriptCallFrame.h:
(Inspector::JavaScriptCallFrame::type):
(Inspector::JavaScriptCallFrame::scopeChain):
(Inspector::JavaScriptCallFrame::vmEntryGlobalObject):
(Inspector::JavaScriptCallFrame::isTailDeleted):
(Inspector::JavaScriptCallFrame::thisValue):
(Inspector::JavaScriptCallFrame::evaluateWithScopeExtension):
* inspector/ScriptDebugServer.cpp:
(Inspector::ScriptDebugServer::evaluateBreakpointAction):
* inspector/protocol/Debugger.json:
* interpreter/ShadowChicken.cpp:
(JSC::ShadowChicken::update):
(JSC::ShadowChicken::visitChildren):
(JSC::ShadowChicken::reset):
* interpreter/ShadowChicken.h:
(JSC::ShadowChicken::Packet::throwMarker):
(JSC::ShadowChicken::Packet::prologue):
(JSC::ShadowChicken::Packet::tail):
(JSC::ShadowChicken::Frame::Frame):
(JSC::ShadowChicken::Frame::operator==):
* jit/CCallHelpers.cpp:
(JSC::CCallHelpers::logShadowChickenProloguePacket):
(JSC::CCallHelpers::logShadowChickenTailPacket):
(JSC::CCallHelpers::ensureShadowChickenPacket):
(JSC::CCallHelpers::setupShadowChickenPacket): Deleted.
* jit/CCallHelpers.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_profile_type):
(JSC::JIT::emit_op_log_shadow_chicken_prologue):
(JSC::JIT::emit_op_log_shadow_chicken_tail):
(JSC::JIT::emit_op_get_enumerable_length):
(JSC::JIT::emit_op_resume):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_profile_type):
(JSC::JIT::emit_op_log_shadow_chicken_prologue):
(JSC::JIT::emit_op_log_shadow_chicken_tail):
* jit/RegisterSet.cpp:
(JSC::RegisterSet::webAssemblyCalleeSaveRegisters):
(JSC::RegisterSet::argumentGPRS):
(JSC::RegisterSet::registersToNotSaveForJSCall):
* jit/RegisterSet.h:
* llint/LLIntData.cpp:
(JSC::LLInt::Data::performAssertions):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/CodeCache.cpp:
(JSC::CodeCache::getGlobalCodeBlock):
* runtime/Options.h:
* tests/stress/shadow-chicken-enabled.js:
(test5a.foo):
(test5a):
(test5b.foo):
(test5b):
(test6.foo):
(test6):

Source/WebCore:

Tests: inspector/debugger/tail-deleted-frames-this-value.html
       inspector/debugger/tail-deleted-frames.html
       inspector/debugger/tail-recursion.html

* ForwardingHeaders/interpreter/ShadowChicken.h: Added.

Source/WebInspectorUI:

This patch makes the WebInspector display tail deleted frames.
We show tail deleted frames with a gray [f] instead of a green
[f]. We also put text in the tooltip to indicate that the frame
is tail deleted. Other than that, tail deleted frames behave like
normal frames. You can evaluate in them, inspect their scope, etc.

* Localizations/en.lproj/localizedStrings.js:
* UserInterface/Images/TailDeletedFunction.svg: Added.
* UserInterface/Images/gtk/TailDeletedFunction.svg: Added.
* UserInterface/Models/CallFrame.js:
* UserInterface/Views/CallFrameIcons.css:
* UserInterface/Views/CallFrameTreeElement.js:
* UserInterface/Views/CallFrameView.js:

LayoutTests:

* inspector/debugger/resources/tail-deleted-frames-this-value.js: Added.
(a):
(b):
* inspector/debugger/resources/tail-deleted-frames.js: Added.
(a):
(b):
(c):
(startABC):
* inspector/debugger/resources/tail-recursion.js: Added.
(recurse):
(startRecurse):
* inspector/debugger/tail-deleted-frames-expected.txt: Added.
* inspector/debugger/tail-deleted-frames-this-value-expected.txt: Added.
* inspector/debugger/tail-deleted-frames-this-value.html: Added.
* inspector/debugger/tail-deleted-frames.html: Added.
* inspector/debugger/tail-recursion-expected.txt: Added.
* inspector/debugger/tail-recursion.html: Added.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@200981 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/debugger/DebuggerCallFrame.cpp b/Source/JavaScriptCore/debugger/DebuggerCallFrame.cpp
index 4b34bf3..8dc7e8f 100644
--- a/Source/JavaScriptCore/debugger/DebuggerCallFrame.cpp
+++ b/Source/JavaScriptCore/debugger/DebuggerCallFrame.cpp
@@ -38,14 +38,12 @@
 #include "JSLexicalEnvironment.h"
 #include "JSWithScope.h"
 #include "Parser.h"
+#include "ShadowChickenInlines.h"
 #include "StackVisitor.h"
 #include "StrongInlines.h"
 
 namespace JSC {
 
-// FIXME: Make this use ShadowChicken so that it sees tail-deleted frames.
-// https://bugs.webkit.org/show_bug.cgi?id=155690
-
 class LineAndColumnFunctor {
 public:
     StackVisitor::Status operator()(StackVisitor& visitor) const
@@ -62,61 +60,59 @@
     mutable unsigned m_column;
 };
 
-class FindCallerMidStackFunctor {
-public:
-    FindCallerMidStackFunctor(CallFrame* callFrame)
-        : m_callFrame(callFrame)
-        , m_callerFrame(nullptr)
-    { }
-
-    StackVisitor::Status operator()(StackVisitor& visitor) const
-    {
-        if (visitor->callFrame() == m_callFrame) {
-            m_callerFrame = visitor->callerFrame();
-            return StackVisitor::Done;
-        }
-        return StackVisitor::Continue;
-    }
-
-    CallFrame* getCallerFrame() const { return m_callerFrame; }
-
-private:
-    CallFrame* m_callFrame;
-    mutable CallFrame* m_callerFrame;
-};
-
-DebuggerCallFrame::DebuggerCallFrame(CallFrame* callFrame)
-    : m_callFrame(callFrame)
+Ref<DebuggerCallFrame> DebuggerCallFrame::create(CallFrame* callFrame)
 {
-    m_position = positionForCallFrame(m_callFrame);
+    Vector<ShadowChicken::Frame> frames;
+    callFrame->vm().shadowChicken().iterate(callFrame->vm(), callFrame, [&] (const ShadowChicken::Frame& frame) -> bool {
+        frames.append(frame);
+        return true;
+    });
+
+    RELEASE_ASSERT(frames.size());
+    RELEASE_ASSERT(!frames[0].isTailDeleted); // The top frame should never be tail deleted.
+    RELEASE_ASSERT(!frames[frames.size() - 1].isTailDeleted); // The first frame should never be tail deleted.
+
+    RefPtr<DebuggerCallFrame> currentParent = nullptr;
+    ExecState* exec = nullptr;
+    for (unsigned i = frames.size(); i--; ) {
+        const ShadowChicken::Frame& frame = frames[i];
+        if (!frame.isTailDeleted)
+            exec = frame.frame;
+        ASSERT(exec);
+        Ref<DebuggerCallFrame> currentFrame = adoptRef(*new DebuggerCallFrame(exec, frame));
+        currentFrame->m_caller = currentParent;
+        currentParent = WTFMove(currentFrame);
+    }
+    return *currentParent;
+}
+
+DebuggerCallFrame::DebuggerCallFrame(CallFrame* callFrame, const ShadowChicken::Frame& frame)
+    : m_validMachineFrame(callFrame)
+    , m_shadowChickenFrame(frame)
+{
+    m_position = currentPosition();
 }
 
 RefPtr<DebuggerCallFrame> DebuggerCallFrame::callerFrame()
 {
     ASSERT(isValid());
     if (!isValid())
-        return 0;
-
-    if (m_caller)
-        return m_caller;
-
-    FindCallerMidStackFunctor functor(m_callFrame);
-    m_callFrame->vm().topCallFrame->iterate(functor);
-
-    CallFrame* callerFrame = functor.getCallerFrame();
-    if (!callerFrame)
         return nullptr;
 
-    m_caller = DebuggerCallFrame::create(callerFrame);
     return m_caller;
 }
 
+ExecState* DebuggerCallFrame::globalExec()
+{
+    return scope()->globalObject()->globalExec();
+}
+
 JSC::JSGlobalObject* DebuggerCallFrame::vmEntryGlobalObject() const
 {
     ASSERT(isValid());
     if (!isValid())
-        return 0;
-    return m_callFrame->vmEntryGlobalObject();
+        return nullptr;
+    return m_validMachineFrame->vmEntryGlobalObject();
 }
 
 SourceID DebuggerCallFrame::sourceID() const
@@ -124,7 +120,9 @@
     ASSERT(isValid());
     if (!isValid())
         return noSourceID;
-    return sourceIDForCallFrame(m_callFrame);
+    if (isTailDeleted())
+        return m_shadowChickenFrame.codeBlock->ownerScriptExecutable()->sourceID();
+    return sourceIDForCallFrame(m_validMachineFrame);
 }
 
 String DebuggerCallFrame::functionName() const
@@ -132,25 +130,34 @@
     ASSERT(isValid());
     if (!isValid())
         return String();
-    return m_callFrame->friendlyFunctionName();
+
+    if (isTailDeleted()) {
+        if (JSFunction* func = jsDynamicCast<JSFunction*>(m_shadowChickenFrame.callee))
+            return func->calculatedDisplayName(m_validMachineFrame);
+        return m_shadowChickenFrame.codeBlock->inferredName().data();
+    }
+
+    return m_validMachineFrame->friendlyFunctionName();
 }
 
 DebuggerScope* DebuggerCallFrame::scope()
 {
     ASSERT(isValid());
     if (!isValid())
-        return 0;
+        return nullptr;
 
     if (!m_scope) {
-        VM& vm = m_callFrame->vm();
+        VM& vm = m_validMachineFrame->vm();
         JSScope* scope;
-        CodeBlock* codeBlock = m_callFrame->codeBlock();
-        if (codeBlock && codeBlock->scopeRegister().isValid())
-            scope = m_callFrame->scope(codeBlock->scopeRegister().offset());
-        else if (JSCallee* callee = jsDynamicCast<JSCallee*>(m_callFrame->callee()))
+        CodeBlock* codeBlock = m_validMachineFrame->codeBlock();
+        if (isTailDeleted())
+            scope = m_shadowChickenFrame.scope;
+        else if (codeBlock && codeBlock->scopeRegister().isValid())
+            scope = m_validMachineFrame->scope(codeBlock->scopeRegister().offset());
+        else if (JSCallee* callee = jsDynamicCast<JSCallee*>(m_validMachineFrame->callee()))
             scope = callee->scope();
         else
-            scope = m_callFrame->lexicalGlobalObject();
+            scope = m_validMachineFrame->lexicalGlobalObject()->globalLexicalEnvironment();
 
         m_scope.set(vm, DebuggerScope::create(vm, scope));
     }
@@ -163,7 +170,10 @@
     if (!isValid())
         return ProgramType;
 
-    if (jsDynamicCast<JSFunction*>(m_callFrame->callee()))
+    if (isTailDeleted())
+        return FunctionType;
+
+    if (jsDynamicCast<JSFunction*>(m_validMachineFrame->callee()))
         return FunctionType;
 
     return ProgramType;
@@ -172,40 +182,63 @@
 JSValue DebuggerCallFrame::thisValue() const
 {
     ASSERT(isValid());
-    return thisValueForCallFrame(m_callFrame);
+    if (!isValid())
+        return jsUndefined();
+
+    CodeBlock* codeBlock = nullptr;
+    JSValue thisValue;
+    if (isTailDeleted()) {
+        thisValue = m_shadowChickenFrame.thisValue;
+        codeBlock = m_shadowChickenFrame.codeBlock;
+    } else {
+        thisValue = m_validMachineFrame->thisValue();
+        codeBlock = m_validMachineFrame->codeBlock();
+    }
+
+    if (!thisValue)
+        return jsUndefined();
+
+    ECMAMode ecmaMode = NotStrictMode;
+    if (codeBlock && codeBlock->isStrictMode())
+        ecmaMode = StrictMode;
+    return thisValue.toThis(m_validMachineFrame, ecmaMode);
 }
 
 // Evaluate some JavaScript code in the scope of this frame.
 JSValue DebuggerCallFrame::evaluateWithScopeExtension(const String& script, JSObject* scopeExtensionObject, NakedPtr<Exception>& exception)
 {
     ASSERT(isValid());
-    CallFrame* callFrame = m_callFrame;
+    CallFrame* callFrame = m_validMachineFrame;
     if (!callFrame)
         return jsUndefined();
 
     JSLockHolder lock(callFrame);
 
-    if (!callFrame->codeBlock())
+    CodeBlock* codeBlock = nullptr;
+    if (isTailDeleted())
+        codeBlock = m_shadowChickenFrame.codeBlock;
+    else
+        codeBlock = callFrame->codeBlock();
+    if (!codeBlock)
         return jsUndefined();
     
     DebuggerEvalEnabler evalEnabler(callFrame);
     VM& vm = callFrame->vm();
-    auto& codeBlock = *callFrame->codeBlock();
-    ThisTDZMode thisTDZMode = codeBlock.unlinkedCodeBlock()->constructorKind() == ConstructorKind::Derived ? ThisTDZMode::AlwaysCheck : ThisTDZMode::CheckIfNeeded;
+    ThisTDZMode thisTDZMode = codeBlock->unlinkedCodeBlock()->constructorKind() == ConstructorKind::Derived ? ThisTDZMode::AlwaysCheck : ThisTDZMode::CheckIfNeeded;
 
     EvalContextType evalContextType;
     
-    if (isFunctionParseMode(codeBlock.unlinkedCodeBlock()->parseMode()))
+    if (isFunctionParseMode(codeBlock->unlinkedCodeBlock()->parseMode()))
         evalContextType = EvalContextType::FunctionEvalContext;
-    else if (codeBlock.unlinkedCodeBlock()->codeType() == EvalCode)
-        evalContextType = codeBlock.unlinkedCodeBlock()->evalContextType();
+    else if (codeBlock->unlinkedCodeBlock()->codeType() == EvalCode)
+        evalContextType = codeBlock->unlinkedCodeBlock()->evalContextType();
     else 
         evalContextType = EvalContextType::None;
 
     VariableEnvironment variablesUnderTDZ;
     JSScope::collectVariablesUnderTDZ(scope()->jsScope(), variablesUnderTDZ);
 
-    EvalExecutable* eval = EvalExecutable::create(callFrame, makeSource(script), codeBlock.isStrictMode(), thisTDZMode, codeBlock.unlinkedCodeBlock()->derivedContextType(), codeBlock.unlinkedCodeBlock()->isArrowFunction(), evalContextType, &variablesUnderTDZ);
+    EvalExecutable* eval = EvalExecutable::create(callFrame, makeSource(script), codeBlock->isStrictMode(), thisTDZMode, codeBlock->unlinkedCodeBlock()->derivedContextType(), codeBlock->unlinkedCodeBlock()->isArrowFunction(), evalContextType, &variablesUnderTDZ);
     if (vm.exception()) {
         exception = vm.exception();
         vm.clearException();
@@ -218,7 +251,7 @@
         globalObject->setGlobalScopeExtension(JSWithScope::create(vm, globalObject, scopeExtensionObject, ignoredPreviousScope));
     }
 
-    JSValue thisValue = thisValueForCallFrame(callFrame);
+    JSValue thisValue = this->thisValue();
     JSValue result = vm.interpreter->execute(eval, callFrame, thisValue, scope()->jsScope());
     if (vm.exception()) {
         exception = vm.exception();
@@ -236,7 +269,7 @@
 {
     RefPtr<DebuggerCallFrame> frame = this;
     while (frame) {
-        frame->m_callFrame = nullptr;
+        frame->m_validMachineFrame = nullptr;
         if (frame->m_scope) {
             frame->m_scope->invalidateChain();
             frame->m_scope.clear();
@@ -245,11 +278,24 @@
     }
 }
 
-TextPosition DebuggerCallFrame::positionForCallFrame(CallFrame* callFrame)
+TextPosition DebuggerCallFrame::currentPosition()
 {
-    if (!callFrame)
+    if (!m_validMachineFrame)
         return TextPosition();
 
+    if (isTailDeleted()) {
+        CodeBlock* codeBlock = m_shadowChickenFrame.codeBlock;
+        if (Optional<unsigned> bytecodeOffset = codeBlock->bytecodeOffsetFromCallSiteIndex(m_shadowChickenFrame.callSiteIndex)) {
+            return TextPosition(OrdinalNumber::fromOneBasedInt(codeBlock->lineNumberForBytecodeOffset(*bytecodeOffset)),
+                OrdinalNumber::fromOneBasedInt(codeBlock->columnNumberForBytecodeOffset(*bytecodeOffset)));
+        }
+    }
+
+    return positionForCallFrame(m_validMachineFrame);
+}
+
+TextPosition DebuggerCallFrame::positionForCallFrame(CallFrame* callFrame)
+{
     LineAndColumnFunctor functor;
     callFrame->iterate(functor);
     return TextPosition(OrdinalNumber::fromOneBasedInt(functor.line()), OrdinalNumber::fromOneBasedInt(functor.column()));
@@ -264,20 +310,4 @@
     return codeBlock->ownerScriptExecutable()->sourceID();
 }
 
-JSValue DebuggerCallFrame::thisValueForCallFrame(CallFrame* callFrame)
-{
-    if (!callFrame)
-        return jsUndefined();
-
-    if (!callFrame->thisValue())
-        return jsUndefined();
-
-    ECMAMode ecmaMode = NotStrictMode;
-    CodeBlock* codeBlock = callFrame->codeBlock();
-    if (codeBlock && codeBlock->isStrictMode())
-        ecmaMode = StrictMode;
-
-    return callFrame->thisValue().toThis(callFrame, ecmaMode);
-}
-
 } // namespace JSC