Remove excessive headers from JavaScriptCore
[WebKit-https.git] / Source / JavaScriptCore / debugger / DebuggerCallFrame.cpp
1 /*
2  * Copyright (C) 2008, 2013-2014, 2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "DebuggerCallFrame.h"
31
32 #include "CatchScope.h"
33 #include "CodeBlock.h"
34 #include "DebuggerEvalEnabler.h"
35 #include "DebuggerScope.h"
36 #include "Interpreter.h"
37 #include "JSCInlines.h"
38 #include "JSFunction.h"
39 #include "JSLexicalEnvironment.h"
40 #include "JSWithScope.h"
41 #include "Parser.h"
42 #include "ShadowChickenInlines.h"
43 #include "StackVisitor.h"
44 #include "StrongInlines.h"
45
46 namespace JSC {
47
48 class LineAndColumnFunctor {
49 public:
50     StackVisitor::Status operator()(StackVisitor& visitor) const
51     {
52         visitor->computeLineAndColumn(m_line, m_column);
53         return StackVisitor::Done;
54     }
55
56     unsigned line() const { return m_line; }
57     unsigned column() const { return m_column; }
58
59 private:
60     mutable unsigned m_line;
61     mutable unsigned m_column;
62 };
63
64 Ref<DebuggerCallFrame> DebuggerCallFrame::create(VM& vm, CallFrame* callFrame)
65 {
66     if (UNLIKELY(callFrame == callFrame->wasmAwareLexicalGlobalObject(vm)->globalExec())) {
67         ShadowChicken::Frame emptyFrame;
68         RELEASE_ASSERT(!emptyFrame.isTailDeleted);
69         return adoptRef(*new DebuggerCallFrame(vm, callFrame, emptyFrame));
70     }
71
72     Vector<ShadowChicken::Frame> frames;
73     vm.shadowChicken().iterate(vm, callFrame, [&] (const ShadowChicken::Frame& frame) -> bool {
74         frames.append(frame);
75         return true;
76     });
77
78     RELEASE_ASSERT(frames.size());
79     ASSERT(!frames[0].isTailDeleted); // The top frame should never be tail deleted.
80
81     RefPtr<DebuggerCallFrame> currentParent = nullptr;
82     ExecState* exec = callFrame->wasmAwareLexicalGlobalObject(vm)->globalExec();
83     // This walks the stack from the entry stack frame to the top of the stack.
84     for (unsigned i = frames.size(); i--; ) {
85         const ShadowChicken::Frame& frame = frames[i];
86         if (!frame.isTailDeleted)
87             exec = frame.frame;
88         Ref<DebuggerCallFrame> currentFrame = adoptRef(*new DebuggerCallFrame(vm, exec, frame));
89         currentFrame->m_caller = currentParent;
90         currentParent = WTFMove(currentFrame);
91     }
92     return *currentParent;
93 }
94
95 DebuggerCallFrame::DebuggerCallFrame(VM& vm, CallFrame* callFrame, const ShadowChicken::Frame& frame)
96     : m_validMachineFrame(callFrame)
97     , m_shadowChickenFrame(frame)
98 {
99     m_position = currentPosition(vm);
100 }
101
102 RefPtr<DebuggerCallFrame> DebuggerCallFrame::callerFrame()
103 {
104     ASSERT(isValid());
105     if (!isValid())
106         return nullptr;
107
108     return m_caller;
109 }
110
111 ExecState* DebuggerCallFrame::globalExec()
112 {
113     return scope()->globalObject()->globalExec();
114 }
115
116 JSC::JSGlobalObject* DebuggerCallFrame::vmEntryGlobalObject() const
117 {
118     ASSERT(isValid());
119     if (!isValid())
120         return nullptr;
121     return m_validMachineFrame->vmEntryGlobalObject();
122 }
123
124 SourceID DebuggerCallFrame::sourceID() const
125 {
126     ASSERT(isValid());
127     if (!isValid())
128         return noSourceID;
129     if (isTailDeleted())
130         return m_shadowChickenFrame.codeBlock->ownerScriptExecutable()->sourceID();
131     return sourceIDForCallFrame(m_validMachineFrame);
132 }
133
134 String DebuggerCallFrame::functionName() const
135 {
136     ASSERT(isValid());
137     if (!isValid())
138         return String();
139
140     VM& vm = m_validMachineFrame->vm();
141     if (isTailDeleted()) {
142         if (JSFunction* func = jsDynamicCast<JSFunction*>(vm, m_shadowChickenFrame.callee))
143             return func->calculatedDisplayName(vm);
144         return m_shadowChickenFrame.codeBlock->inferredName().data();
145     }
146
147     return m_validMachineFrame->friendlyFunctionName();
148 }
149
150 DebuggerScope* DebuggerCallFrame::scope()
151 {
152     ASSERT(isValid());
153     if (!isValid())
154         return nullptr;
155
156     if (!m_scope) {
157         VM& vm = m_validMachineFrame->vm();
158         JSScope* scope;
159         CodeBlock* codeBlock = m_validMachineFrame->codeBlock();
160         if (isTailDeleted())
161             scope = m_shadowChickenFrame.scope;
162         else if (codeBlock && codeBlock->scopeRegister().isValid())
163             scope = m_validMachineFrame->scope(codeBlock->scopeRegister().offset());
164         else if (JSCallee* callee = jsDynamicCast<JSCallee*>(vm, m_validMachineFrame->jsCallee()))
165             scope = callee->scope();
166         else
167             scope = m_validMachineFrame->lexicalGlobalObject()->globalLexicalEnvironment();
168
169         m_scope.set(vm, DebuggerScope::create(vm, scope));
170     }
171     return m_scope.get();
172 }
173
174 DebuggerCallFrame::Type DebuggerCallFrame::type() const
175 {
176     ASSERT(isValid());
177     if (!isValid())
178         return ProgramType;
179
180     if (isTailDeleted())
181         return FunctionType;
182
183     if (jsDynamicCast<JSFunction*>(m_validMachineFrame->vm(), m_validMachineFrame->jsCallee()))
184         return FunctionType;
185
186     return ProgramType;
187 }
188
189 JSValue DebuggerCallFrame::thisValue() const
190 {
191     ASSERT(isValid());
192     if (!isValid())
193         return jsUndefined();
194
195     CodeBlock* codeBlock = nullptr;
196     JSValue thisValue;
197     if (isTailDeleted()) {
198         thisValue = m_shadowChickenFrame.thisValue;
199         codeBlock = m_shadowChickenFrame.codeBlock;
200     } else {
201         thisValue = m_validMachineFrame->thisValue();
202         codeBlock = m_validMachineFrame->codeBlock();
203     }
204
205     if (!thisValue)
206         return jsUndefined();
207
208     ECMAMode ecmaMode = NotStrictMode;
209     if (codeBlock && codeBlock->isStrictMode())
210         ecmaMode = StrictMode;
211     return thisValue.toThis(m_validMachineFrame, ecmaMode);
212 }
213
214 // Evaluate some JavaScript code in the scope of this frame.
215 JSValue DebuggerCallFrame::evaluateWithScopeExtension(const String& script, JSObject* scopeExtensionObject, NakedPtr<Exception>& exception)
216 {
217     ASSERT(isValid());
218     CallFrame* callFrame = m_validMachineFrame;
219     if (!callFrame)
220         return jsUndefined();
221
222     VM& vm = callFrame->vm();
223     JSLockHolder lock(vm);
224     auto catchScope = DECLARE_CATCH_SCOPE(vm);
225
226     CodeBlock* codeBlock = nullptr;
227     if (isTailDeleted())
228         codeBlock = m_shadowChickenFrame.codeBlock;
229     else
230         codeBlock = callFrame->codeBlock();
231     if (!codeBlock)
232         return jsUndefined();
233     
234     DebuggerEvalEnabler evalEnabler(callFrame);
235
236     EvalContextType evalContextType;
237     
238     if (isFunctionParseMode(codeBlock->unlinkedCodeBlock()->parseMode()))
239         evalContextType = EvalContextType::FunctionEvalContext;
240     else if (codeBlock->unlinkedCodeBlock()->codeType() == EvalCode)
241         evalContextType = codeBlock->unlinkedCodeBlock()->evalContextType();
242     else 
243         evalContextType = EvalContextType::None;
244
245     VariableEnvironment variablesUnderTDZ;
246     JSScope::collectClosureVariablesUnderTDZ(scope()->jsScope(), variablesUnderTDZ);
247
248     auto* eval = DirectEvalExecutable::create(callFrame, makeSource(script, callFrame->callerSourceOrigin()), codeBlock->isStrictMode(), codeBlock->unlinkedCodeBlock()->derivedContextType(), codeBlock->unlinkedCodeBlock()->isArrowFunction(), evalContextType, &variablesUnderTDZ);
249     if (UNLIKELY(catchScope.exception())) {
250         exception = catchScope.exception();
251         catchScope.clearException();
252         return jsUndefined();
253     }
254
255     JSGlobalObject* globalObject = callFrame->vmEntryGlobalObject();
256     if (scopeExtensionObject) {
257         JSScope* ignoredPreviousScope = globalObject->globalScope();
258         globalObject->setGlobalScopeExtension(JSWithScope::create(vm, globalObject, scopeExtensionObject, ignoredPreviousScope));
259     }
260
261     JSValue thisValue = this->thisValue();
262     JSValue result = vm.interpreter->execute(eval, callFrame, thisValue, scope()->jsScope());
263     if (UNLIKELY(catchScope.exception())) {
264         exception = catchScope.exception();
265         catchScope.clearException();
266     }
267
268     if (scopeExtensionObject)
269         globalObject->clearGlobalScopeExtension();
270
271     ASSERT(result);
272     return result;
273 }
274
275 void DebuggerCallFrame::invalidate()
276 {
277     RefPtr<DebuggerCallFrame> frame = this;
278     while (frame) {
279         frame->m_validMachineFrame = nullptr;
280         if (frame->m_scope) {
281             frame->m_scope->invalidateChain();
282             frame->m_scope.clear();
283         }
284         frame = WTFMove(frame->m_caller);
285     }
286 }
287
288 TextPosition DebuggerCallFrame::currentPosition(VM& vm)
289 {
290     if (!m_validMachineFrame)
291         return TextPosition();
292
293     if (isTailDeleted()) {
294         CodeBlock* codeBlock = m_shadowChickenFrame.codeBlock;
295         if (std::optional<unsigned> bytecodeOffset = codeBlock->bytecodeOffsetFromCallSiteIndex(m_shadowChickenFrame.callSiteIndex)) {
296             return TextPosition(OrdinalNumber::fromOneBasedInt(codeBlock->lineNumberForBytecodeOffset(*bytecodeOffset)),
297                 OrdinalNumber::fromOneBasedInt(codeBlock->columnNumberForBytecodeOffset(*bytecodeOffset)));
298         }
299     }
300
301     return positionForCallFrame(vm, m_validMachineFrame);
302 }
303
304 TextPosition DebuggerCallFrame::positionForCallFrame(VM& vm, CallFrame* callFrame)
305 {
306     LineAndColumnFunctor functor;
307     StackVisitor::visit(callFrame, &vm, functor);
308     return TextPosition(OrdinalNumber::fromOneBasedInt(functor.line()), OrdinalNumber::fromOneBasedInt(functor.column()));
309 }
310
311 SourceID DebuggerCallFrame::sourceIDForCallFrame(CallFrame* callFrame)
312 {
313     ASSERT(callFrame);
314     CodeBlock* codeBlock = callFrame->codeBlock();
315     if (!codeBlock)
316         return noSourceID;
317     return codeBlock->ownerScriptExecutable()->sourceID();
318 }
319
320 } // namespace JSC