LCOV - code coverage report
Current view: top level - src/inspector - v8-debugger-script.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 200 221 90.5 %
Date: 2019-01-20 Functions: 45 55 81.8 %

          Line data    Source code
       1             : // Copyright 2014 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-debugger-script.h"
       6             : 
       7             : #include "src/inspector/inspected-context.h"
       8             : #include "src/inspector/string-util.h"
       9             : #include "src/inspector/v8-inspector-impl.h"
      10             : #include "src/inspector/wasm-translation.h"
      11             : #include "src/v8memory.h"
      12             : 
      13             : namespace v8_inspector {
      14             : 
      15             : namespace {
      16             : 
      17             : const char kGlobalDebuggerScriptHandleLabel[] = "DevTools debugger";
      18             : 
      19             : // Hash algorithm for substrings is described in "Über die Komplexität der
      20             : // Multiplikation in
      21             : // eingeschränkten Branchingprogrammmodellen" by Woelfe.
      22             : // http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECTION00832000000000000000
      23       60326 : String16 calculateHash(v8::Isolate* isolate, v8::Local<v8::String> source) {
      24             :   static uint64_t prime[] = {0x3FB75161, 0xAB1F4E4F, 0x82675BC5, 0xCD924D35,
      25             :                              0x81ABE279};
      26             :   static uint64_t random[] = {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476,
      27             :                               0xC3D2E1F0};
      28             :   static uint32_t randomOdd[] = {0xB4663807, 0xCC322BF5, 0xD4F91BBD, 0xA7BEA11D,
      29             :                                  0x8F462907};
      30             : 
      31       60326 :   uint64_t hashes[] = {0, 0, 0, 0, 0};
      32       60326 :   uint64_t zi[] = {1, 1, 1, 1, 1};
      33             : 
      34             :   const size_t hashesSize = arraysize(hashes);
      35             : 
      36             :   size_t current = 0;
      37             : 
      38       60326 :   std::unique_ptr<UChar[]> buffer(new UChar[source->Length()]);
      39             :   int written = source->Write(
      40       60326 :       isolate, reinterpret_cast<uint16_t*>(buffer.get()), 0, source->Length());
      41             : 
      42             :   const uint32_t* data = nullptr;
      43       60326 :   size_t sizeInBytes = sizeof(UChar) * written;
      44             :   data = reinterpret_cast<const uint32_t*>(buffer.get());
      45   138776248 :   for (size_t i = 0; i < sizeInBytes / 4; ++i) {
      46             :     uint32_t d = v8::internal::ReadUnalignedUInt32(
      47   138715922 :         reinterpret_cast<v8::internal::Address>(data + i));
      48             : #if V8_TARGET_LITTLE_ENDIAN
      49             :     uint32_t v = d;
      50             : #else
      51             :     uint32_t v = (d << 16) | (d >> 16);
      52             : #endif
      53   138715922 :     uint64_t xi = v * randomOdd[current] & 0x7FFFFFFF;
      54   138715922 :     hashes[current] = (hashes[current] + zi[current] * xi) % prime[current];
      55   138715922 :     zi[current] = (zi[current] * random[current]) % prime[current];
      56   138715922 :     current = current == hashesSize - 1 ? 0 : current + 1;
      57             :   }
      58       60326 :   if (sizeInBytes % 4) {
      59             :     uint32_t v = 0;
      60             :     const uint8_t* data_8b = reinterpret_cast<const uint8_t*>(data);
      61       95640 :     for (size_t i = sizeInBytes - sizeInBytes % 4; i < sizeInBytes; ++i) {
      62       63760 :       v <<= 8;
      63             : #if V8_TARGET_LITTLE_ENDIAN
      64       63760 :       v |= data_8b[i];
      65             : #else
      66             :       if (i % 2) {
      67             :         v |= data_8b[i - 1];
      68             :       } else {
      69             :         v |= data_8b[i + 1];
      70             :       }
      71             : #endif
      72             :     }
      73       31880 :     uint64_t xi = v * randomOdd[current] & 0x7FFFFFFF;
      74       31880 :     hashes[current] = (hashes[current] + zi[current] * xi) % prime[current];
      75       31880 :     zi[current] = (zi[current] * random[current]) % prime[current];
      76             :     current = current == hashesSize - 1 ? 0 : current + 1;
      77             :   }
      78             : 
      79      301630 :   for (size_t i = 0; i < hashesSize; ++i)
      80      301630 :     hashes[i] = (hashes[i] + zi[i] * (prime[i] - 1)) % prime[i];
      81             : 
      82       60326 :   String16Builder hash;
      83      361956 :   for (size_t i = 0; i < hashesSize; ++i)
      84      301630 :     hash.appendUnsignedAsHex(static_cast<uint32_t>(hashes[i]));
      85      120652 :   return hash.toString();
      86             : }
      87             : 
      88         145 : void TranslateProtocolLocationToV8Location(WasmTranslation* wasmTranslation,
      89             :                                            v8::debug::Location* loc,
      90             :                                            const String16& scriptId,
      91             :                                            const String16& expectedV8ScriptId) {
      92         145 :   if (loc->IsEmpty()) return;
      93         145 :   int lineNumber = loc->GetLineNumber();
      94         145 :   int columnNumber = loc->GetColumnNumber();
      95         145 :   String16 translatedScriptId = scriptId;
      96             :   wasmTranslation->TranslateProtocolLocationToWasmScriptLocation(
      97         145 :       &translatedScriptId, &lineNumber, &columnNumber);
      98             :   DCHECK_EQ(expectedV8ScriptId.utf8(), translatedScriptId.utf8());
      99         145 :   *loc = v8::debug::Location(lineNumber, columnNumber);
     100             : }
     101             : 
     102         185 : void TranslateV8LocationToProtocolLocation(
     103             :     WasmTranslation* wasmTranslation, v8::debug::Location* loc,
     104             :     const String16& scriptId, const String16& expectedProtocolScriptId) {
     105         185 :   int lineNumber = loc->GetLineNumber();
     106         185 :   int columnNumber = loc->GetColumnNumber();
     107         185 :   String16 translatedScriptId = scriptId;
     108             :   wasmTranslation->TranslateWasmScriptLocationToProtocolLocation(
     109         185 :       &translatedScriptId, &lineNumber, &columnNumber);
     110             :   DCHECK_EQ(expectedProtocolScriptId.utf8(), translatedScriptId.utf8());
     111         185 :   *loc = v8::debug::Location(lineNumber, columnNumber);
     112         185 : }
     113             : 
     114      180978 : class ActualScript : public V8DebuggerScript {
     115             :   friend class V8DebuggerScript;
     116             : 
     117             :  public:
     118       60326 :   ActualScript(v8::Isolate* isolate, v8::Local<v8::debug::Script> script,
     119             :                bool isLiveEdit, V8InspectorClient* client)
     120             :       : V8DebuggerScript(isolate, String16::fromInteger(script->Id()),
     121             :                          GetScriptURL(isolate, script, client)),
     122      241304 :         m_isLiveEdit(isLiveEdit) {
     123       60326 :     Initialize(script);
     124       60326 :   }
     125             : 
     126       60326 :   bool isLiveEdit() const override { return m_isLiveEdit; }
     127       60326 :   bool isModule() const override { return m_isModule; }
     128             : 
     129       21041 :   String16 source(size_t pos, size_t len) const override {
     130       21041 :     v8::HandleScope scope(m_isolate);
     131             :     v8::Local<v8::String> v8Source;
     132       63123 :     if (!script()->Source().ToLocal(&v8Source)) return String16();
     133       21041 :     if (pos >= static_cast<size_t>(v8Source->Length())) return String16();
     134             :     size_t substringLength =
     135       42052 :         std::min(len, static_cast<size_t>(v8Source->Length()) - pos);
     136       21026 :     std::unique_ptr<UChar[]> buffer(new UChar[substringLength]);
     137             :     v8Source->Write(m_isolate, reinterpret_cast<uint16_t*>(buffer.get()),
     138       21026 :                     static_cast<int>(pos), static_cast<int>(substringLength));
     139       42067 :     return String16(buffer.get(), substringLength);
     140             :   }
     141       62591 :   int startLine() const override { return m_startLine; }
     142       60326 :   int startColumn() const override { return m_startColumn; }
     143       62581 :   int endLine() const override { return m_endLine; }
     144       60326 :   int endColumn() const override { return m_endColumn; }
     145       55125 :   bool isSourceLoadedLazily() const override { return false; }
     146       60326 :   int length() const override {
     147       60326 :     v8::HandleScope scope(m_isolate);
     148             :     v8::Local<v8::String> v8Source;
     149      180978 :     if (!script()->Source().ToLocal(&v8Source)) return 0;
     150       60326 :     return v8Source->Length();
     151             :   }
     152             : 
     153       60326 :   const String16& sourceMappingURL() const override {
     154       60326 :     return m_sourceMappingURL;
     155             :   }
     156             : 
     157        5201 :   void setSourceMappingURL(const String16& sourceMappingURL) override {
     158        5201 :     m_sourceMappingURL = sourceMappingURL;
     159        5201 :   }
     160             : 
     161          50 :   void setSource(const String16& newSource, bool preview,
     162             :                  v8::debug::LiveEditResult* result) override {
     163          50 :     v8::EscapableHandleScope scope(m_isolate);
     164          50 :     v8::Local<v8::String> v8Source = toV8String(m_isolate, newSource);
     165         100 :     if (!m_script.Get(m_isolate)->SetScriptSource(v8Source, preview, result)) {
     166          10 :       result->message = scope.Escape(result->message);
     167          10 :       return;
     168             :     }
     169          40 :     if (preview) return;
     170          80 :     m_hash = String16();
     171          40 :     Initialize(scope.Escape(result->script));
     172             :   }
     173             : 
     174         225 :   bool getPossibleBreakpoints(
     175             :       const v8::debug::Location& start, const v8::debug::Location& end,
     176             :       bool restrictToFunction,
     177             :       std::vector<v8::debug::BreakLocation>* locations) override {
     178         225 :     v8::HandleScope scope(m_isolate);
     179         225 :     v8::Local<v8::debug::Script> script = m_script.Get(m_isolate);
     180             :     std::vector<v8::debug::BreakLocation> allLocations;
     181         225 :     if (!script->GetPossibleBreakpoints(start, end, restrictToFunction,
     182         225 :                                         &allLocations)) {
     183             :       return false;
     184             :     }
     185         440 :     if (!allLocations.size()) return true;
     186         195 :     v8::debug::BreakLocation current = allLocations[0];
     187        9940 :     for (size_t i = 1; i < allLocations.size(); ++i) {
     188        7675 :       if (allLocations[i].GetLineNumber() == current.GetLineNumber() &&
     189        5800 :           allLocations[i].GetColumnNumber() == current.GetColumnNumber()) {
     190        1660 :         if (allLocations[i].type() != v8::debug::kCommonBreakLocation) {
     191             :           DCHECK(allLocations[i].type() == v8::debug::kCallBreakLocation ||
     192             :                  allLocations[i].type() == v8::debug::kReturnBreakLocation);
     193             :           // debugger can returns more then one break location at the same
     194             :           // source location, e.g. foo() - in this case there are two break
     195             :           // locations before foo: for statement and for function call, we can
     196             :           // merge them for inspector and report only one with call type.
     197         530 :           current = allLocations[i];
     198             :         }
     199             :       } else {
     200             :         // we assume that returned break locations are sorted.
     201             :         DCHECK(
     202             :             allLocations[i].GetLineNumber() > current.GetLineNumber() ||
     203             :             (allLocations[i].GetColumnNumber() >= current.GetColumnNumber() &&
     204             :              allLocations[i].GetLineNumber() == current.GetLineNumber()));
     205        3945 :         locations->push_back(current);
     206        7890 :         current = allLocations[i];
     207             :       }
     208             :     }
     209         195 :     locations->push_back(current);
     210         420 :     return true;
     211             :   }
     212             : 
     213      120527 :   void resetBlackboxedStateCache() override {
     214      120527 :     v8::HandleScope scope(m_isolate);
     215      241054 :     v8::debug::ResetBlackboxedStateCache(m_isolate, m_script.Get(m_isolate));
     216      120527 :   }
     217             : 
     218         310 :   int offset(int lineNumber, int columnNumber) const override {
     219         310 :     v8::HandleScope scope(m_isolate);
     220         310 :     return m_script.Get(m_isolate)->GetSourceOffset(
     221         620 :         v8::debug::Location(lineNumber, columnNumber));
     222             :   }
     223             : 
     224          60 :   v8::debug::Location location(int offset) const override {
     225          60 :     v8::HandleScope scope(m_isolate);
     226         120 :     return m_script.Get(m_isolate)->GetSourceLocation(offset);
     227             :   }
     228             : 
     229        2090 :   bool setBreakpoint(const String16& condition, v8::debug::Location* location,
     230             :                      int* id) const override {
     231        2090 :     v8::HandleScope scope(m_isolate);
     232        2090 :     return script()->SetBreakpoint(toV8String(m_isolate, condition), location,
     233        6270 :                                    id);
     234             :   }
     235             : 
     236       60391 :   const String16& hash() const override {
     237       60391 :     if (m_hash.isEmpty()) {
     238       60326 :       v8::HandleScope scope(m_isolate);
     239             :       v8::Local<v8::String> v8Source;
     240      180978 :       if (script()->Source().ToLocal(&v8Source)) {
     241      120652 :         m_hash = calculateHash(m_isolate, v8Source);
     242       60326 :       }
     243             :     }
     244             :     DCHECK(!m_hash.isEmpty());
     245       60391 :     return m_hash;
     246             :   }
     247             : 
     248             :  private:
     249       60326 :   String16 GetScriptURL(v8::Isolate* isolate,
     250             :                         v8::Local<v8::debug::Script> script,
     251             :                         V8InspectorClient* client) {
     252             :     v8::Local<v8::String> sourceURL;
     253      120652 :     if (script->SourceURL().ToLocal(&sourceURL) && sourceURL->Length() > 0)
     254        2214 :       return toProtocolString(isolate, sourceURL);
     255             :     v8::Local<v8::String> v8Name;
     256      116224 :     if (script->Name().ToLocal(&v8Name) && v8Name->Length() > 0) {
     257       15979 :       String16 name = toProtocolString(isolate, v8Name);
     258             :       std::unique_ptr<StringBuffer> url =
     259       15979 :           client->resourceNameToUrl(toStringView(name));
     260       15979 :       return url ? toString16(url->string()) : name;
     261             :     }
     262       42133 :     return String16();
     263             :   }
     264             : 
     265      143783 :   v8::Local<v8::debug::Script> script() const override {
     266      287566 :     return m_script.Get(m_isolate);
     267             :   }
     268             : 
     269       60366 :   void Initialize(v8::Local<v8::debug::Script> script) {
     270             :     v8::Local<v8::String> tmp;
     271             :     m_hasSourceURLComment =
     272      120732 :         script->SourceURL().ToLocal(&tmp) && tmp->Length() > 0;
     273      120732 :     if (script->SourceMappingURL().ToLocal(&tmp))
     274        1170 :       m_sourceMappingURL = toProtocolString(m_isolate, tmp);
     275       60366 :     m_startLine = script->LineOffset();
     276       60366 :     m_startColumn = script->ColumnOffset();
     277       60366 :     std::vector<int> lineEnds = script->LineEnds();
     278      120732 :     CHECK(lineEnds.size());
     279      120732 :     int source_length = lineEnds[lineEnds.size() - 1];
     280       60366 :     if (lineEnds.size()) {
     281       60366 :       m_endLine = static_cast<int>(lineEnds.size()) + m_startLine - 1;
     282       60366 :       if (lineEnds.size() > 1) {
     283       42776 :         m_endColumn = source_length - lineEnds[lineEnds.size() - 2] - 1;
     284             :       } else {
     285       38978 :         m_endColumn = source_length + m_startColumn;
     286             :       }
     287             :     } else {
     288           0 :       m_endLine = m_startLine;
     289           0 :       m_endColumn = m_startColumn;
     290             :     }
     291             : 
     292      120732 :     USE(script->ContextId().To(&m_executionContextId));
     293             : 
     294       60366 :     m_isModule = script->IsModule();
     295             : 
     296       60366 :     m_script.Reset(m_isolate, script);
     297             :     m_script.AnnotateStrongRetainer(kGlobalDebuggerScriptHandleLabel);
     298       60366 :   }
     299             : 
     300             :   String16 m_sourceMappingURL;
     301             :   bool m_isLiveEdit = false;
     302             :   bool m_isModule = false;
     303             :   mutable String16 m_hash;
     304             :   int m_startLine = 0;
     305             :   int m_startColumn = 0;
     306             :   int m_endLine = 0;
     307             :   int m_endColumn = 0;
     308             :   v8::Global<v8::debug::Script> m_script;
     309             : };
     310             : 
     311         306 : class WasmVirtualScript : public V8DebuggerScript {
     312             :   friend class V8DebuggerScript;
     313             : 
     314             :  public:
     315         102 :   WasmVirtualScript(v8::Isolate* isolate, WasmTranslation* wasmTranslation,
     316             :                     v8::Local<v8::debug::WasmScript> script, String16 id,
     317             :                     String16 url, int functionIndex)
     318             :       : V8DebuggerScript(isolate, std::move(id), std::move(url)),
     319             :         m_script(isolate, script),
     320             :         m_wasmTranslation(wasmTranslation),
     321         408 :         m_functionIndex(functionIndex) {
     322             :     m_script.AnnotateStrongRetainer(kGlobalDebuggerScriptHandleLabel);
     323         204 :     m_executionContextId = script->ContextId().ToChecked();
     324         102 :   }
     325             : 
     326         102 :   const String16& sourceMappingURL() const override { return emptyString(); }
     327         102 :   bool isLiveEdit() const override { return false; }
     328         102 :   bool isModule() const override { return false; }
     329           0 :   void setSourceMappingURL(const String16&) override {}
     330           0 :   void setSource(const String16&, bool, v8::debug::LiveEditResult*) override {
     331           0 :     UNREACHABLE();
     332             :   }
     333         102 :   bool isSourceLoadedLazily() const override { return true; }
     334          64 :   String16 source(size_t pos, size_t len) const override {
     335          64 :     return m_wasmTranslation->GetSource(m_id, m_functionIndex)
     336          64 :         .substring(pos, len);
     337             :   }
     338          95 :   int startLine() const override {
     339          95 :     return m_wasmTranslation->GetStartLine(m_id, m_functionIndex);
     340             :   }
     341           0 :   int startColumn() const override {
     342           0 :     return m_wasmTranslation->GetStartColumn(m_id, m_functionIndex);
     343             :   }
     344          95 :   int endLine() const override {
     345          95 :     return m_wasmTranslation->GetEndLine(m_id, m_functionIndex);
     346             :   }
     347           0 :   int endColumn() const override {
     348           0 :     return m_wasmTranslation->GetEndColumn(m_id, m_functionIndex);
     349             :   }
     350           0 :   int length() const override {
     351           0 :     return static_cast<int>(source(0, UINT_MAX).length());
     352             :   }
     353             : 
     354          30 :   bool getPossibleBreakpoints(
     355             :       const v8::debug::Location& start, const v8::debug::Location& end,
     356             :       bool restrictToFunction,
     357             :       std::vector<v8::debug::BreakLocation>* locations) override {
     358          30 :     v8::HandleScope scope(m_isolate);
     359          30 :     v8::Local<v8::debug::Script> script = m_script.Get(m_isolate);
     360          30 :     String16 v8ScriptId = String16::fromInteger(script->Id());
     361             : 
     362          30 :     v8::debug::Location translatedStart = start;
     363             :     TranslateProtocolLocationToV8Location(m_wasmTranslation, &translatedStart,
     364          30 :                                           scriptId(), v8ScriptId);
     365             : 
     366          30 :     v8::debug::Location translatedEnd = end;
     367          30 :     if (translatedEnd.IsEmpty()) {
     368             :       // Stop before the start of the next function.
     369             :       translatedEnd =
     370          10 :           v8::debug::Location(translatedStart.GetLineNumber() + 1, 0);
     371             :     } else {
     372             :       TranslateProtocolLocationToV8Location(m_wasmTranslation, &translatedEnd,
     373          20 :                                             scriptId(), v8ScriptId);
     374             :     }
     375             : 
     376             :     bool success = script->GetPossibleBreakpoints(
     377          30 :         translatedStart, translatedEnd, restrictToFunction, locations);
     378         150 :     for (v8::debug::BreakLocation& loc : *locations) {
     379             :       TranslateV8LocationToProtocolLocation(m_wasmTranslation, &loc, v8ScriptId,
     380          90 :                                             scriptId());
     381             :     }
     382          30 :     return success;
     383             :   }
     384             : 
     385         204 :   void resetBlackboxedStateCache() override {}
     386             : 
     387           0 :   int offset(int lineNumber, int columnNumber) const override {
     388           0 :     return kNoOffset;
     389             :   }
     390             : 
     391           0 :   v8::debug::Location location(int offset) const override {
     392           0 :     return v8::debug::Location();
     393             :   }
     394             : 
     395          95 :   bool setBreakpoint(const String16& condition, v8::debug::Location* location,
     396             :                      int* id) const override {
     397          95 :     v8::HandleScope scope(m_isolate);
     398          95 :     v8::Local<v8::debug::Script> script = m_script.Get(m_isolate);
     399          95 :     String16 v8ScriptId = String16::fromInteger(script->Id());
     400             : 
     401             :     TranslateProtocolLocationToV8Location(m_wasmTranslation, location,
     402          95 :                                           scriptId(), v8ScriptId);
     403          95 :     if (location->IsEmpty()) return false;
     404          95 :     if (!script->SetBreakpoint(toV8String(m_isolate, condition), location, id))
     405             :       return false;
     406             :     TranslateV8LocationToProtocolLocation(m_wasmTranslation, location,
     407          95 :                                           v8ScriptId, scriptId());
     408         190 :     return true;
     409             :   }
     410             : 
     411         102 :   const String16& hash() const override {
     412         102 :     if (m_hash.isEmpty()) {
     413         204 :       m_hash = m_wasmTranslation->GetHash(m_id, m_functionIndex);
     414             :     }
     415         102 :     return m_hash;
     416             :   }
     417             : 
     418             :  private:
     419         102 :   static const String16& emptyString() {
     420             :     // On the heap and leaked so that no destructor needs to run at exit time.
     421         102 :     static const String16* singleEmptyString = new String16;
     422         102 :     return *singleEmptyString;
     423             :   }
     424             : 
     425           0 :   v8::Local<v8::debug::Script> script() const override {
     426           0 :     return m_script.Get(m_isolate);
     427             :   }
     428             : 
     429             :   v8::Global<v8::debug::WasmScript> m_script;
     430             :   WasmTranslation* m_wasmTranslation;
     431             :   int m_functionIndex;
     432             :   mutable String16 m_hash;
     433             : };
     434             : 
     435             : }  // namespace
     436             : 
     437       60326 : std::unique_ptr<V8DebuggerScript> V8DebuggerScript::Create(
     438             :     v8::Isolate* isolate, v8::Local<v8::debug::Script> scriptObj,
     439             :     bool isLiveEdit, V8InspectorClient* client) {
     440             :   return std::unique_ptr<ActualScript>(
     441      120652 :       new ActualScript(isolate, scriptObj, isLiveEdit, client));
     442             : }
     443             : 
     444         102 : std::unique_ptr<V8DebuggerScript> V8DebuggerScript::CreateWasm(
     445             :     v8::Isolate* isolate, WasmTranslation* wasmTranslation,
     446             :     v8::Local<v8::debug::WasmScript> underlyingScript, String16 id,
     447             :     String16 url, int functionIndex) {
     448             :   return std::unique_ptr<WasmVirtualScript>(
     449             :       new WasmVirtualScript(isolate, wasmTranslation, underlyingScript,
     450         306 :                             std::move(id), std::move(url), functionIndex));
     451             : }
     452             : 
     453           0 : V8DebuggerScript::V8DebuggerScript(v8::Isolate* isolate, String16 id,
     454             :                                    String16 url)
     455       60428 :     : m_id(std::move(id)), m_url(std::move(url)), m_isolate(isolate) {}
     456             : 
     457             : V8DebuggerScript::~V8DebuggerScript() = default;
     458             : 
     459        5201 : void V8DebuggerScript::setSourceURL(const String16& sourceURL) {
     460        5201 :   if (sourceURL.length() > 0) {
     461          40 :     m_hasSourceURLComment = true;
     462          40 :     m_url = sourceURL;
     463             :   }
     464        5201 : }
     465             : 
     466           0 : bool V8DebuggerScript::setBreakpoint(const String16& condition,
     467             :                                      v8::debug::Location* loc, int* id) const {
     468           0 :   v8::HandleScope scope(m_isolate);
     469           0 :   return script()->SetBreakpoint(toV8String(m_isolate, condition), loc, id);
     470             : }
     471             : }  // namespace v8_inspector

Generated by: LCOV version 1.10