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
15namespace v8 {
16namespace internal {
17
18class Code;
19class OptimizedCompilationInfo;
20class Script;
21class SharedFunctionInfo;
22struct 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.
45class 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
162inline bool operator==(const SourcePosition& lhs, const SourcePosition& rhs) {
163 return lhs.raw() == rhs.raw();
164}
165
166inline bool operator!=(const SourcePosition& lhs, const SourcePosition& rhs) {
167 return !(lhs == rhs);
168}
169
170struct 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
178struct 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
188std::ostream& operator<<(std::ostream& out, const SourcePosition& pos);
189
190std::ostream& operator<<(std::ostream& out, const SourcePositionInfo& pos);
191std::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