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