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_CODEGEN_SOURCE_POSITION_H_
6 #define V8_CODEGEN_SOURCE_POSITION_H_
7
8 #include <iosfwd>
9
10 #include "src/base/bit-field.h"
11 #include "src/common/globals.h"
12 #include "src/flags/flags.h"
13 #include "src/handles/handles.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:
SourcePosition(int script_offset, int inlining_id = kNotInlined)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.
External(int line, int file_id)56 static SourcePosition External(int line, int file_id) {
57 return SourcePosition(line, file_id, kNotInlined);
58 }
59
Unknown()60 static SourcePosition Unknown() { return SourcePosition(kNoSourcePosition); }
IsKnown() const61 bool IsKnown() const {
62 if (IsExternal()) return true;
63 return ScriptOffset() != kNoSourcePosition || InliningId() != kNotInlined;
64 }
isInlined() const65 bool isInlined() const {
66 if (IsExternal()) return false;
67 return InliningId() != kNotInlined;
68 }
69
IsExternal() const70 bool IsExternal() const { return IsExternalField::decode(value_); }
IsJavaScript() const71 bool IsJavaScript() const { return !IsExternal(); }
72
ExternalLine() const73 int ExternalLine() const {
74 DCHECK(IsExternal());
75 return ExternalLineField::decode(value_);
76 }
77
ExternalFileId() const78 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 SourcePositionInfo FirstInfo(Handle<Code> code) const;
88
89 void Print(std::ostream& out, Code code) const;
90 void PrintJson(std::ostream& out) const;
91
ScriptOffset() const92 int ScriptOffset() const {
93 DCHECK(IsJavaScript());
94 return ScriptOffsetField::decode(value_) - 1;
95 }
InliningId() const96 int InliningId() const { return InliningIdField::decode(value_) - 1; }
97
SetIsExternal(bool external)98 void SetIsExternal(bool external) {
99 value_ = IsExternalField::update(value_, external);
100 }
SetExternalLine(int line)101 void SetExternalLine(int line) {
102 DCHECK(IsExternal());
103 DCHECK(line <= ExternalLineField::kMax - 1);
104 value_ = ExternalLineField::update(value_, line);
105 }
SetExternalFileId(int file_id)106 void SetExternalFileId(int file_id) {
107 DCHECK(IsExternal());
108 DCHECK(file_id <= ExternalFileIdField::kMax - 1);
109 value_ = ExternalFileIdField::update(value_, file_id);
110 }
111
SetScriptOffset(int script_offset)112 void SetScriptOffset(int script_offset) {
113 DCHECK(IsJavaScript());
114 DCHECK(script_offset <= ScriptOffsetField::kMax - 2);
115 DCHECK_GE(script_offset, kNoSourcePosition);
116 value_ = ScriptOffsetField::update(value_, script_offset + 1);
117 }
SetInliningId(int inlining_id)118 void SetInliningId(int inlining_id) {
119 DCHECK(inlining_id <= InliningIdField::kMax - 2);
120 DCHECK_GE(inlining_id, kNotInlined);
121 value_ = InliningIdField::update(value_, inlining_id + 1);
122 }
123
124 static const int kNotInlined = -1;
125 STATIC_ASSERT(kNoSourcePosition == -1);
126
raw() const127 int64_t raw() const { return static_cast<int64_t>(value_); }
FromRaw(int64_t raw)128 static SourcePosition FromRaw(int64_t raw) {
129 SourcePosition position = Unknown();
130 DCHECK_GE(raw, 0);
131 position.value_ = static_cast<uint64_t>(raw);
132 return position;
133 }
134
135 private:
136 // Used by SourcePosition::External(line, file_id).
SourcePosition(int line, int file_id, int inlining_id)137 SourcePosition(int line, int file_id, int inlining_id) : value_(0) {
138 SetIsExternal(true);
139 SetExternalLine(line);
140 SetExternalFileId(file_id);
141 SetInliningId(inlining_id);
142 }
143
144 void Print(std::ostream& out, SharedFunctionInfo function) const;
145
146 using IsExternalField = base::BitField64<bool, 0, 1>;
147
148 // The two below are only used if IsExternal() is true.
149 using ExternalLineField = base::BitField64<int, 1, 20>;
150 using ExternalFileIdField = base::BitField64<int, 21, 10>;
151
152 // ScriptOffsetField is only used if IsExternal() is false.
153 using ScriptOffsetField = base::BitField64<int, 1, 30>;
154
155 // InliningId is in the high bits for better compression in
156 // SourcePositionTable.
157 using InliningIdField = base::BitField64<int, 31, 16>;
158
159 // Leaving the highest bit untouched to allow for signed conversion.
160 uint64_t value_;
161 };
162
operator ==(const SourcePosition& lhs, const SourcePosition& rhs)163 inline bool operator==(const SourcePosition& lhs, const SourcePosition& rhs) {
164 return lhs.raw() == rhs.raw();
165 }
166
operator !=(const SourcePosition& lhs, const SourcePosition& rhs)167 inline bool operator!=(const SourcePosition& lhs, const SourcePosition& rhs) {
168 return !(lhs == rhs);
169 }
170
171 struct InliningPosition {
172 // position of the inlined call
173 SourcePosition position = SourcePosition::Unknown();
174
175 // references position in DeoptimizationData::literals()
176 int inlined_function_id;
177 };
178
179 struct SourcePositionInfo {
180 SourcePositionInfo(SourcePosition pos, Handle<SharedFunctionInfo> f);
181
182 SourcePosition position;
183 Handle<SharedFunctionInfo> shared;
184 Handle<Script> script;
185 int line = -1;
186 int column = -1;
187 };
188
189 std::ostream& operator<<(std::ostream& out, const SourcePosition& pos);
190
191 std::ostream& operator<<(std::ostream& out, const SourcePositionInfo& pos);
192 std::ostream& operator<<(std::ostream& out,
193 const std::vector<SourcePositionInfo>& stack);
194
195 } // namespace internal
196 } // namespace v8
197
198 #endif // V8_CODEGEN_SOURCE_POSITION_H_
199