1/*
2 * Copyright (C) 2013-2018 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#pragma once
27
28#include "CalleeBits.h"
29#include "WasmIndexOrName.h"
30#include <wtf/Function.h>
31#include <wtf/Indenter.h>
32#include <wtf/text/WTFString.h>
33
34namespace JSC {
35
36struct EntryFrame;
37struct InlineCallFrame;
38
39class CodeBlock;
40class CodeOrigin;
41class ExecState;
42class JSCell;
43class JSFunction;
44class ClonedArguments;
45class Register;
46class RegisterAtOffsetList;
47
48typedef ExecState CallFrame;
49
50class StackVisitor {
51public:
52 class Frame {
53 public:
54 enum CodeType {
55 Global,
56 Eval,
57 Function,
58 Module,
59 Native,
60 Wasm
61 };
62
63 size_t index() const { return m_index; }
64 size_t argumentCountIncludingThis() const { return m_argumentCountIncludingThis; }
65 bool callerIsEntryFrame() const { return m_callerIsEntryFrame; }
66 CallFrame* callerFrame() const { return m_callerFrame; }
67 CalleeBits callee() const { return m_callee; }
68 CodeBlock* codeBlock() const { return m_codeBlock; }
69 unsigned bytecodeOffset() const { return m_bytecodeOffset; }
70 InlineCallFrame* inlineCallFrame() const {
71#if ENABLE(DFG_JIT)
72 return m_inlineCallFrame;
73#else
74 return nullptr;
75#endif
76 }
77
78 bool isNativeFrame() const { return !codeBlock() && !isWasmFrame(); }
79 bool isInlinedFrame() const { return !!inlineCallFrame(); }
80 bool isWasmFrame() const { return m_isWasmFrame; }
81 Wasm::IndexOrName const wasmFunctionIndexOrName()
82 {
83 ASSERT(isWasmFrame());
84 return m_wasmFunctionIndexOrName;
85 }
86
87 JS_EXPORT_PRIVATE String functionName() const;
88 JS_EXPORT_PRIVATE String sourceURL() const;
89 JS_EXPORT_PRIVATE String toString() const;
90
91 JS_EXPORT_PRIVATE intptr_t sourceID();
92
93 CodeType codeType() const;
94 bool hasLineAndColumnInfo() const;
95 JS_EXPORT_PRIVATE void computeLineAndColumn(unsigned& line, unsigned& column) const;
96
97#if ENABLE(ASSEMBLER)
98 Optional<RegisterAtOffsetList> calleeSaveRegistersForUnwinding();
99#endif
100
101 ClonedArguments* createArguments();
102 CallFrame* callFrame() const { return m_callFrame; }
103
104 void dump(PrintStream&, Indenter = Indenter()) const;
105 void dump(PrintStream&, Indenter, WTF::Function<void(PrintStream&)> prefix) const;
106
107 private:
108 Frame() { }
109 ~Frame() { }
110
111 void retrieveExpressionInfo(int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column) const;
112 void setToEnd();
113
114#if ENABLE(DFG_JIT)
115 InlineCallFrame* m_inlineCallFrame;
116#endif
117 CallFrame* m_callFrame;
118 EntryFrame* m_entryFrame;
119 EntryFrame* m_callerEntryFrame;
120 CallFrame* m_callerFrame;
121 CalleeBits m_callee;
122 CodeBlock* m_codeBlock;
123 size_t m_index;
124 size_t m_argumentCountIncludingThis;
125 unsigned m_bytecodeOffset;
126 bool m_callerIsEntryFrame : 1;
127 bool m_isWasmFrame : 1;
128 Wasm::IndexOrName m_wasmFunctionIndexOrName;
129
130 friend class StackVisitor;
131 };
132
133 enum Status {
134 Continue = 0,
135 Done = 1
136 };
137
138 // StackVisitor::visit() expects a Functor that implements the following method:
139 // Status operator()(StackVisitor&) const;
140
141 enum EmptyEntryFrameAction {
142 ContinueIfTopEntryFrameIsEmpty,
143 TerminateIfTopEntryFrameIsEmpty,
144 };
145
146 template <EmptyEntryFrameAction action = ContinueIfTopEntryFrameIsEmpty, typename Functor>
147 static void visit(CallFrame* startFrame, VM* vm, const Functor& functor)
148 {
149 StackVisitor visitor(startFrame, vm);
150 if (action == TerminateIfTopEntryFrameIsEmpty && visitor.topEntryFrameIsEmpty())
151 return;
152 while (visitor->callFrame()) {
153 Status status = functor(visitor);
154 if (status != Continue)
155 break;
156 visitor.gotoNextFrame();
157 }
158 }
159
160 Frame& operator*() { return m_frame; }
161 ALWAYS_INLINE Frame* operator->() { return &m_frame; }
162 void unwindToMachineCodeBlockFrame();
163
164 bool topEntryFrameIsEmpty() const { return m_topEntryFrameIsEmpty; }
165
166private:
167 JS_EXPORT_PRIVATE StackVisitor(CallFrame* startFrame, VM*);
168
169 JS_EXPORT_PRIVATE void gotoNextFrame();
170
171 void readFrame(CallFrame*);
172 void readNonInlinedFrame(CallFrame*, CodeOrigin* = 0);
173#if ENABLE(DFG_JIT)
174 void readInlinedFrame(CallFrame*, CodeOrigin*);
175#endif
176
177 Frame m_frame;
178 bool m_topEntryFrameIsEmpty { false };
179};
180
181class CallerFunctor {
182public:
183 CallerFunctor()
184 : m_hasSkippedFirstFrame(false)
185 , m_callerFrame(0)
186 {
187 }
188
189 CallFrame* callerFrame() const { return m_callerFrame; }
190
191 StackVisitor::Status operator()(StackVisitor& visitor) const
192 {
193 if (!m_hasSkippedFirstFrame) {
194 m_hasSkippedFirstFrame = true;
195 return StackVisitor::Continue;
196 }
197
198 m_callerFrame = visitor->callFrame();
199 return StackVisitor::Done;
200 }
201
202private:
203 mutable bool m_hasSkippedFirstFrame;
204 mutable CallFrame* m_callerFrame;
205};
206
207} // namespace JSC
208