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
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  SourcePositionInfo FirstInfo(Handle<Code> code) const;
88
89  void Print(std::ostream& out, Code code) const;
90  void PrintJson(std::ostream& out) const;
91
92  int ScriptOffset() const {
93    DCHECK(IsJavaScript());
94    return ScriptOffsetField::decode(value_) - 1;
95  }
96  int InliningId() const { return InliningIdField::decode(value_) - 1; }
97
98  void SetIsExternal(bool external) {
99    value_ = IsExternalField::update(value_, external);
100  }
101  void SetExternalLine(int line) {
102    DCHECK(IsExternal());
103    DCHECK(line <= ExternalLineField::kMax - 1);
104    value_ = ExternalLineField::update(value_, line);
105  }
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
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  }
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
127  int64_t raw() const { return static_cast<int64_t>(value_); }
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).
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
163inline bool operator==(const SourcePosition& lhs, const SourcePosition& rhs) {
164  return lhs.raw() == rhs.raw();
165}
166
167inline bool operator!=(const SourcePosition& lhs, const SourcePosition& rhs) {
168  return !(lhs == rhs);
169}
170
171struct 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
179struct 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
189std::ostream& operator<<(std::ostream& out, const SourcePosition& pos);
190
191std::ostream& operator<<(std::ostream& out, const SourcePositionInfo& pos);
192std::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