]> git.saurik.com Git - apple/javascriptcore.git/blob - bytecode/CodeOrigin.h
cffd4eb9e55e8863e04dabc829d46357b4f6081b
[apple/javascriptcore.git] / bytecode / CodeOrigin.h
1 /*
2 * Copyright (C) 2011, 2012, 2013 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 #ifndef CodeOrigin_h
27 #define CodeOrigin_h
28
29 #include "CodeBlockHash.h"
30 #include "CodeSpecializationKind.h"
31 #include "JSFunction.h"
32 #include "ValueRecovery.h"
33 #include "WriteBarrier.h"
34 #include <wtf/BitVector.h>
35 #include <wtf/HashMap.h>
36 #include <wtf/PrintStream.h>
37 #include <wtf/StdLibExtras.h>
38 #include <wtf/Vector.h>
39
40 namespace JSC {
41
42 struct InlineCallFrame;
43 class ExecState;
44 class ScriptExecutable;
45 class JSFunction;
46
47 struct CodeOrigin {
48 static const unsigned invalidBytecodeIndex = UINT_MAX;
49
50 // Bytecode offset that you'd use to re-execute this instruction, and the
51 // bytecode index of the bytecode instruction that produces some result that
52 // you're interested in (used for mapping Nodes whose values you're using
53 // to bytecode instructions that have the appropriate value profile).
54 unsigned bytecodeIndex;
55
56 InlineCallFrame* inlineCallFrame;
57
58 CodeOrigin()
59 : bytecodeIndex(invalidBytecodeIndex)
60 , inlineCallFrame(0)
61 {
62 }
63
64 CodeOrigin(WTF::HashTableDeletedValueType)
65 : bytecodeIndex(invalidBytecodeIndex)
66 , inlineCallFrame(deletedMarker())
67 {
68 }
69
70 explicit CodeOrigin(unsigned bytecodeIndex, InlineCallFrame* inlineCallFrame = 0)
71 : bytecodeIndex(bytecodeIndex)
72 , inlineCallFrame(inlineCallFrame)
73 {
74 ASSERT(bytecodeIndex < invalidBytecodeIndex);
75 }
76
77 bool isSet() const { return bytecodeIndex != invalidBytecodeIndex; }
78 bool operator!() const { return !isSet(); }
79
80 bool isHashTableDeletedValue() const
81 {
82 return bytecodeIndex == invalidBytecodeIndex && !!inlineCallFrame;
83 }
84
85 // The inline depth is the depth of the inline stack, so 1 = not inlined,
86 // 2 = inlined one deep, etc.
87 unsigned inlineDepth() const;
88
89 // If the code origin corresponds to inlined code, gives you the heap object that
90 // would have owned the code if it had not been inlined. Otherwise returns 0.
91 ScriptExecutable* codeOriginOwner() const;
92
93 int stackOffset() const;
94
95 static unsigned inlineDepthForCallFrame(InlineCallFrame*);
96
97 unsigned hash() const;
98 bool operator==(const CodeOrigin& other) const;
99 bool operator!=(const CodeOrigin& other) const { return !(*this == other); }
100
101 // This checks if the two code origins correspond to the same stack trace snippets,
102 // but ignore whether the InlineCallFrame's are identical.
103 bool isApproximatelyEqualTo(const CodeOrigin& other) const;
104
105 unsigned approximateHash() const;
106
107 // Get the inline stack. This is slow, and is intended for debugging only.
108 Vector<CodeOrigin> inlineStack() const;
109
110 void dump(PrintStream&) const;
111 void dumpInContext(PrintStream&, DumpContext*) const;
112
113 private:
114 static InlineCallFrame* deletedMarker()
115 {
116 return bitwise_cast<InlineCallFrame*>(static_cast<uintptr_t>(1));
117 }
118 };
119
120 struct InlineCallFrame {
121 Vector<ValueRecovery> arguments; // Includes 'this'.
122 WriteBarrier<ScriptExecutable> executable;
123 ValueRecovery calleeRecovery;
124 CodeOrigin caller;
125 BitVector capturedVars; // Indexed by the machine call frame's variable numbering.
126 signed stackOffset : 30;
127 bool isCall : 1;
128 bool isClosureCall : 1; // If false then we know that callee/scope are constants and the DFG won't treat them as variables, i.e. they have to be recovered manually.
129 VirtualRegister argumentsRegister; // This is only set if the code uses arguments. The unmodified arguments register follows the unmodifiedArgumentsRegister() convention (see CodeBlock.h).
130
131 // There is really no good notion of a "default" set of values for
132 // InlineCallFrame's fields. This constructor is here just to reduce confusion if
133 // we forgot to initialize explicitly.
134 InlineCallFrame()
135 : stackOffset(0)
136 , isCall(false)
137 , isClosureCall(false)
138 {
139 }
140
141 CodeSpecializationKind specializationKind() const { return specializationFromIsCall(isCall); }
142
143 JSFunction* calleeConstant() const
144 {
145 if (calleeRecovery.isConstant())
146 return jsCast<JSFunction*>(calleeRecovery.constant());
147 return 0;
148 }
149
150 void visitAggregate(SlotVisitor& visitor)
151 {
152 visitor.append(&executable);
153 }
154
155 // Get the callee given a machine call frame to which this InlineCallFrame belongs.
156 JSFunction* calleeForCallFrame(ExecState*) const;
157
158 CString inferredName() const;
159 CodeBlockHash hash() const;
160 CString hashAsStringIfPossible() const;
161
162 CodeBlock* baselineCodeBlock() const;
163
164 ptrdiff_t callerFrameOffset() const { return stackOffset * sizeof(Register) + CallFrame::callerFrameOffset(); }
165 ptrdiff_t returnPCOffset() const { return stackOffset * sizeof(Register) + CallFrame::returnPCOffset(); }
166
167 void dumpBriefFunctionInformation(PrintStream&) const;
168 void dump(PrintStream&) const;
169 void dumpInContext(PrintStream&, DumpContext*) const;
170
171 MAKE_PRINT_METHOD(InlineCallFrame, dumpBriefFunctionInformation, briefFunctionInformation);
172 };
173
174 inline int CodeOrigin::stackOffset() const
175 {
176 if (!inlineCallFrame)
177 return 0;
178
179 return inlineCallFrame->stackOffset;
180 }
181
182 inline unsigned CodeOrigin::hash() const
183 {
184 return WTF::IntHash<unsigned>::hash(bytecodeIndex) +
185 WTF::PtrHash<InlineCallFrame*>::hash(inlineCallFrame);
186 }
187
188 inline bool CodeOrigin::operator==(const CodeOrigin& other) const
189 {
190 return bytecodeIndex == other.bytecodeIndex
191 && inlineCallFrame == other.inlineCallFrame;
192 }
193
194 inline ScriptExecutable* CodeOrigin::codeOriginOwner() const
195 {
196 if (!inlineCallFrame)
197 return 0;
198 return inlineCallFrame->executable.get();
199 }
200
201 struct CodeOriginHash {
202 static unsigned hash(const CodeOrigin& key) { return key.hash(); }
203 static bool equal(const CodeOrigin& a, const CodeOrigin& b) { return a == b; }
204 static const bool safeToCompareToEmptyOrDeleted = true;
205 };
206
207 struct CodeOriginApproximateHash {
208 static unsigned hash(const CodeOrigin& key) { return key.approximateHash(); }
209 static bool equal(const CodeOrigin& a, const CodeOrigin& b) { return a.isApproximatelyEqualTo(b); }
210 static const bool safeToCompareToEmptyOrDeleted = true;
211 };
212
213 } // namespace JSC
214
215 namespace WTF {
216
217 template<typename T> struct DefaultHash;
218 template<> struct DefaultHash<JSC::CodeOrigin> {
219 typedef JSC::CodeOriginHash Hash;
220 };
221
222 template<typename T> struct HashTraits;
223 template<> struct HashTraits<JSC::CodeOrigin> : SimpleClassHashTraits<JSC::CodeOrigin> {
224 static const bool emptyValueIsZero = false;
225 };
226
227 } // namespace WTF
228
229 #endif // CodeOrigin_h
230