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 <ostream>
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:
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()61   bool IsKnown() const {
62     if (IsExternal()) return true;
63     return ScriptOffset() != kNoSourcePosition || InliningId() != kNotInlined;
64   }
isInlined()65   bool isInlined() const {
66     if (IsExternal()) return false;
67     return InliningId() != kNotInlined;
68   }
69 
IsExternal()70   bool IsExternal() const { return IsExternalField::decode(value_); }
IsJavaScript()71   bool IsJavaScript() const { return !IsExternal(); }
72 
ExternalLine()73   int ExternalLine() const {
74     DCHECK(IsExternal());
75     return ExternalLineField::decode(value_);
76   }
77 
ExternalFileId()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 
ScriptOffset()91   int ScriptOffset() const {
92     DCHECK(IsJavaScript());
93     return ScriptOffsetField::decode(value_) - 1;
94   }
InliningId()95   int InliningId() const { return InliningIdField::decode(value_) - 1; }
96 
SetIsExternal(bool external)97   void SetIsExternal(bool external) {
98     value_ = IsExternalField::update(value_, external);
99   }
SetExternalLine(int line)100   void SetExternalLine(int line) {
101     DCHECK(IsExternal());
102     DCHECK(line <= ExternalLineField::kMax - 1);
103     value_ = ExternalLineField::update(value_, line);
104   }
SetExternalFileId(int file_id)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 
SetScriptOffset(int script_offset)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   }
SetInliningId(int inlining_id)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 
raw()126   int64_t raw() const { return static_cast<int64_t>(value_); }
FromRaw(int64_t raw)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).
SourcePosition(int line,int file_id,int inlining_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   using IsExternalField = base::BitField64<bool, 0, 1>;
146 
147   // The two below are only used if IsExternal() is true.
148   using ExternalLineField = base::BitField64<int, 1, 20>;
149   using ExternalFileIdField = base::BitField64<int, 21, 10>;
150 
151   // ScriptOffsetField is only used if IsExternal() is false.
152   using ScriptOffsetField = base::BitField64<int, 1, 30>;
153 
154   // InliningId is in the high bits for better compression in
155   // SourcePositionTable.
156   using InliningIdField = base::BitField64<int, 31, 16>;
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_CODEGEN_SOURCE_POSITION_H_
198