// 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/codegen/source-position.h" #include "src/codegen/optimized-compilation-info.h" #include "src/objects/objects-inl.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:"; } if (pos.IsExternal()) { out << pos.ExternalLine() << ", " << pos.ExternalFileId() << ">"; } else { 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(); DeoptimizationData deopt_data = DeoptimizationData::cast(code->deoptimization_data()); 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; } SourcePositionInfo SourcePosition::FirstInfo(Handle<Code> code) const { DisallowGarbageCollection no_gc; Isolate* isolate = code->GetIsolate(); DeoptimizationData deopt_data = DeoptimizationData::cast(code->deoptimization_data()); SourcePosition pos = *this; if (pos.isInlined()) { InliningPosition inl = deopt_data.InliningPositions().get(pos.InliningId()); Handle<SharedFunctionInfo> function( deopt_data.GetInlinedFunction(inl.inlined_function_id), isolate); return SourcePositionInfo(pos, function); } Handle<SharedFunctionInfo> function( SharedFunctionInfo::cast(deopt_data.SharedFunctionInfo()), isolate); return SourcePositionInfo(pos, function); } void SourcePosition::Print(std::ostream& out, SharedFunctionInfo function) const { Script::PositionInfo pos; Object source_name; 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.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 { if (IsExternal()) { out << "{ \"line\" : " << ExternalLine() << ", " << " \"fileId\" : " << ExternalFileId() << ", " << " \"inliningId\" : " << InliningId() << "}"; } else { 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), shared(f), 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