LCOV - code coverage report
Current view: top level - src/inspector - v8-stack-trace-impl.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 112 127 88.2 %
Date: 2017-04-26 Functions: 23 34 67.6 %

          Line data    Source code
       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/inspector/v8-stack-trace-impl.h"
       6             : 
       7             : #include <algorithm>
       8             : 
       9             : #include "src/inspector/v8-debugger.h"
      10             : #include "src/inspector/wasm-translation.h"
      11             : 
      12             : namespace v8_inspector {
      13             : 
      14             : namespace {
      15             : 
      16             : static const v8::StackTrace::StackTraceOptions stackTraceOptions =
      17             :     static_cast<v8::StackTrace::StackTraceOptions>(
      18             :         v8::StackTrace::kDetailed |
      19             :         v8::StackTrace::kExposeFramesAcrossSecurityOrigins);
      20             : 
      21       52253 : std::vector<std::shared_ptr<StackFrame>> toFramesVector(
      22             :     V8Debugger* debugger, v8::Local<v8::StackTrace> v8StackTrace,
      23             :     int maxStackSize) {
      24             :   DCHECK(debugger->isolate()->InContext());
      25      104506 :   int frameCount = std::min(v8StackTrace->GetFrameCount(), maxStackSize);
      26             :   std::vector<std::shared_ptr<StackFrame>> frames;
      27       98782 :   for (int i = 0; i < frameCount; ++i) {
      28       93058 :     frames.push_back(debugger->symbolize(v8StackTrace->GetFrame(i)));
      29             :   }
      30       52253 :   return frames;
      31             : }
      32             : 
      33      100404 : void calculateAsyncChain(V8Debugger* debugger, int contextGroupId,
      34             :                          std::shared_ptr<AsyncStackTrace>* asyncParent,
      35             :                          std::shared_ptr<AsyncStackTrace>* asyncCreation,
      36             :                          int* maxAsyncDepth) {
      37      112512 :   *asyncParent = debugger->currentAsyncParent();
      38      112512 :   *asyncCreation = debugger->currentAsyncCreation();
      39      100404 :   if (maxAsyncDepth) *maxAsyncDepth = debugger->maxAsyncCallChainDepth();
      40             : 
      41             :   DCHECK(!*asyncParent || !*asyncCreation ||
      42             :          (*asyncParent)->contextGroupId() ==
      43             :              (*asyncCreation)->contextGroupId());
      44             :   // Do not accidentally append async call chain from another group. This should
      45             :   // not happen if we have proper instrumentation, but let's double-check to be
      46             :   // safe.
      47      120936 :   if (contextGroupId && *asyncParent &&
      48             :       (*asyncParent)->contextGroupId() != contextGroupId) {
      49             :     asyncParent->reset();
      50        6840 :     asyncCreation->reset();
      51           0 :     if (maxAsyncDepth) *maxAsyncDepth = 0;
      52       56256 :     return;
      53             :   }
      54             : 
      55             :   // Only the top stack in the chain may be empty and doesn't contain creation
      56             :   // stack, so ensure that second stack is non-empty (it's the top of appended
      57             :   // chain).
      58       74124 :   if (*asyncParent && !(*asyncCreation) && !(*asyncParent)->creation().lock() &&
      59             :       (*asyncParent)->isEmpty()) {
      60         396 :     *asyncParent = (*asyncParent)->parent().lock();
      61             :   }
      62             : }
      63             : 
      64       42537 : std::unique_ptr<protocol::Runtime::StackTrace> buildInspectorObjectCommon(
      65       84828 :     const std::vector<std::shared_ptr<StackFrame>>& frames,
      66             :     const std::shared_ptr<AsyncStackTrace>& asyncParent,
      67             :     const std::shared_ptr<AsyncStackTrace>& asyncCreation, int maxAsyncDepth) {
      68             :   std::unique_ptr<protocol::Array<protocol::Runtime::CallFrame>>
      69             :       inspectorFrames = protocol::Array<protocol::Runtime::CallFrame>::create();
      70      169656 :   for (size_t i = 0; i < frames.size(); i++) {
      71       84582 :     inspectorFrames->addItem(frames[i]->buildInspectorObject());
      72             :   }
      73             :   std::unique_ptr<protocol::Runtime::StackTrace> stackTrace =
      74             :       protocol::Runtime::StackTrace::create()
      75       42537 :           .setCallFrames(std::move(inspectorFrames))
      76             :           .build();
      77       42537 :   if (asyncParent && maxAsyncDepth > 0) {
      78             :     stackTrace->setParent(asyncParent->buildInspectorObject(asyncCreation.get(),
      79        3912 :                                                             maxAsyncDepth - 1));
      80             :   }
      81       42537 :   return stackTrace;
      82             : }
      83             : 
      84             : }  //  namespace
      85             : 
      86       45131 : StackFrame::StackFrame(v8::Local<v8::StackFrame> v8Frame)
      87             :     : m_functionName(toProtocolString(v8Frame->GetFunctionName())),
      88             :       m_scriptId(String16::fromInteger(v8Frame->GetScriptId())),
      89             :       m_sourceURL(toProtocolString(v8Frame->GetScriptNameOrSourceURL())),
      90       45131 :       m_lineNumber(v8Frame->GetLineNumber() - 1),
      91       90262 :       m_columnNumber(v8Frame->GetColumn() - 1) {
      92             :   DCHECK(m_lineNumber + 1 != v8::Message::kNoLineNumberInfo);
      93             :   DCHECK(m_columnNumber + 1 != v8::Message::kNoColumnInfo);
      94       45131 : }
      95             : 
      96         186 : void StackFrame::translate(WasmTranslation* wasmTranslation) {
      97             :   wasmTranslation->TranslateWasmScriptLocationToProtocolLocation(
      98         186 :       &m_scriptId, &m_lineNumber, &m_columnNumber);
      99         186 : }
     100             : 
     101           0 : const String16& StackFrame::functionName() const { return m_functionName; }
     102             : 
     103           0 : const String16& StackFrame::scriptId() const { return m_scriptId; }
     104             : 
     105           0 : const String16& StackFrame::sourceURL() const { return m_sourceURL; }
     106             : 
     107        7334 : int StackFrame::lineNumber() const { return m_lineNumber; }
     108             : 
     109        7322 : int StackFrame::columnNumber() const { return m_columnNumber; }
     110             : 
     111       43923 : std::unique_ptr<protocol::Runtime::CallFrame> StackFrame::buildInspectorObject()
     112             :     const {
     113             :   return protocol::Runtime::CallFrame::create()
     114       43923 :       .setFunctionName(m_functionName)
     115             :       .setScriptId(m_scriptId)
     116             :       .setUrl(m_sourceURL)
     117       43923 :       .setLineNumber(m_lineNumber)
     118       43923 :       .setColumnNumber(m_columnNumber)
     119       43923 :       .build();
     120             : }
     121             : 
     122             : // static
     123         768 : void V8StackTraceImpl::setCaptureStackTraceForUncaughtExceptions(
     124             :     v8::Isolate* isolate, bool capture) {
     125             :   isolate->SetCaptureStackTraceForUncaughtExceptions(
     126         768 :       capture, V8StackTraceImpl::maxCallStackSizeToCapture);
     127         768 : }
     128             : 
     129             : // static
     130       44148 : std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::create(
     131       44148 :     V8Debugger* debugger, int contextGroupId,
     132             :     v8::Local<v8::StackTrace> v8StackTrace, int maxStackSize) {
     133             :   DCHECK(debugger);
     134             : 
     135             :   v8::Isolate* isolate = debugger->isolate();
     136       44148 :   v8::HandleScope scope(isolate);
     137             : 
     138       44148 :   std::vector<std::shared_ptr<StackFrame>> frames;
     139       44148 :   if (!v8StackTrace.IsEmpty() && v8StackTrace->GetFrameCount()) {
     140       80290 :     frames = toFramesVector(debugger, v8StackTrace, maxStackSize);
     141             :   }
     142             : 
     143       44148 :   int maxAsyncDepth = 0;
     144       44148 :   std::shared_ptr<AsyncStackTrace> asyncParent;
     145       44148 :   std::shared_ptr<AsyncStackTrace> asyncCreation;
     146             :   calculateAsyncChain(debugger, contextGroupId, &asyncParent, &asyncCreation,
     147       44148 :                       &maxAsyncDepth);
     148       44148 :   if (frames.empty() && !asyncCreation && !asyncParent) return nullptr;
     149             :   return std::unique_ptr<V8StackTraceImpl>(new V8StackTraceImpl(
     150      165087 :       std::move(frames), maxAsyncDepth, asyncParent, asyncCreation));
     151             : }
     152             : 
     153             : // static
     154       44028 : std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::capture(
     155       44028 :     V8Debugger* debugger, int contextGroupId, int maxStackSize) {
     156             :   DCHECK(debugger);
     157             :   v8::Isolate* isolate = debugger->isolate();
     158       44028 :   v8::HandleScope handleScope(isolate);
     159             :   v8::Local<v8::StackTrace> v8StackTrace;
     160       44028 :   if (isolate->InContext()) {
     161             :     v8StackTrace = v8::StackTrace::CurrentStackTrace(isolate, maxStackSize,
     162       43508 :                                                      stackTraceOptions);
     163             :   }
     164             :   return V8StackTraceImpl::create(debugger, contextGroupId, v8StackTrace,
     165       44028 :                                   maxStackSize);
     166             : }
     167             : 
     168       40313 : V8StackTraceImpl::V8StackTraceImpl(
     169             :     std::vector<std::shared_ptr<StackFrame>> frames, int maxAsyncDepth,
     170             :     std::shared_ptr<AsyncStackTrace> asyncParent,
     171             :     std::shared_ptr<AsyncStackTrace> asyncCreation)
     172             :     : m_frames(std::move(frames)),
     173             :       m_maxAsyncDepth(maxAsyncDepth),
     174             :       m_asyncParent(asyncParent),
     175      120939 :       m_asyncCreation(asyncCreation) {}
     176             : 
     177      161252 : V8StackTraceImpl::~V8StackTraceImpl() {}
     178             : 
     179           0 : std::unique_ptr<V8StackTrace> V8StackTraceImpl::clone() {
     180             :   return std::unique_ptr<V8StackTrace>(
     181             :       new V8StackTraceImpl(m_frames, 0, std::shared_ptr<AsyncStackTrace>(),
     182           0 :                            std::shared_ptr<AsyncStackTrace>()));
     183             : }
     184             : 
     185       80442 : bool V8StackTraceImpl::isEmpty() const { return m_frames.empty(); }
     186             : 
     187        7254 : StringView V8StackTraceImpl::topSourceURL() const {
     188        7254 :   return toStringView(m_frames[0]->sourceURL());
     189             : }
     190             : 
     191        7304 : int V8StackTraceImpl::topLineNumber() const {
     192       14608 :   return m_frames[0]->lineNumber() + 1;
     193             : }
     194             : 
     195        7292 : int V8StackTraceImpl::topColumnNumber() const {
     196       14584 :   return m_frames[0]->columnNumber() + 1;
     197             : }
     198             : 
     199          50 : StringView V8StackTraceImpl::topScriptId() const {
     200          50 :   return toStringView(m_frames[0]->scriptId());
     201             : }
     202             : 
     203           0 : StringView V8StackTraceImpl::topFunctionName() const {
     204           0 :   return toStringView(m_frames[0]->functionName());
     205             : }
     206             : 
     207             : std::unique_ptr<protocol::Runtime::StackTrace>
     208       40203 : V8StackTraceImpl::buildInspectorObjectImpl() const {
     209             :   return buildInspectorObjectCommon(m_frames, m_asyncParent.lock(),
     210      120609 :                                     m_asyncCreation.lock(), m_maxAsyncDepth);
     211             : }
     212             : 
     213             : std::unique_ptr<protocol::Runtime::API::StackTrace>
     214           0 : V8StackTraceImpl::buildInspectorObject() const {
     215           0 :   return buildInspectorObjectImpl();
     216             : }
     217             : 
     218          12 : std::unique_ptr<StringBuffer> V8StackTraceImpl::toString() const {
     219          12 :   String16Builder stackTrace;
     220          84 :   for (size_t i = 0; i < m_frames.size(); ++i) {
     221          72 :     const StackFrame& frame = *m_frames[i];
     222         102 :     stackTrace.append("\n    at " + (frame.functionName().length()
     223             :                                          ? frame.functionName()
     224          30 :                                          : "(anonymous function)"));
     225          60 :     stackTrace.append(" (");
     226          30 :     stackTrace.append(frame.sourceURL());
     227          30 :     stackTrace.append(':');
     228          60 :     stackTrace.append(String16::fromInteger(frame.lineNumber() + 1));
     229          30 :     stackTrace.append(':');
     230          60 :     stackTrace.append(String16::fromInteger(frame.columnNumber() + 1));
     231          30 :     stackTrace.append(')');
     232             :   }
     233          12 :   String16 string = stackTrace.toString();
     234          36 :   return StringBufferImpl::adopt(string);
     235             : }
     236             : 
     237             : // static
     238       12108 : std::shared_ptr<AsyncStackTrace> AsyncStackTrace::capture(
     239       12108 :     V8Debugger* debugger, int contextGroupId, const String16& description,
     240             :     int maxStackSize) {
     241             :   DCHECK(debugger);
     242             : 
     243             :   v8::Isolate* isolate = debugger->isolate();
     244       12108 :   v8::HandleScope handleScope(isolate);
     245             : 
     246       12108 :   std::vector<std::shared_ptr<StackFrame>> frames;
     247       12108 :   if (isolate->InContext()) {
     248             :     v8::Local<v8::StackTrace> v8StackTrace = v8::StackTrace::CurrentStackTrace(
     249       12108 :         isolate, maxStackSize, stackTraceOptions);
     250       24216 :     frames = toFramesVector(debugger, v8StackTrace, maxStackSize);
     251             :   }
     252             : 
     253       12108 :   std::shared_ptr<AsyncStackTrace> asyncParent;
     254       12108 :   std::shared_ptr<AsyncStackTrace> asyncCreation;
     255             :   calculateAsyncChain(debugger, contextGroupId, &asyncParent, &asyncCreation,
     256       12108 :                       nullptr);
     257             : 
     258       12108 :   if (frames.empty() && !asyncCreation && !asyncParent) return nullptr;
     259             : 
     260             :   // When async call chain is empty but doesn't contain useful schedule stack
     261             :   // and parent async call chain contains creationg stack but doesn't
     262             :   // synchronous we can merge them together.
     263             :   // e.g. Promise ThenableJob.
     264       32010 :   if (asyncParent && frames.empty() &&
     265       14286 :       asyncParent->m_description == description && !asyncCreation) {
     266             :     return asyncParent;
     267             :   }
     268             : 
     269             :   DCHECK(contextGroupId || asyncParent);
     270        8574 :   if (!contextGroupId && asyncParent) {
     271           0 :     contextGroupId = asyncParent->m_contextGroupId;
     272             :   }
     273             :   return std::shared_ptr<AsyncStackTrace>(
     274             :       new AsyncStackTrace(contextGroupId, description, std::move(frames),
     275       37830 :                           asyncParent, asyncCreation));
     276             : }
     277             : 
     278        8574 : AsyncStackTrace::AsyncStackTrace(
     279             :     int contextGroupId, const String16& description,
     280             :     std::vector<std::shared_ptr<StackFrame>> frames,
     281             :     std::shared_ptr<AsyncStackTrace> asyncParent,
     282             :     std::shared_ptr<AsyncStackTrace> asyncCreation)
     283             :     : m_contextGroupId(contextGroupId),
     284             :       m_description(description),
     285             :       m_frames(std::move(frames)),
     286             :       m_asyncParent(asyncParent),
     287        8574 :       m_asyncCreation(asyncCreation) {
     288             :   DCHECK(m_contextGroupId);
     289        8574 : }
     290             : 
     291             : std::unique_ptr<protocol::Runtime::StackTrace>
     292        2334 : AsyncStackTrace::buildInspectorObject(AsyncStackTrace* asyncCreation,
     293             :                                       int maxAsyncDepth) const {
     294             :   std::unique_ptr<protocol::Runtime::StackTrace> stackTrace =
     295             :       buildInspectorObjectCommon(m_frames, m_asyncParent.lock(),
     296        7002 :                                  m_asyncCreation.lock(), maxAsyncDepth);
     297        4668 :   if (!m_description.isEmpty()) stackTrace->setDescription(m_description);
     298        3966 :   if (asyncCreation && !asyncCreation->isEmpty()) {
     299             :     stackTrace->setPromiseCreationFrame(
     300        3264 :         asyncCreation->m_frames[0]->buildInspectorObject());
     301             :   }
     302        2334 :   return stackTrace;
     303             : }
     304             : 
     305        6840 : int AsyncStackTrace::contextGroupId() const { return m_contextGroupId; }
     306             : 
     307           0 : std::weak_ptr<AsyncStackTrace> AsyncStackTrace::parent() const {
     308           0 :   return m_asyncParent;
     309             : }
     310             : 
     311           0 : std::weak_ptr<AsyncStackTrace> AsyncStackTrace::creation() const {
     312           0 :   return m_asyncCreation;
     313             : }
     314             : 
     315        8220 : bool AsyncStackTrace::isEmpty() const { return m_frames.empty(); }
     316             : 
     317             : }  // namespace v8_inspector

Generated by: LCOV version 1.10