1 | // Copyright 2016 the V8 project authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | #ifndef V8_SOURCE_POSITION_H_ |
6 | #define V8_SOURCE_POSITION_H_ |
7 | |
8 | #include <ostream> |
9 | |
10 | #include "src/flags.h" |
11 | #include "src/globals.h" |
12 | #include "src/handles.h" |
13 | #include "src/utils.h" |
14 | |
15 | namespace v8 { |
16 | namespace internal { |
17 | |
18 | class Code; |
19 | class OptimizedCompilationInfo; |
20 | class Script; |
21 | class SharedFunctionInfo; |
22 | struct SourcePositionInfo; |
23 | |
24 | // SourcePosition stores |
25 | // - is_external (1 bit true/false) |
26 | // |
27 | // - if is_external is true: |
28 | // - external_line (20 bits, non-negative int) |
29 | // - external_file_id (10 bits, non-negative int) |
30 | // |
31 | // - if is_external is false: |
32 | // - script_offset (30 bit non-negative int or kNoSourcePosition) |
33 | // |
34 | // - In both cases, there is an inlining_id. |
35 | // - inlining_id (16 bit non-negative int or kNotInlined). |
36 | // |
37 | // An "external" SourcePosition is one given by a file_id and a line, |
38 | // suitable for embedding references to .cc or .tq files. |
39 | // Otherwise, a SourcePosition contains an offset into a JavaScript |
40 | // file. |
41 | // |
42 | // A defined inlining_id refers to positions in |
43 | // OptimizedCompilationInfo::inlined_functions or |
44 | // DeoptimizationData::InliningPositions, depending on the compilation stage. |
45 | class SourcePosition final { |
46 | public: |
47 | explicit SourcePosition(int script_offset, int inlining_id = kNotInlined) |
48 | : value_(0) { |
49 | SetIsExternal(false); |
50 | SetScriptOffset(script_offset); |
51 | SetInliningId(inlining_id); |
52 | } |
53 | |
54 | // External SourcePositions should use the following method to construct |
55 | // SourcePositions to avoid confusion. |
56 | static SourcePosition External(int line, int file_id) { |
57 | return SourcePosition(line, file_id, kNotInlined); |
58 | } |
59 | |
60 | static SourcePosition Unknown() { return SourcePosition(kNoSourcePosition); } |
61 | bool IsKnown() const { |
62 | if (IsExternal()) return true; |
63 | return ScriptOffset() != kNoSourcePosition || InliningId() != kNotInlined; |
64 | } |
65 | bool isInlined() const { |
66 | if (IsExternal()) return false; |
67 | return InliningId() != kNotInlined; |
68 | } |
69 | |
70 | bool IsExternal() const { return IsExternalField::decode(value_); } |
71 | bool IsJavaScript() const { return !IsExternal(); } |
72 | |
73 | int ExternalLine() const { |
74 | DCHECK(IsExternal()); |
75 | return ExternalLineField::decode(value_); |
76 | } |
77 | |
78 | int ExternalFileId() const { |
79 | DCHECK(IsExternal()); |
80 | return ExternalFileIdField::decode(value_); |
81 | } |
82 | |
83 | // Assumes that the code object is optimized |
84 | std::vector<SourcePositionInfo> InliningStack(Handle<Code> code) const; |
85 | std::vector<SourcePositionInfo> InliningStack( |
86 | OptimizedCompilationInfo* cinfo) const; |
87 | |
88 | void Print(std::ostream& out, Code code) const; |
89 | void PrintJson(std::ostream& out) const; |
90 | |
91 | int ScriptOffset() const { |
92 | DCHECK(IsJavaScript()); |
93 | return ScriptOffsetField::decode(value_) - 1; |
94 | } |
95 | int InliningId() const { return InliningIdField::decode(value_) - 1; } |
96 | |
97 | void SetIsExternal(bool external) { |
98 | value_ = IsExternalField::update(value_, external); |
99 | } |
100 | void SetExternalLine(int line) { |
101 | DCHECK(IsExternal()); |
102 | DCHECK(line <= ExternalLineField::kMax - 1); |
103 | value_ = ExternalLineField::update(value_, line); |
104 | } |
105 | void SetExternalFileId(int file_id) { |
106 | DCHECK(IsExternal()); |
107 | DCHECK(file_id <= ExternalFileIdField::kMax - 1); |
108 | value_ = ExternalFileIdField::update(value_, file_id); |
109 | } |
110 | |
111 | void SetScriptOffset(int script_offset) { |
112 | DCHECK(IsJavaScript()); |
113 | DCHECK(script_offset <= ScriptOffsetField::kMax - 2); |
114 | DCHECK_GE(script_offset, kNoSourcePosition); |
115 | value_ = ScriptOffsetField::update(value_, script_offset + 1); |
116 | } |
117 | void SetInliningId(int inlining_id) { |
118 | DCHECK(inlining_id <= InliningIdField::kMax - 2); |
119 | DCHECK_GE(inlining_id, kNotInlined); |
120 | value_ = InliningIdField::update(value_, inlining_id + 1); |
121 | } |
122 | |
123 | static const int kNotInlined = -1; |
124 | STATIC_ASSERT(kNoSourcePosition == -1); |
125 | |
126 | int64_t raw() const { return static_cast<int64_t>(value_); } |
127 | static SourcePosition FromRaw(int64_t raw) { |
128 | SourcePosition position = Unknown(); |
129 | DCHECK_GE(raw, 0); |
130 | position.value_ = static_cast<uint64_t>(raw); |
131 | return position; |
132 | } |
133 | |
134 | private: |
135 | // Used by SourcePosition::External(line, file_id). |
136 | SourcePosition(int line, int file_id, int inlining_id) : value_(0) { |
137 | SetIsExternal(true); |
138 | SetExternalLine(line); |
139 | SetExternalFileId(file_id); |
140 | SetInliningId(inlining_id); |
141 | } |
142 | |
143 | void Print(std::ostream& out, SharedFunctionInfo function) const; |
144 | |
145 | typedef BitField64<bool, 0, 1> IsExternalField; |
146 | |
147 | // The two below are only used if IsExternal() is true. |
148 | typedef BitField64<int, 1, 20> ExternalLineField; |
149 | typedef BitField64<int, 21, 10> ExternalFileIdField; |
150 | |
151 | // ScriptOffsetField is only used if IsExternal() is false. |
152 | typedef BitField64<int, 1, 30> ScriptOffsetField; |
153 | |
154 | // InliningId is in the high bits for better compression in |
155 | // SourcePositionTable. |
156 | typedef BitField64<int, 31, 16> InliningIdField; |
157 | |
158 | // Leaving the highest bit untouched to allow for signed conversion. |
159 | uint64_t value_; |
160 | }; |
161 | |
162 | inline bool operator==(const SourcePosition& lhs, const SourcePosition& rhs) { |
163 | return lhs.raw() == rhs.raw(); |
164 | } |
165 | |
166 | inline bool operator!=(const SourcePosition& lhs, const SourcePosition& rhs) { |
167 | return !(lhs == rhs); |
168 | } |
169 | |
170 | struct InliningPosition { |
171 | // position of the inlined call |
172 | SourcePosition position = SourcePosition::Unknown(); |
173 | |
174 | // references position in DeoptimizationData::literals() |
175 | int inlined_function_id; |
176 | }; |
177 | |
178 | struct SourcePositionInfo { |
179 | SourcePositionInfo(SourcePosition pos, Handle<SharedFunctionInfo> f); |
180 | |
181 | SourcePosition position; |
182 | Handle<SharedFunctionInfo> shared; |
183 | Handle<Script> script; |
184 | int line = -1; |
185 | int column = -1; |
186 | }; |
187 | |
188 | std::ostream& operator<<(std::ostream& out, const SourcePosition& pos); |
189 | |
190 | std::ostream& operator<<(std::ostream& out, const SourcePositionInfo& pos); |
191 | std::ostream& operator<<(std::ostream& out, |
192 | const std::vector<SourcePositionInfo>& stack); |
193 | |
194 | } // namespace internal |
195 | } // namespace v8 |
196 | |
197 | #endif // V8_SOURCE_POSITION_H_ |
198 | |