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 |