Hook up ShadowChicken to the debugger to show tail deleted frames
[WebKit-https.git] / Source / JavaScriptCore / inspector / JSJavaScriptCallFrame.cpp
1 /*
2  * Copyright (C) 2014 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "JSJavaScriptCallFrame.h"
28
29 #include "DebuggerScope.h"
30 #include "Error.h"
31 #include "JSCJSValue.h"
32 #include "JSCellInlines.h"
33 #include "JSJavaScriptCallFramePrototype.h"
34 #include "StructureInlines.h"
35
36 using namespace JSC;
37
38 namespace Inspector {
39
40 const ClassInfo JSJavaScriptCallFrame::s_info = { "JavaScriptCallFrame", &Base::s_info, 0, CREATE_METHOD_TABLE(JSJavaScriptCallFrame) };
41
42 JSJavaScriptCallFrame::JSJavaScriptCallFrame(VM& vm, Structure* structure, PassRefPtr<JavaScriptCallFrame> impl)
43     : JSDestructibleObject(vm, structure)
44     , m_impl(impl.leakRef())
45 {
46 }
47
48 void JSJavaScriptCallFrame::finishCreation(VM& vm)
49 {
50     Base::finishCreation(vm);
51     ASSERT(inherits(info()));
52 }
53
54 JSObject* JSJavaScriptCallFrame::createPrototype(VM& vm, JSGlobalObject* globalObject)
55 {
56     return JSJavaScriptCallFramePrototype::create(vm, globalObject, JSJavaScriptCallFramePrototype::createStructure(vm, globalObject, globalObject->objectPrototype()));
57 }
58
59 void JSJavaScriptCallFrame::destroy(JSC::JSCell* cell)
60 {
61     JSJavaScriptCallFrame* thisObject = static_cast<JSJavaScriptCallFrame*>(cell);
62     thisObject->JSJavaScriptCallFrame::~JSJavaScriptCallFrame();
63 }
64
65 void JSJavaScriptCallFrame::releaseImpl()
66 {
67     if (auto impl = std::exchange(m_impl, nullptr))
68         impl->deref();
69 }
70
71 JSJavaScriptCallFrame::~JSJavaScriptCallFrame()
72 {
73     releaseImpl();
74 }
75
76 JSValue JSJavaScriptCallFrame::evaluateWithScopeExtension(ExecState* exec)
77 {
78     JSValue scriptValue = exec->argument(0);
79     if (!scriptValue.isString())
80         return throwTypeError(exec, "JSJavaScriptCallFrame.evaluateWithScopeExtension first argument must be a string.");
81
82     String script = scriptValue.toString(exec)->value(exec);
83     if (exec->hadException())
84         return jsUndefined();
85
86     NakedPtr<Exception> exception;
87     JSObject* scopeExtension = exec->argument(1).getObject();
88     JSValue result = impl().evaluateWithScopeExtension(script, scopeExtension, exception);
89     if (exception)
90         exec->vm().throwException(exec, exception);
91
92     return result;
93 }
94
95 JSValue JSJavaScriptCallFrame::scopeType(ExecState* exec)
96 {
97     if (!impl().scopeChain())
98         return jsUndefined();
99
100     if (!exec->argument(0).isInt32())
101         return jsUndefined();
102     int index = exec->argument(0).asInt32();
103
104     DebuggerScope* scopeChain = impl().scopeChain();
105     DebuggerScope::iterator end = scopeChain->end();
106
107     for (DebuggerScope::iterator iter = scopeChain->begin(); iter != end; ++iter) {
108         DebuggerScope* scope = iter.get();
109
110         if (!index) {
111             if (scope->isCatchScope())
112                 return jsNumber(JSJavaScriptCallFrame::CATCH_SCOPE);
113             if (scope->isFunctionNameScope())
114                 return jsNumber(JSJavaScriptCallFrame::FUNCTION_NAME_SCOPE);
115             if (scope->isWithScope())
116                 return jsNumber(JSJavaScriptCallFrame::WITH_SCOPE);
117             if (scope->isNestedLexicalScope())
118                 return jsNumber(JSJavaScriptCallFrame::NESTED_LEXICAL_SCOPE);
119             if (scope->isGlobalLexicalEnvironment())
120                 return jsNumber(JSJavaScriptCallFrame::GLOBAL_LEXICAL_ENVIRONMENT_SCOPE);
121             if (scope->isGlobalScope()) {
122                 ASSERT(++iter == end);
123                 return jsNumber(JSJavaScriptCallFrame::GLOBAL_SCOPE);
124             }
125             ASSERT(scope->isClosureScope());
126             return jsNumber(JSJavaScriptCallFrame::CLOSURE_SCOPE);
127         }
128
129         --index;
130     }
131
132     ASSERT_NOT_REACHED();
133     return jsUndefined();
134 }
135
136 JSValue JSJavaScriptCallFrame::caller(ExecState* exec) const
137 {
138     return toJS(exec, globalObject(), impl().caller());
139 }
140
141 JSValue JSJavaScriptCallFrame::sourceID(ExecState*) const
142 {
143     return jsNumber(impl().sourceID());
144 }
145
146 JSValue JSJavaScriptCallFrame::line(ExecState*) const
147 {
148     return jsNumber(impl().line());
149 }
150
151 JSValue JSJavaScriptCallFrame::column(ExecState*) const
152 {
153     return jsNumber(impl().column());
154 }
155
156 JSValue JSJavaScriptCallFrame::functionName(ExecState* exec) const
157 {
158     return jsString(exec, impl().functionName());
159 }
160
161 JSValue JSJavaScriptCallFrame::scopeChain(ExecState* exec) const
162 {
163     if (!impl().scopeChain())
164         return jsNull();
165
166     DebuggerScope* scopeChain = impl().scopeChain();
167     DebuggerScope::iterator iter = scopeChain->begin();
168     DebuggerScope::iterator end = scopeChain->end();
169
170     // We must always have something in the scope chain.
171     ASSERT(iter != end);
172
173     MarkedArgumentBuffer list;
174     do {
175         list.append(iter.get());
176         ++iter;
177     } while (iter != end);
178
179     return constructArray(exec, nullptr, globalObject(), list);
180 }
181
182 JSValue JSJavaScriptCallFrame::thisObject(ExecState*) const
183 {
184     return impl().thisValue();
185 }
186
187 JSValue JSJavaScriptCallFrame::isTailDeleted(JSC::ExecState*) const
188 {
189     return jsBoolean(impl().isTailDeleted());
190 }
191
192 JSValue JSJavaScriptCallFrame::type(ExecState* exec) const
193 {
194     switch (impl().type()) {
195     case DebuggerCallFrame::FunctionType:
196         return jsNontrivialString(exec, ASCIILiteral("function"));
197     case DebuggerCallFrame::ProgramType:
198         return jsNontrivialString(exec, ASCIILiteral("program"));
199     }
200
201     ASSERT_NOT_REACHED();
202     return jsNull();
203 }
204
205 JSValue toJS(ExecState* exec, JSGlobalObject* globalObject, JavaScriptCallFrame* impl)
206 {
207     if (!impl)
208         return jsNull();
209
210     JSObject* prototype = JSJavaScriptCallFrame::createPrototype(exec->vm(), globalObject);
211     Structure* structure = JSJavaScriptCallFrame::createStructure(exec->vm(), globalObject, prototype);
212     JSJavaScriptCallFrame* javaScriptCallFrame = JSJavaScriptCallFrame::create(exec->vm(), structure, impl);
213
214     return javaScriptCallFrame;
215 }
216
217 JSJavaScriptCallFrame* toJSJavaScriptCallFrame(JSValue value)
218 {
219     return value.inherits(JSJavaScriptCallFrame::info()) ? jsCast<JSJavaScriptCallFrame*>(value) : nullptr;
220 }
221
222 } // namespace Inspector
223