Home | History | Annotate | Download | only in inspector
      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/protocol-platform.h"
      8 #include "src/inspector/string-util.h"
      9 
     10 namespace v8_inspector {
     11 
     12 static const char hexDigits[17] = "0123456789ABCDEF";
     13 
     14 static void appendUnsignedAsHex(uint64_t number, String16Builder* destination) {
     15   for (size_t i = 0; i < 8; ++i) {
     16     UChar c = hexDigits[number & 0xF];
     17     destination->append(c);
     18     number >>= 4;
     19   }
     20 }
     21 
     22 // Hash algorithm for substrings is described in "ber die Komplexitt der
     23 // Multiplikation in
     24 // eingeschrnkten Branchingprogrammmodellen" by Woelfe.
     25 // http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECTION00832000000000000000
     26 static String16 calculateHash(const String16& str) {
     27   static uint64_t prime[] = {0x3FB75161, 0xAB1F4E4F, 0x82675BC5, 0xCD924D35,
     28                              0x81ABE279};
     29   static uint64_t random[] = {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476,
     30                               0xC3D2E1F0};
     31   static uint32_t randomOdd[] = {0xB4663807, 0xCC322BF5, 0xD4F91BBD, 0xA7BEA11D,
     32                                  0x8F462907};
     33 
     34   uint64_t hashes[] = {0, 0, 0, 0, 0};
     35   uint64_t zi[] = {1, 1, 1, 1, 1};
     36 
     37   const size_t hashesSize = arraysize(hashes);
     38 
     39   size_t current = 0;
     40   const uint32_t* data = nullptr;
     41   size_t sizeInBytes = sizeof(UChar) * str.length();
     42   data = reinterpret_cast<const uint32_t*>(str.characters16());
     43   for (size_t i = 0; i < sizeInBytes / 4; i += 4) {
     44     uint32_t v = data[i];
     45     uint64_t xi = v * randomOdd[current] & 0x7FFFFFFF;
     46     hashes[current] = (hashes[current] + zi[current] * xi) % prime[current];
     47     zi[current] = (zi[current] * random[current]) % prime[current];
     48     current = current == hashesSize - 1 ? 0 : current + 1;
     49   }
     50   if (sizeInBytes % 4) {
     51     uint32_t v = 0;
     52     for (size_t i = sizeInBytes - sizeInBytes % 4; i < sizeInBytes; ++i) {
     53       v <<= 8;
     54       v |= reinterpret_cast<const uint8_t*>(data)[i];
     55     }
     56     uint64_t xi = v * randomOdd[current] & 0x7FFFFFFF;
     57     hashes[current] = (hashes[current] + zi[current] * xi) % prime[current];
     58     zi[current] = (zi[current] * random[current]) % prime[current];
     59     current = current == hashesSize - 1 ? 0 : current + 1;
     60   }
     61 
     62   for (size_t i = 0; i < hashesSize; ++i)
     63     hashes[i] = (hashes[i] + zi[i] * (prime[i] - 1)) % prime[i];
     64 
     65   String16Builder hash;
     66   for (size_t i = 0; i < hashesSize; ++i) appendUnsignedAsHex(hashes[i], &hash);
     67   return hash.toString();
     68 }
     69 
     70 V8DebuggerScript::V8DebuggerScript(v8::Isolate* isolate,
     71                                    v8::Local<v8::DebugInterface::Script> script,
     72                                    bool isLiveEdit) {
     73   m_isolate = script->GetIsolate();
     74   m_id = String16::fromInteger(script->Id());
     75   v8::Local<v8::String> tmp;
     76   if (script->Name().ToLocal(&tmp)) m_url = toProtocolString(tmp);
     77   if (script->SourceURL().ToLocal(&tmp)) {
     78     m_sourceURL = toProtocolString(tmp);
     79     if (m_url.isEmpty()) m_url = toProtocolString(tmp);
     80   }
     81   if (script->SourceMappingURL().ToLocal(&tmp))
     82     m_sourceMappingURL = toProtocolString(tmp);
     83   m_startLine = script->LineOffset();
     84   m_startColumn = script->ColumnOffset();
     85   std::vector<int> lineEnds = script->LineEnds();
     86   CHECK(lineEnds.size());
     87   int source_length = lineEnds[lineEnds.size() - 1];
     88   if (lineEnds.size()) {
     89     m_endLine = static_cast<int>(lineEnds.size()) + m_startLine - 1;
     90     if (lineEnds.size() > 1) {
     91       m_endColumn = source_length - lineEnds[lineEnds.size() - 2] - 1;
     92     } else {
     93       m_endColumn = source_length + m_startColumn;
     94     }
     95   } else {
     96     m_endLine = m_startLine;
     97     m_endColumn = m_startColumn;
     98   }
     99 
    100   if (script->ContextData().ToLocal(&tmp)) {
    101     String16 contextData = toProtocolString(tmp);
    102     size_t firstComma = contextData.find(",", 0);
    103     size_t secondComma = firstComma != String16::kNotFound
    104                              ? contextData.find(",", firstComma + 1)
    105                              : String16::kNotFound;
    106     if (secondComma != String16::kNotFound) {
    107       String16 executionContextId =
    108           contextData.substring(firstComma + 1, secondComma - firstComma - 1);
    109       bool isOk = false;
    110       m_executionContextId = executionContextId.toInteger(&isOk);
    111       if (!isOk) m_executionContextId = 0;
    112       m_executionContextAuxData = contextData.substring(secondComma + 1);
    113     }
    114   }
    115 
    116   m_isLiveEdit = isLiveEdit;
    117 
    118   if (script->Source().ToLocal(&tmp)) {
    119     m_source.Reset(m_isolate, tmp);
    120     String16 source = toProtocolString(tmp);
    121     m_hash = calculateHash(source);
    122     // V8 will not count last line if script source ends with \n.
    123     if (source.length() > 1 && source[source.length() - 1] == '\n') {
    124       m_endLine++;
    125       m_endColumn = 0;
    126     }
    127   }
    128 
    129   m_script.Reset(m_isolate, script);
    130 }
    131 
    132 V8DebuggerScript::~V8DebuggerScript() {}
    133 
    134 const String16& V8DebuggerScript::sourceURL() const {
    135   return m_sourceURL.isEmpty() ? m_url : m_sourceURL;
    136 }
    137 
    138 v8::Local<v8::String> V8DebuggerScript::source(v8::Isolate* isolate) const {
    139   return m_source.Get(isolate);
    140 }
    141 
    142 void V8DebuggerScript::setSourceURL(const String16& sourceURL) {
    143   m_sourceURL = sourceURL;
    144 }
    145 
    146 void V8DebuggerScript::setSourceMappingURL(const String16& sourceMappingURL) {
    147   m_sourceMappingURL = sourceMappingURL;
    148 }
    149 
    150 void V8DebuggerScript::setSource(v8::Local<v8::String> source) {
    151   m_source.Reset(m_isolate, source);
    152   m_hash = calculateHash(toProtocolString(source));
    153 }
    154 
    155 bool V8DebuggerScript::getPossibleBreakpoints(
    156     const v8::DebugInterface::Location& start,
    157     const v8::DebugInterface::Location& end,
    158     std::vector<v8::DebugInterface::Location>* locations) {
    159   v8::HandleScope scope(m_isolate);
    160   v8::Local<v8::DebugInterface::Script> script = m_script.Get(m_isolate);
    161   return script->GetPossibleBreakpoints(start, end, locations);
    162 }
    163 
    164 }  // namespace v8_inspector
    165