text: // Copyright 2016 the V8 project authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "src/source-position.h"
  #include "src/objects-inl.h"
  #include "src/optimized-compilation-info.h"
  
  namespace v8 {
  namespace internal {
  
  std::ostream& operator<<(std::ostream& out, const SourcePositionInfo& pos) {
    out << "<";
    if (!pos.script.is_null() && pos.script->name()->IsString()) {
      out << String::cast(pos.script->name())->ToCString(DISALLOW_NULLS).get();
    } else {
      out << "unknown";
    }
    out << ":" << pos.line + 1 << ":" << pos.column + 1 << ">";
    return out;
  }
  
  std::ostream& operator<<(std::ostream& out,
                           const std::vector<SourcePositionInfo>& stack) {
    bool first = true;
    for (const SourcePositionInfo& pos : stack) {
      if (!first) out << " inlined at ";
      out << pos;
      first = false;
    }
    return out;
  }
  
  std::ostream& operator<<(std::ostream& out, const SourcePosition& pos) {
    if (pos.isInlined()) {
      out << "<inlined(" << pos.InliningId() << "):";
    } else {
      out << "<not inlined:";
    }
    out << pos.ScriptOffset() << ">";
    return out;
  }
  
  std::vector<SourcePositionInfo> SourcePosition::InliningStack(
      OptimizedCompilationInfo* cinfo) const {
    SourcePosition pos = *this;
    std::vector<SourcePositionInfo> stack;
    while (pos.isInlined()) {
      const auto& inl = cinfo->inlined_functions()[pos.InliningId()];
      stack.push_back(SourcePositionInfo(pos, inl.shared_info));
      pos = inl.position.position;
    }
    stack.push_back(SourcePositionInfo(pos, cinfo->shared_info()));
    return stack;
  }
  
  std::vector<SourcePositionInfo> SourcePosition::InliningStack(
      Handle<Code> code) const {
    Isolate* isolate = code->GetIsolate();
    Handle<DeoptimizationData> deopt_data(
        DeoptimizationData::cast(code->deoptimization_data()), isolate);
    SourcePosition pos = *this;
    std::vector<SourcePositionInfo> stack;
    while (pos.isInlined()) {
      InliningPosition inl =
          deopt_data->InliningPositions()->get(pos.InliningId());
      Handle<SharedFunctionInfo> function(
          deopt_data->GetInlinedFunction(inl.inlined_function_id), isolate);
      stack.push_back(SourcePositionInfo(pos, function));
      pos = inl.position;
    }
    Handle<SharedFunctionInfo> function(
        SharedFunctionInfo::cast(deopt_data->SharedFunctionInfo()), isolate);
    stack.push_back(SourcePositionInfo(pos, function));
    return stack;
  }
  
  void SourcePosition::Print(std::ostream& out,
                             SharedFunctionInfo* function) const {
    Script::PositionInfo pos;
    Object* source_name = nullptr;
    if (function->script()->IsScript()) {
      Script* script = Script::cast(function->script());
      source_name = script->name();
      script->GetPositionInfo(ScriptOffset(), &pos, Script::WITH_OFFSET);
    }
    out << "<";
    if (source_name != nullptr && source_name->IsString()) {
      out << String::cast(source_name)
                 ->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL)
                 .get();
    } else {
      out << "unknown";
    }
    out << ":" << pos.line + 1 << ":" << pos.column + 1 << ">";
  }
  
  void SourcePosition::PrintJson(std::ostream& out) const {
    out << "{ \"scriptOffset\" : " << ScriptOffset() << ", "
        << "  \"inliningId\" : " << InliningId() << "}";
  }
  
  void SourcePosition::Print(std::ostream& out, Code* code) const {
    DeoptimizationData* deopt_data =
        DeoptimizationData::cast(code->deoptimization_data());
    if (!isInlined()) {
      SharedFunctionInfo* function(
          SharedFunctionInfo::cast(deopt_data->SharedFunctionInfo()));
      Print(out, function);
    } else {
      InliningPosition inl = deopt_data->InliningPositions()->get(InliningId());
      if (inl.inlined_function_id == -1) {
        out << *this;
      } else {
        SharedFunctionInfo* function =
            deopt_data->GetInlinedFunction(inl.inlined_function_id);
        Print(out, function);
      }
      out << " inlined at ";
      inl.position.Print(out, code);
    }
  }
  
  SourcePositionInfo::SourcePositionInfo(SourcePosition pos,
                                         Handle<SharedFunctionInfo> f)
      : position(pos),
        script(f.is_null() || !f->script()->IsScript()
                   ? Handle<Script>::null()
                   : handle(Script::cast(f->script()), f->GetIsolate())) {
    if (!script.is_null()) {
      Script::PositionInfo info;
      if (Script::GetPositionInfo(script, pos.ScriptOffset(), &info,
                                  Script::WITH_OFFSET)) {
        line = info.line;
        column = info.column;
      }
    }
  }
  
  }  // namespace internal
  }  // namespace v8
  