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#include "src/codegen/source-position.h"
6#include "src/codegen/optimized-compilation-info.h"
7#include "src/objects/objects-inl.h"
8
9namespace v8 {
10namespace internal {
11
12std::ostream& operator<<(std::ostream& out, const SourcePositionInfo& pos) {
13  out << "<";
14  if (!pos.script.is_null() && pos.script->name().IsString()) {
15    out << String::cast(pos.script->name()).ToCString(DISALLOW_NULLS).get();
16  } else {
17    out << "unknown";
18  }
19  out << ":" << pos.line + 1 << ":" << pos.column + 1 << ">";
20  return out;
21}
22
23std::ostream& operator<<(std::ostream& out,
24                         const std::vector<SourcePositionInfo>& stack) {
25  bool first = true;
26  for (const SourcePositionInfo& pos : stack) {
27    if (!first) out << " inlined at ";
28    out << pos;
29    first = false;
30  }
31  return out;
32}
33
34std::ostream& operator<<(std::ostream& out, const SourcePosition& pos) {
35  if (pos.isInlined()) {
36    out << "<inlined(" << pos.InliningId() << "):";
37  } else {
38    out << "<not inlined:";
39  }
40
41  if (pos.IsExternal()) {
42    out << pos.ExternalLine() << ", " << pos.ExternalFileId() << ">";
43  } else {
44    out << pos.ScriptOffset() << ">";
45  }
46  return out;
47}
48
49std::vector<SourcePositionInfo> SourcePosition::InliningStack(
50    OptimizedCompilationInfo* cinfo) const {
51  SourcePosition pos = *this;
52  std::vector<SourcePositionInfo> stack;
53  while (pos.isInlined()) {
54    const auto& inl = cinfo->inlined_functions()[pos.InliningId()];
55    stack.push_back(SourcePositionInfo(pos, inl.shared_info));
56    pos = inl.position.position;
57  }
58  stack.push_back(SourcePositionInfo(pos, cinfo->shared_info()));
59  return stack;
60}
61
62std::vector<SourcePositionInfo> SourcePosition::InliningStack(
63    Handle<Code> code) const {
64  Isolate* isolate = code->GetIsolate();
65  DeoptimizationData deopt_data =
66      DeoptimizationData::cast(code->deoptimization_data());
67  SourcePosition pos = *this;
68  std::vector<SourcePositionInfo> stack;
69  while (pos.isInlined()) {
70    InliningPosition inl = deopt_data.InliningPositions().get(pos.InliningId());
71    Handle<SharedFunctionInfo> function(
72        deopt_data.GetInlinedFunction(inl.inlined_function_id), isolate);
73    stack.push_back(SourcePositionInfo(pos, function));
74    pos = inl.position;
75  }
76  Handle<SharedFunctionInfo> function(
77      SharedFunctionInfo::cast(deopt_data.SharedFunctionInfo()), isolate);
78  stack.push_back(SourcePositionInfo(pos, function));
79  return stack;
80}
81
82SourcePositionInfo SourcePosition::FirstInfo(Handle<Code> code) const {
83  DisallowGarbageCollection no_gc;
84  Isolate* isolate = code->GetIsolate();
85  DeoptimizationData deopt_data =
86      DeoptimizationData::cast(code->deoptimization_data());
87  SourcePosition pos = *this;
88  if (pos.isInlined()) {
89    InliningPosition inl = deopt_data.InliningPositions().get(pos.InliningId());
90    Handle<SharedFunctionInfo> function(
91        deopt_data.GetInlinedFunction(inl.inlined_function_id), isolate);
92    return SourcePositionInfo(pos, function);
93  }
94  Handle<SharedFunctionInfo> function(
95      SharedFunctionInfo::cast(deopt_data.SharedFunctionInfo()), isolate);
96  return SourcePositionInfo(pos, function);
97}
98
99void SourcePosition::Print(std::ostream& out,
100                           SharedFunctionInfo function) const {
101  Script::PositionInfo pos;
102  Object source_name;
103  if (function.script().IsScript()) {
104    Script script = Script::cast(function.script());
105    source_name = script.name();
106    script.GetPositionInfo(ScriptOffset(), &pos, Script::WITH_OFFSET);
107  }
108  out << "<";
109  if (source_name.IsString()) {
110    out << String::cast(source_name)
111               .ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL)
112               .get();
113  } else {
114    out << "unknown";
115  }
116  out << ":" << pos.line + 1 << ":" << pos.column + 1 << ">";
117}
118
119void SourcePosition::PrintJson(std::ostream& out) const {
120  if (IsExternal()) {
121    out << "{ \"line\" : " << ExternalLine() << ", "
122        << "  \"fileId\" : " << ExternalFileId() << ", "
123        << "  \"inliningId\" : " << InliningId() << "}";
124  } else {
125    out << "{ \"scriptOffset\" : " << ScriptOffset() << ", "
126        << "  \"inliningId\" : " << InliningId() << "}";
127  }
128}
129
130void SourcePosition::Print(std::ostream& out, Code code) const {
131  DeoptimizationData deopt_data =
132      DeoptimizationData::cast(code.deoptimization_data());
133  if (!isInlined()) {
134    SharedFunctionInfo function(
135        SharedFunctionInfo::cast(deopt_data.SharedFunctionInfo()));
136    Print(out, function);
137  } else {
138    InliningPosition inl = deopt_data.InliningPositions().get(InliningId());
139    if (inl.inlined_function_id == -1) {
140      out << *this;
141    } else {
142      SharedFunctionInfo function =
143          deopt_data.GetInlinedFunction(inl.inlined_function_id);
144      Print(out, function);
145    }
146    out << " inlined at ";
147    inl.position.Print(out, code);
148  }
149}
150
151SourcePositionInfo::SourcePositionInfo(SourcePosition pos,
152                                       Handle<SharedFunctionInfo> f)
153    : position(pos),
154      shared(f),
155      script(f.is_null() || !f->script().IsScript()
156                 ? Handle<Script>::null()
157                 : handle(Script::cast(f->script()), f->GetIsolate())) {
158  if (!script.is_null()) {
159    Script::PositionInfo info;
160    if (Script::GetPositionInfo(script, pos.ScriptOffset(), &info,
161                                Script::WITH_OFFSET)) {
162      line = info.line;
163      column = info.column;
164    }
165  }
166}
167
168}  // namespace internal
169}  // namespace v8
170