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