Web Inspector: Eliminate the crazy code for evaluateOnCallFrame
[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 "CodeBlock.h"
33 #include "DebuggerEvalEnabler.h"
34 #include "DebuggerScope.h"
35 #include "Interpreter.h"
36 #include "JSCInlines.h"
37 #include "JSFunction.h"
38 #include "JSLexicalEnvironment.h"
39 #include "JSWithScope.h"
40 #include "Parser.h"
41 #include "StackVisitor.h"
42 #include "StrongInlines.h"
43
44 namespace JSC {
45
46 // FIXME: Make this use ShadowChicken so that it sees tail-deleted frames.
47 // https://bugs.webkit.org/show_bug.cgi?id=155690
48
49 class LineAndColumnFunctor {
50 public:
51     StackVisitor::Status operator()(StackVisitor& visitor) const
52     {
53         visitor->computeLineAndColumn(m_line, m_column);
54         return StackVisitor::Done;
55     }
56
57     unsigned line() const { return m_line; }
58     unsigned column() const { return m_column; }
59
60 private:
61     mutable unsigned m_line;
62     mutable unsigned m_column;
63 };
64
65 class FindCallerMidStackFunctor {
66 public:
67     FindCallerMidStackFunctor(CallFrame* callFrame)
68         : m_callFrame(callFrame)
69         , m_callerFrame(nullptr)
70     { }
71
72     StackVisitor::Status operator()(StackVisitor& visitor) const
73     {
74         if (visitor->callFrame() == m_callFrame) {
75             m_callerFrame = visitor->callerFrame();
76             return StackVisitor::Done;
77         }
78         return StackVisitor::Continue;
79     }
80
81     CallFrame* getCallerFrame() const { return m_callerFrame; }
82
83 private:
84     CallFrame* m_callFrame;
85     mutable CallFrame* m_callerFrame;
86 };
87
88 DebuggerCallFrame::DebuggerCallFrame(CallFrame* callFrame)
89     : m_callFrame(callFrame)
90 {
91     m_position = positionForCallFrame(m_callFrame);
92 }
93
94 RefPtr<DebuggerCallFrame> DebuggerCallFrame::callerFrame()
95 {
96     ASSERT(isValid());
97     if (!isValid())
98         return 0;
99
100     if (m_caller)
101         return m_caller;
102
103     FindCallerMidStackFunctor functor(m_callFrame);
104     m_callFrame->vm().topCallFrame->iterate(functor);
105
106     CallFrame* callerFrame = functor.getCallerFrame();
107     if (!callerFrame)
108         return nullptr;
109
110     m_caller = DebuggerCallFrame::create(callerFrame);
111     return m_caller;
112 }
113
114 JSC::JSGlobalObject* DebuggerCallFrame::vmEntryGlobalObject() const
115 {
116     ASSERT(isValid());
117     if (!isValid())
118         return 0;
119     return m_callFrame->vmEntryGlobalObject();
120 }
121
122 SourceID DebuggerCallFrame::sourceID() const
123 {
124     ASSERT(isValid());
125     if (!isValid())
126         return noSourceID;
127     return sourceIDForCallFrame(m_callFrame);
128 }
129
130 String DebuggerCallFrame::functionName() const
131 {
132     ASSERT(isValid());
133     if (!isValid())
134         return String();
135     return m_callFrame->friendlyFunctionName();
136 }
137
138 DebuggerScope* DebuggerCallFrame::scope()
139 {
140     ASSERT(isValid());
141     if (!isValid())
142         return 0;
143
144     if (!m_scope) {
145         VM& vm = m_callFrame->vm();
146         JSScope* scope;
147         CodeBlock* codeBlock = m_callFrame->codeBlock();
148         if (codeBlock && codeBlock->scopeRegister().isValid())
149             scope = m_callFrame->scope(codeBlock->scopeRegister().offset());
150         else if (JSCallee* callee = jsDynamicCast<JSCallee*>(m_callFrame->callee()))
151             scope = callee->scope();
152         else
153             scope = m_callFrame->lexicalGlobalObject();
154
155         m_scope.set(vm, DebuggerScope::create(vm, scope));
156     }
157     return m_scope.get();
158 }
159
160 DebuggerCallFrame::Type DebuggerCallFrame::type() const
161 {
162     ASSERT(isValid());
163     if (!isValid())
164         return ProgramType;
165
166     if (jsDynamicCast<JSFunction*>(m_callFrame->callee()))
167         return FunctionType;
168
169     return ProgramType;
170 }
171
172 JSValue DebuggerCallFrame::thisValue() const
173 {
174     ASSERT(isValid());
175     return thisValueForCallFrame(m_callFrame);
176 }
177
178 // Evaluate some JavaScript code in the scope of this frame.
179 JSValue DebuggerCallFrame::evaluateWithScopeExtension(const String& script, JSObject* scopeExtensionObject, NakedPtr<Exception>& exception)
180 {
181     ASSERT(isValid());
182     CallFrame* callFrame = m_callFrame;
183     if (!callFrame)
184         return jsUndefined();
185
186     JSLockHolder lock(callFrame);
187
188     if (!callFrame->codeBlock())
189         return jsUndefined();
190     
191     DebuggerEvalEnabler evalEnabler(callFrame);
192     VM& vm = callFrame->vm();
193     auto& codeBlock = *callFrame->codeBlock();
194     ThisTDZMode thisTDZMode = codeBlock.unlinkedCodeBlock()->constructorKind() == ConstructorKind::Derived ? ThisTDZMode::AlwaysCheck : ThisTDZMode::CheckIfNeeded;
195
196     EvalContextType evalContextType;
197     
198     if (isFunctionParseMode(codeBlock.unlinkedCodeBlock()->parseMode()))
199         evalContextType = EvalContextType::FunctionEvalContext;
200     else if (codeBlock.unlinkedCodeBlock()->codeType() == EvalCode)
201         evalContextType = codeBlock.unlinkedCodeBlock()->evalContextType();
202     else 
203         evalContextType = EvalContextType::None;
204
205     VariableEnvironment variablesUnderTDZ;
206     JSScope::collectVariablesUnderTDZ(scope()->jsScope(), variablesUnderTDZ);
207
208     EvalExecutable* eval = EvalExecutable::create(callFrame, makeSource(script), codeBlock.isStrictMode(), thisTDZMode, codeBlock.unlinkedCodeBlock()->derivedContextType(), codeBlock.unlinkedCodeBlock()->isArrowFunction(), evalContextType, &variablesUnderTDZ);
209     if (vm.exception()) {
210         exception = vm.exception();
211         vm.clearException();
212         return jsUndefined();
213     }
214
215     JSGlobalObject* globalObject = callFrame->vmEntryGlobalObject();
216     if (scopeExtensionObject) {
217         JSScope* ignoredPreviousScope = globalObject->globalScope();
218         globalObject->setGlobalScopeExtension(JSWithScope::create(vm, globalObject, scopeExtensionObject, ignoredPreviousScope));
219     }
220
221     JSValue thisValue = thisValueForCallFrame(callFrame);
222     JSValue result = vm.interpreter->execute(eval, callFrame, thisValue, scope()->jsScope());
223     if (vm.exception()) {
224         exception = vm.exception();
225         vm.clearException();
226     }
227
228     if (scopeExtensionObject)
229         globalObject->clearGlobalScopeExtension();
230
231     ASSERT(result);
232     return result;
233 }
234
235 void DebuggerCallFrame::invalidate()
236 {
237     RefPtr<DebuggerCallFrame> frame = this;
238     while (frame) {
239         frame->m_callFrame = nullptr;
240         if (frame->m_scope) {
241             frame->m_scope->invalidateChain();
242             frame->m_scope.clear();
243         }
244         frame = frame->m_caller.release();
245     }
246 }
247
248 TextPosition DebuggerCallFrame::positionForCallFrame(CallFrame* callFrame)
249 {
250     if (!callFrame)
251         return TextPosition();
252
253     LineAndColumnFunctor functor;
254     callFrame->iterate(functor);
255     return TextPosition(OrdinalNumber::fromOneBasedInt(functor.line()), OrdinalNumber::fromOneBasedInt(functor.column()));
256 }
257
258 SourceID DebuggerCallFrame::sourceIDForCallFrame(CallFrame* callFrame)
259 {
260     ASSERT(callFrame);
261     CodeBlock* codeBlock = callFrame->codeBlock();
262     if (!codeBlock)
263         return noSourceID;
264     return codeBlock->ownerScriptExecutable()->sourceID();
265 }
266
267 JSValue DebuggerCallFrame::thisValueForCallFrame(CallFrame* callFrame)
268 {
269     if (!callFrame)
270         return jsUndefined();
271
272     if (!callFrame->thisValue())
273         return jsUndefined();
274
275     ECMAMode ecmaMode = NotStrictMode;
276     CodeBlock* codeBlock = callFrame->codeBlock();
277     if (codeBlock && codeBlock->isStrictMode())
278         ecmaMode = StrictMode;
279
280     return callFrame->thisValue().toThis(callFrame, ecmaMode);
281 }
282
283 } // namespace JSC