| File: | out/../deps/v8/src/inspector/v8-debugger-script.cc |
| Warning: | line 77, column 5 Value stored to 'current' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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/base/memory.h" |
| 8 | #include "src/inspector/inspected-context.h" |
| 9 | #include "src/inspector/protocol/Debugger.h" |
| 10 | #include "src/inspector/string-util.h" |
| 11 | #include "src/inspector/v8-debugger-agent-impl.h" |
| 12 | #include "src/inspector/v8-inspector-impl.h" |
| 13 | |
| 14 | namespace v8_inspector { |
| 15 | |
| 16 | namespace { |
| 17 | |
| 18 | const char kGlobalDebuggerScriptHandleLabel[] = "DevTools debugger"; |
| 19 | |
| 20 | // Hash algorithm for substrings is described in "Über die Komplexität der |
| 21 | // Multiplikation in |
| 22 | // eingeschränkten Branchingprogrammmodellen" by Woelfe. |
| 23 | // http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECTION00832000000000000000 |
| 24 | String16 calculateHash(v8::Isolate* isolate, v8::Local<v8::String> source) { |
| 25 | static uint64_t prime[] = {0x3FB75161, 0xAB1F4E4F, 0x82675BC5, 0xCD924D35, |
| 26 | 0x81ABE279}; |
| 27 | static uint64_t random[] = {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, |
| 28 | 0xC3D2E1F0}; |
| 29 | static uint32_t randomOdd[] = {0xB4663807, 0xCC322BF5, 0xD4F91BBD, 0xA7BEA11D, |
| 30 | 0x8F462907}; |
| 31 | |
| 32 | uint64_t hashes[] = {0, 0, 0, 0, 0}; |
| 33 | uint64_t zi[] = {1, 1, 1, 1, 1}; |
| 34 | |
| 35 | const size_t hashesSize = arraysize(hashes)(sizeof(ArraySizeHelper(hashes))); |
| 36 | |
| 37 | size_t current = 0; |
| 38 | |
| 39 | std::unique_ptr<UChar[]> buffer(new UChar[source->Length()]); |
| 40 | int written = source->Write( |
| 41 | isolate, reinterpret_cast<uint16_t*>(buffer.get()), 0, source->Length()); |
| 42 | |
| 43 | const uint32_t* data = nullptr; |
| 44 | size_t sizeInBytes = sizeof(UChar) * written; |
| 45 | data = reinterpret_cast<const uint32_t*>(buffer.get()); |
| 46 | for (size_t i = 0; i < sizeInBytes / 4; ++i) { |
| 47 | uint32_t d = v8::base::ReadUnalignedValue<uint32_t>( |
| 48 | reinterpret_cast<v8::internal::Address>(data + i)); |
| 49 | #if V8_TARGET_LITTLE_ENDIAN1 |
| 50 | uint32_t v = d; |
| 51 | #else |
| 52 | uint32_t v = (d << 16) | (d >> 16); |
| 53 | #endif |
| 54 | uint64_t xi = v * randomOdd[current] & 0x7FFFFFFF; |
| 55 | hashes[current] = (hashes[current] + zi[current] * xi) % prime[current]; |
| 56 | zi[current] = (zi[current] * random[current]) % prime[current]; |
| 57 | current = current == hashesSize - 1 ? 0 : current + 1; |
| 58 | } |
| 59 | if (sizeInBytes % 4) { |
| 60 | uint32_t v = 0; |
| 61 | const uint8_t* data_8b = reinterpret_cast<const uint8_t*>(data); |
| 62 | for (size_t i = sizeInBytes - sizeInBytes % 4; i < sizeInBytes; ++i) { |
| 63 | v <<= 8; |
| 64 | #if V8_TARGET_LITTLE_ENDIAN1 |
| 65 | v |= data_8b[i]; |
| 66 | #else |
| 67 | if (i % 2) { |
| 68 | v |= data_8b[i - 1]; |
| 69 | } else { |
| 70 | v |= data_8b[i + 1]; |
| 71 | } |
| 72 | #endif |
| 73 | } |
| 74 | uint64_t xi = v * randomOdd[current] & 0x7FFFFFFF; |
| 75 | hashes[current] = (hashes[current] + zi[current] * xi) % prime[current]; |
| 76 | zi[current] = (zi[current] * random[current]) % prime[current]; |
| 77 | current = current == hashesSize - 1 ? 0 : current + 1; |
Value stored to 'current' is never read | |
| 78 | } |
| 79 | |
| 80 | for (size_t i = 0; i < hashesSize; ++i) |
| 81 | hashes[i] = (hashes[i] + zi[i] * (prime[i] - 1)) % prime[i]; |
| 82 | |
| 83 | String16Builder hash; |
| 84 | for (size_t i = 0; i < hashesSize; ++i) |
| 85 | hash.appendUnsignedAsHex(static_cast<uint32_t>(hashes[i])); |
| 86 | return hash.toString(); |
| 87 | } |
| 88 | |
| 89 | class ActualScript : public V8DebuggerScript { |
| 90 | friend class V8DebuggerScript; |
| 91 | |
| 92 | public: |
| 93 | ActualScript(v8::Isolate* isolate, v8::Local<v8::debug::Script> script, |
| 94 | bool isLiveEdit, V8DebuggerAgentImpl* agent, |
| 95 | V8InspectorClient* client) |
| 96 | : V8DebuggerScript(isolate, String16::fromInteger(script->Id()), |
| 97 | GetScriptURL(isolate, script, client), |
| 98 | GetScriptName(isolate, script, client)), |
| 99 | m_agent(agent), |
| 100 | m_isLiveEdit(isLiveEdit) { |
| 101 | Initialize(script); |
| 102 | } |
| 103 | |
| 104 | bool isLiveEdit() const override { return m_isLiveEdit; } |
| 105 | bool isModule() const override { return m_isModule; } |
| 106 | |
| 107 | String16 source(size_t pos, size_t len) const override { |
| 108 | v8::HandleScope scope(m_isolate); |
| 109 | v8::Local<v8::String> v8Source; |
| 110 | if (!m_scriptSource.Get(m_isolate)->JavaScriptCode().ToLocal(&v8Source)) { |
| 111 | return String16(); |
| 112 | } |
| 113 | if (pos >= static_cast<size_t>(v8Source->Length())) return String16(); |
| 114 | size_t substringLength = |
| 115 | std::min(len, static_cast<size_t>(v8Source->Length()) - pos); |
| 116 | std::unique_ptr<UChar[]> buffer(new UChar[substringLength]); |
| 117 | v8Source->Write(m_isolate, reinterpret_cast<uint16_t*>(buffer.get()), |
| 118 | static_cast<int>(pos), static_cast<int>(substringLength)); |
| 119 | return String16(buffer.get(), substringLength); |
| 120 | } |
| 121 | Language getLanguage() const override { return m_language; } |
| 122 | |
| 123 | #if V8_ENABLE_WEBASSEMBLY1 |
| 124 | v8::Maybe<v8::MemorySpan<const uint8_t>> wasmBytecode() const override { |
| 125 | v8::HandleScope scope(m_isolate); |
| 126 | v8::MemorySpan<const uint8_t> bytecode; |
| 127 | if (m_scriptSource.Get(m_isolate)->WasmBytecode().To(&bytecode)) { |
| 128 | return v8::Just(bytecode); |
| 129 | } |
| 130 | return v8::Nothing<v8::MemorySpan<const uint8_t>>(); |
| 131 | } |
| 132 | |
| 133 | v8::Maybe<v8::debug::WasmScript::DebugSymbolsType> getDebugSymbolsType() |
| 134 | const override { |
| 135 | auto script = this->script(); |
| 136 | if (!script->IsWasm()) |
| 137 | return v8::Nothing<v8::debug::WasmScript::DebugSymbolsType>(); |
| 138 | return v8::Just(v8::debug::WasmScript::Cast(*script)->GetDebugSymbolType()); |
| 139 | } |
| 140 | |
| 141 | v8::Maybe<String16> getExternalDebugSymbolsURL() const override { |
| 142 | auto script = this->script(); |
| 143 | if (!script->IsWasm()) return v8::Nothing<String16>(); |
| 144 | v8::MemorySpan<const char> external_url = |
| 145 | v8::debug::WasmScript::Cast(*script)->ExternalSymbolsURL(); |
| 146 | if (external_url.size() == 0) return v8::Nothing<String16>(); |
| 147 | return v8::Just(String16(external_url.data(), external_url.size())); |
| 148 | } |
| 149 | #endif // V8_ENABLE_WEBASSEMBLY |
| 150 | |
| 151 | int startLine() const override { return m_startLine; } |
| 152 | int startColumn() const override { return m_startColumn; } |
| 153 | int endLine() const override { return m_endLine; } |
| 154 | int endColumn() const override { return m_endColumn; } |
| 155 | int codeOffset() const override { |
| 156 | #if V8_ENABLE_WEBASSEMBLY1 |
| 157 | if (script()->IsWasm()) { |
| 158 | return v8::debug::WasmScript::Cast(*script())->CodeOffset(); |
| 159 | } |
| 160 | #endif // V8_ENABLE_WEBASSEMBLY |
| 161 | return 0; |
| 162 | } |
| 163 | int length() const override { |
| 164 | return static_cast<int>(m_scriptSource.Get(m_isolate)->Length()); |
| 165 | } |
| 166 | |
| 167 | const String16& sourceMappingURL() const override { |
| 168 | return m_sourceMappingURL; |
| 169 | } |
| 170 | |
| 171 | void setSourceMappingURL(const String16& sourceMappingURL) override { |
| 172 | m_sourceMappingURL = sourceMappingURL; |
| 173 | } |
| 174 | |
| 175 | void setSource(const String16& newSource, bool preview, |
| 176 | v8::debug::LiveEditResult* result) override { |
| 177 | v8::EscapableHandleScope scope(m_isolate); |
| 178 | v8::Local<v8::String> v8Source = toV8String(m_isolate, newSource); |
| 179 | if (!m_script.Get(m_isolate)->SetScriptSource(v8Source, preview, result)) { |
| 180 | result->message = scope.Escape(result->message); |
| 181 | return; |
| 182 | } |
| 183 | // NOP if preview or unchanged source (diffs.empty() in PatchScript) |
| 184 | if (preview || result->script.IsEmpty()) return; |
| 185 | |
| 186 | m_hash = String16(); |
| 187 | Initialize(scope.Escape(result->script)); |
| 188 | } |
| 189 | |
| 190 | bool getPossibleBreakpoints( |
| 191 | const v8::debug::Location& start, const v8::debug::Location& end, |
| 192 | bool restrictToFunction, |
| 193 | std::vector<v8::debug::BreakLocation>* locations) override { |
| 194 | v8::HandleScope scope(m_isolate); |
| 195 | v8::Local<v8::debug::Script> script = m_script.Get(m_isolate); |
| 196 | std::vector<v8::debug::BreakLocation> allLocations; |
| 197 | if (!script->GetPossibleBreakpoints(start, end, restrictToFunction, |
| 198 | &allLocations)) { |
| 199 | return false; |
| 200 | } |
| 201 | if (!allLocations.size()) return true; |
| 202 | v8::debug::BreakLocation current = allLocations[0]; |
| 203 | for (size_t i = 1; i < allLocations.size(); ++i) { |
| 204 | if (allLocations[i].GetLineNumber() == current.GetLineNumber() && |
| 205 | allLocations[i].GetColumnNumber() == current.GetColumnNumber()) { |
| 206 | if (allLocations[i].type() != v8::debug::kCommonBreakLocation) { |
| 207 | DCHECK(allLocations[i].type() == v8::debug::kCallBreakLocation ||((void) 0) |
| 208 | allLocations[i].type() == v8::debug::kReturnBreakLocation)((void) 0); |
| 209 | // debugger can returns more then one break location at the same |
| 210 | // source location, e.g. foo() - in this case there are two break |
| 211 | // locations before foo: for statement and for function call, we can |
| 212 | // merge them for inspector and report only one with call type. |
| 213 | current = allLocations[i]; |
| 214 | } |
| 215 | } else { |
| 216 | // we assume that returned break locations are sorted. |
| 217 | DCHECK(((void) 0) |
| 218 | allLocations[i].GetLineNumber() > current.GetLineNumber() ||((void) 0) |
| 219 | (allLocations[i].GetColumnNumber() >= current.GetColumnNumber() &&((void) 0) |
| 220 | allLocations[i].GetLineNumber() == current.GetLineNumber()))((void) 0); |
| 221 | locations->push_back(current); |
| 222 | current = allLocations[i]; |
| 223 | } |
| 224 | } |
| 225 | locations->push_back(current); |
| 226 | return true; |
| 227 | } |
| 228 | |
| 229 | void resetBlackboxedStateCache() override { |
| 230 | v8::HandleScope scope(m_isolate); |
| 231 | v8::debug::ResetBlackboxedStateCache(m_isolate, m_script.Get(m_isolate)); |
| 232 | } |
| 233 | |
| 234 | int offset(int lineNumber, int columnNumber) const override { |
| 235 | v8::HandleScope scope(m_isolate); |
| 236 | return m_script.Get(m_isolate)->GetSourceOffset( |
| 237 | v8::debug::Location(lineNumber, columnNumber)); |
| 238 | } |
| 239 | |
| 240 | v8::debug::Location location(int offset) const override { |
| 241 | v8::HandleScope scope(m_isolate); |
| 242 | return m_script.Get(m_isolate)->GetSourceLocation(offset); |
| 243 | } |
| 244 | |
| 245 | bool setBreakpoint(const String16& condition, v8::debug::Location* location, |
| 246 | int* id) const override { |
| 247 | v8::HandleScope scope(m_isolate); |
| 248 | return script()->SetBreakpoint(toV8String(m_isolate, condition), location, |
| 249 | id); |
| 250 | } |
| 251 | |
| 252 | bool setInstrumentationBreakpoint(int* id) const override { |
| 253 | v8::HandleScope scope(m_isolate); |
| 254 | return script()->SetInstrumentationBreakpoint(id); |
| 255 | } |
| 256 | |
| 257 | const String16& hash() const override { |
| 258 | if (!m_hash.isEmpty()) return m_hash; |
| 259 | v8::HandleScope scope(m_isolate); |
| 260 | v8::Local<v8::String> v8Source; |
| 261 | if (!m_scriptSource.Get(m_isolate)->JavaScriptCode().ToLocal(&v8Source)) { |
| 262 | v8Source = v8::String::Empty(m_isolate); |
| 263 | } |
| 264 | m_hash = calculateHash(m_isolate, v8Source); |
| 265 | DCHECK(!m_hash.isEmpty())((void) 0); |
| 266 | return m_hash; |
| 267 | } |
| 268 | |
| 269 | private: |
| 270 | static String16 GetScriptURL(v8::Isolate* isolate, |
| 271 | v8::Local<v8::debug::Script> script, |
| 272 | V8InspectorClient* client) { |
| 273 | v8::Local<v8::String> sourceURL; |
| 274 | if (script->SourceURL().ToLocal(&sourceURL) && sourceURL->Length() > 0) |
| 275 | return toProtocolString(isolate, sourceURL); |
| 276 | return GetScriptName(isolate, script, client); |
| 277 | } |
| 278 | |
| 279 | static String16 GetScriptName(v8::Isolate* isolate, |
| 280 | v8::Local<v8::debug::Script> script, |
| 281 | V8InspectorClient* client) { |
| 282 | v8::Local<v8::String> v8Name; |
| 283 | if (script->Name().ToLocal(&v8Name) && v8Name->Length() > 0) { |
| 284 | String16 name = toProtocolString(isolate, v8Name); |
| 285 | std::unique_ptr<StringBuffer> url = |
| 286 | client->resourceNameToUrl(toStringView(name)); |
| 287 | return url ? toString16(url->string()) : name; |
| 288 | } |
| 289 | return String16(); |
| 290 | } |
| 291 | |
| 292 | v8::Local<v8::debug::Script> script() const override { |
| 293 | return m_script.Get(m_isolate); |
| 294 | } |
| 295 | |
| 296 | void Initialize(v8::Local<v8::debug::Script> script) { |
| 297 | v8::Local<v8::String> tmp; |
| 298 | m_hasSourceURLComment = |
| 299 | script->SourceURL().ToLocal(&tmp) && tmp->Length() > 0; |
| 300 | if (script->SourceMappingURL().ToLocal(&tmp)) |
| 301 | m_sourceMappingURL = toProtocolString(m_isolate, tmp); |
| 302 | m_startLine = script->StartLine(); |
| 303 | m_startColumn = script->StartColumn(); |
| 304 | m_endLine = script->EndLine(); |
| 305 | m_endColumn = script->EndColumn(); |
| 306 | |
| 307 | USE(script->ContextId().To(&m_executionContextId))do { ::v8::base::Use unused_tmp_array_for_use_macro[]{script-> ContextId().To(&m_executionContextId)}; (void)unused_tmp_array_for_use_macro ; } while (false); |
| 308 | m_language = V8DebuggerScript::Language::JavaScript; |
| 309 | #if V8_ENABLE_WEBASSEMBLY1 |
| 310 | if (script->IsWasm()) { |
| 311 | m_language = V8DebuggerScript::Language::WebAssembly; |
| 312 | } |
| 313 | #endif // V8_ENABLE_WEBASSEMBLY |
| 314 | |
| 315 | m_isModule = script->IsModule(); |
| 316 | |
| 317 | m_script.Reset(m_isolate, script); |
| 318 | m_script.AnnotateStrongRetainer(kGlobalDebuggerScriptHandleLabel); |
| 319 | m_scriptSource.Reset(m_isolate, script->Source()); |
| 320 | m_scriptSource.AnnotateStrongRetainer(kGlobalDebuggerScriptHandleLabel); |
| 321 | } |
| 322 | |
| 323 | void MakeWeak() override { |
| 324 | m_script.SetWeak( |
| 325 | this, |
| 326 | [](const v8::WeakCallbackInfo<ActualScript>& data) { |
| 327 | data.GetParameter()->WeakCallback(); |
| 328 | }, |
| 329 | v8::WeakCallbackType::kParameter); |
| 330 | } |
| 331 | |
| 332 | void WeakCallback() { |
| 333 | m_script.Reset(); |
| 334 | m_agent->ScriptCollected(this); |
| 335 | } |
| 336 | |
| 337 | V8DebuggerAgentImpl* m_agent; |
| 338 | String16 m_sourceMappingURL; |
| 339 | Language m_language; |
| 340 | bool m_isLiveEdit = false; |
| 341 | bool m_isModule = false; |
| 342 | mutable String16 m_hash; |
| 343 | int m_startLine = 0; |
| 344 | int m_startColumn = 0; |
| 345 | int m_endLine = 0; |
| 346 | int m_endColumn = 0; |
| 347 | v8::Global<v8::debug::Script> m_script; |
| 348 | v8::Global<v8::debug::ScriptSource> m_scriptSource; |
| 349 | }; |
| 350 | |
| 351 | } // namespace |
| 352 | |
| 353 | std::unique_ptr<V8DebuggerScript> V8DebuggerScript::Create( |
| 354 | v8::Isolate* isolate, v8::Local<v8::debug::Script> scriptObj, |
| 355 | bool isLiveEdit, V8DebuggerAgentImpl* agent, V8InspectorClient* client) { |
| 356 | return std::make_unique<ActualScript>(isolate, scriptObj, isLiveEdit, agent, |
| 357 | client); |
| 358 | } |
| 359 | |
| 360 | V8DebuggerScript::V8DebuggerScript(v8::Isolate* isolate, String16 id, |
| 361 | String16 url, String16 embedderName) |
| 362 | : m_id(std::move(id)), |
| 363 | m_url(std::move(url)), |
| 364 | m_isolate(isolate), |
| 365 | m_embedderName(embedderName) {} |
| 366 | |
| 367 | V8DebuggerScript::~V8DebuggerScript() = default; |
| 368 | |
| 369 | void V8DebuggerScript::setSourceURL(const String16& sourceURL) { |
| 370 | if (sourceURL.length() > 0) { |
| 371 | m_hasSourceURLComment = true; |
| 372 | m_url = sourceURL; |
| 373 | } |
| 374 | } |
| 375 | |
| 376 | #if V8_ENABLE_WEBASSEMBLY1 |
| 377 | void V8DebuggerScript::removeWasmBreakpoint(int id) { |
| 378 | v8::HandleScope scope(m_isolate); |
| 379 | script()->RemoveWasmBreakpoint(id); |
| 380 | } |
| 381 | #endif // V8_ENABLE_WEBASSEMBLY |
| 382 | |
| 383 | } // namespace v8_inspector |