5 #include "src/inspector/v8-debugger-script.h" 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" 17 const char kGlobalDebuggerScriptHandleLabel[] =
"DevTools debugger";
24 static uint64_t prime[] = {0x3FB75161, 0xAB1F4E4F, 0x82675BC5, 0xCD924D35,
26 static uint64_t random[] = {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476,
28 static uint32_t randomOdd[] = {0xB4663807, 0xCC322BF5, 0xD4F91BBD, 0xA7BEA11D,
31 uint64_t hashes[] = {0, 0, 0, 0, 0};
32 uint64_t zi[] = {1, 1, 1, 1, 1};
34 const size_t hashesSize = arraysize(hashes);
38 std::unique_ptr<UChar[]> buffer(
new UChar[source->Length()]);
39 int written = source->Write(
40 isolate, reinterpret_cast<uint16_t*>(buffer.get()), 0, source->Length());
43 size_t sizeInBytes =
sizeof(UChar) * written;
44 data =
reinterpret_cast<const uint32_t*
>(buffer.get());
45 for (
size_t i = 0;
i < sizeInBytes / 4; ++
i) {
46 uint32_t d = v8::internal::ReadUnalignedUInt32(
47 reinterpret_cast<v8::internal::Address>(data +
i));
48 #if V8_TARGET_LITTLE_ENDIAN 53 uint64_t xi = v * randomOdd[current] & 0x7FFFFFFF;
54 hashes[current] = (hashes[current] + zi[current] * xi) % prime[current];
55 zi[current] = (zi[current] * random[current]) % prime[current];
56 current = current == hashesSize - 1 ? 0 : current + 1;
58 if (sizeInBytes % 4) {
60 const uint8_t* data_8b =
reinterpret_cast<const uint8_t*
>(data);
61 for (
size_t i = sizeInBytes - sizeInBytes % 4;
i < sizeInBytes; ++
i) {
63 #if V8_TARGET_LITTLE_ENDIAN 73 uint64_t xi = v * randomOdd[current] & 0x7FFFFFFF;
74 hashes[current] = (hashes[current] + zi[current] * xi) % prime[current];
75 zi[current] = (zi[current] * random[current]) % prime[current];
76 current = current == hashesSize - 1 ? 0 : current + 1;
79 for (
size_t i = 0;
i < hashesSize; ++
i)
80 hashes[
i] = (hashes[
i] + zi[
i] * (prime[
i] - 1)) % prime[
i];
83 for (
size_t i = 0;
i < hashesSize; ++
i)
84 hash.appendUnsignedAsHex(static_cast<uint32_t>(hashes[
i]));
85 return hash.toString();
88 void TranslateProtocolLocationToV8Location(WasmTranslation* wasmTranslation,
90 const String16& scriptId,
91 const String16& expectedV8ScriptId) {
92 if (loc->IsEmpty())
return;
93 int lineNumber = loc->GetLineNumber();
94 int columnNumber = loc->GetColumnNumber();
95 String16 translatedScriptId = scriptId;
96 wasmTranslation->TranslateProtocolLocationToWasmScriptLocation(
97 &translatedScriptId, &lineNumber, &columnNumber);
98 DCHECK_EQ(expectedV8ScriptId.utf8(), translatedScriptId.utf8());
102 void TranslateV8LocationToProtocolLocation(
104 const String16& scriptId,
const String16& expectedProtocolScriptId) {
105 int lineNumber = loc->GetLineNumber();
106 int columnNumber = loc->GetColumnNumber();
107 String16 translatedScriptId = scriptId;
108 wasmTranslation->TranslateWasmScriptLocationToProtocolLocation(
109 &translatedScriptId, &lineNumber, &columnNumber);
110 DCHECK_EQ(expectedProtocolScriptId.utf8(), translatedScriptId.utf8());
114 class ActualScript :
public V8DebuggerScript {
115 friend class V8DebuggerScript;
119 bool isLiveEdit, V8InspectorClient* client)
120 : V8DebuggerScript(isolate, String16::fromInteger(script->Id()),
121 GetScriptURL(isolate, script, client)),
122 m_isLiveEdit(isLiveEdit) {
126 bool isLiveEdit()
const override {
return m_isLiveEdit; }
127 bool isModule()
const override {
return m_isModule; }
129 String16 source(
size_t pos,
size_t len)
const override {
132 if (!script()->Source().ToLocal(&v8Source))
return String16();
133 if (pos >= static_cast<size_t>(v8Source->
Length()))
return String16();
134 size_t substringLength =
135 std::min(len, static_cast<size_t>(v8Source->
Length()) - pos);
136 std::unique_ptr<UChar[]> buffer(
new UChar[substringLength]);
137 v8Source->Write(m_isolate, reinterpret_cast<uint16_t*>(buffer.get()),
138 static_cast<int>(pos),
static_cast<int>(substringLength));
139 return String16(buffer.get(), substringLength);
141 int startLine()
const override {
return m_startLine; }
142 int startColumn()
const override {
return m_startColumn; }
143 int endLine()
const override {
return m_endLine; }
144 int endColumn()
const override {
return m_endColumn; }
145 bool isSourceLoadedLazily()
const override {
return false; }
146 int length()
const override {
149 if (!script()->Source().ToLocal(&v8Source))
return 0;
150 return v8Source->
Length();
153 const String16& sourceMappingURL()
const override {
154 return m_sourceMappingURL;
157 void setSourceMappingURL(
const String16& sourceMappingURL)
override {
158 m_sourceMappingURL = sourceMappingURL;
161 void setSource(
const String16& newSource,
bool preview,
165 if (!m_script.Get(m_isolate)->SetScriptSource(v8Source, preview, result)) {
166 result->message = scope.Escape(result->message);
171 Initialize(scope.Escape(result->script));
174 bool getPossibleBreakpoints(
176 bool restrictToFunction,
177 std::vector<v8::debug::BreakLocation>* locations)
override {
180 std::vector<v8::debug::BreakLocation> allLocations;
181 if (!script->GetPossibleBreakpoints(start, end, restrictToFunction,
185 if (!allLocations.size())
return true;
187 for (
size_t i = 1;
i < allLocations.size(); ++
i) {
188 if (allLocations[
i].GetLineNumber() == current.GetLineNumber() &&
189 allLocations[
i].GetColumnNumber() == current.GetColumnNumber()) {
190 if (allLocations[
i].type() != v8::debug::kCommonBreakLocation) {
191 DCHECK(allLocations[
i].type() == v8::debug::kCallBreakLocation ||
192 allLocations[
i].type() == v8::debug::kReturnBreakLocation);
197 current = allLocations[
i];
202 allLocations[
i].GetLineNumber() > current.GetLineNumber() ||
203 (allLocations[
i].GetColumnNumber() >= current.GetColumnNumber() &&
204 allLocations[
i].GetLineNumber() == current.GetLineNumber()));
205 locations->push_back(current);
206 current = allLocations[
i];
209 locations->push_back(current);
213 void resetBlackboxedStateCache()
override {
215 v8::debug::ResetBlackboxedStateCache(m_isolate, m_script.Get(m_isolate));
218 int offset(
int lineNumber,
int columnNumber)
const override {
220 return m_script.Get(m_isolate)->GetSourceOffset(
226 return m_script.Get(m_isolate)->GetSourceLocation(offset);
230 int*
id)
const override {
232 return script()->SetBreakpoint(toV8String(m_isolate, condition), location,
236 const String16& hash()
const override {
237 if (m_hash.isEmpty()) {
240 if (script()->Source().ToLocal(&v8Source)) {
241 m_hash = calculateHash(m_isolate, v8Source);
244 DCHECK(!m_hash.isEmpty());
249 String16 GetScriptURL(v8::Isolate* isolate,
251 V8InspectorClient* client) {
253 if (script->SourceURL().ToLocal(&sourceURL) && sourceURL->
Length() > 0)
254 return toProtocolString(isolate, sourceURL);
256 if (script->Name().ToLocal(&v8Name) && v8Name->
Length() > 0) {
257 String16 name = toProtocolString(isolate, v8Name);
258 std::unique_ptr<StringBuffer> url =
259 client->resourceNameToUrl(toStringView(name));
260 return url ? toString16(url->string()) : name;
266 return m_script.Get(m_isolate);
271 m_hasSourceURLComment =
272 script->SourceURL().ToLocal(&tmp) && tmp->
Length() > 0;
273 if (script->SourceMappingURL().ToLocal(&tmp))
274 m_sourceMappingURL = toProtocolString(m_isolate, tmp);
275 m_startLine = script->LineOffset();
276 m_startColumn = script->ColumnOffset();
277 std::vector<int> lineEnds = script->LineEnds();
278 CHECK(lineEnds.size());
279 int source_length = lineEnds[lineEnds.size() - 1];
280 if (lineEnds.size()) {
281 m_endLine =
static_cast<int>(lineEnds.size()) + m_startLine - 1;
282 if (lineEnds.size() > 1) {
283 m_endColumn = source_length - lineEnds[lineEnds.size() - 2] - 1;
285 m_endColumn = source_length + m_startColumn;
288 m_endLine = m_startLine;
289 m_endColumn = m_startColumn;
292 USE(script->ContextId().To(&m_executionContextId));
294 m_isModule = script->IsModule();
296 m_script.Reset(m_isolate, script);
297 m_script.AnnotateStrongRetainer(kGlobalDebuggerScriptHandleLabel);
300 String16 m_sourceMappingURL;
301 bool m_isLiveEdit =
false;
302 bool m_isModule =
false;
303 mutable String16 m_hash;
305 int m_startColumn = 0;
311 class WasmVirtualScript :
public V8DebuggerScript {
312 friend class V8DebuggerScript;
315 WasmVirtualScript(v8::Isolate* isolate, WasmTranslation* wasmTranslation,
317 String16 url,
int functionIndex)
318 : V8DebuggerScript(isolate,
std::move(id),
std::move(url)),
319 m_script(isolate, script),
320 m_wasmTranslation(wasmTranslation),
321 m_functionIndex(functionIndex) {
322 m_script.AnnotateStrongRetainer(kGlobalDebuggerScriptHandleLabel);
323 m_executionContextId = script->ContextId().ToChecked();
326 const String16& sourceMappingURL()
const override {
return emptyString(); }
327 bool isLiveEdit()
const override {
return false; }
328 bool isModule()
const override {
return false; }
329 void setSourceMappingURL(
const String16&)
override {}
333 bool isSourceLoadedLazily()
const override {
return true; }
334 String16 source(
size_t pos,
size_t len)
const override {
335 return m_wasmTranslation->GetSource(m_id, m_functionIndex)
336 .substring(pos, len);
338 int startLine()
const override {
339 return m_wasmTranslation->GetStartLine(m_id, m_functionIndex);
341 int startColumn()
const override {
342 return m_wasmTranslation->GetStartColumn(m_id, m_functionIndex);
344 int endLine()
const override {
345 return m_wasmTranslation->GetEndLine(m_id, m_functionIndex);
347 int endColumn()
const override {
348 return m_wasmTranslation->GetEndColumn(m_id, m_functionIndex);
350 int length()
const override {
351 return static_cast<int>(source(0, UINT_MAX).length());
354 bool getPossibleBreakpoints(
356 bool restrictToFunction,
357 std::vector<v8::debug::BreakLocation>* locations)
override {
360 String16 v8ScriptId = String16::fromInteger(script->Id());
363 TranslateProtocolLocationToV8Location(m_wasmTranslation, &translatedStart,
364 scriptId(), v8ScriptId);
367 if (translatedEnd.IsEmpty()) {
372 TranslateProtocolLocationToV8Location(m_wasmTranslation, &translatedEnd,
373 scriptId(), v8ScriptId);
376 bool success = script->GetPossibleBreakpoints(
377 translatedStart, translatedEnd, restrictToFunction, locations);
379 TranslateV8LocationToProtocolLocation(m_wasmTranslation, &loc, v8ScriptId,
385 void resetBlackboxedStateCache()
override {}
387 int offset(
int lineNumber,
int columnNumber)
const override {
396 int*
id)
const override {
399 String16 v8ScriptId = String16::fromInteger(script->Id());
401 TranslateProtocolLocationToV8Location(m_wasmTranslation, location,
402 scriptId(), v8ScriptId);
403 if (location->IsEmpty())
return false;
404 if (!script->SetBreakpoint(toV8String(m_isolate, condition), location,
id))
406 TranslateV8LocationToProtocolLocation(m_wasmTranslation, location,
407 v8ScriptId, scriptId());
411 const String16& hash()
const override {
412 if (m_hash.isEmpty()) {
413 m_hash = m_wasmTranslation->GetHash(m_id, m_functionIndex);
419 static const String16& emptyString() {
421 static const String16* singleEmptyString =
new String16;
422 return *singleEmptyString;
426 return m_script.Get(m_isolate);
430 WasmTranslation* m_wasmTranslation;
432 mutable String16 m_hash;
437 std::unique_ptr<V8DebuggerScript> V8DebuggerScript::Create(
439 bool isLiveEdit, V8InspectorClient* client) {
440 return std::unique_ptr<ActualScript>(
441 new ActualScript(isolate, scriptObj, isLiveEdit, client));
444 std::unique_ptr<V8DebuggerScript> V8DebuggerScript::CreateWasm(
445 v8::Isolate* isolate, WasmTranslation* wasmTranslation,
447 String16 url,
int functionIndex) {
448 return std::unique_ptr<WasmVirtualScript>(
449 new WasmVirtualScript(isolate, wasmTranslation, underlyingScript,
450 std::move(
id), std::move(url), functionIndex));
453 V8DebuggerScript::V8DebuggerScript(v8::Isolate* isolate, String16
id,
455 : m_id(
std::move(id)), m_url(
std::move(url)), m_isolate(isolate) {}
457 V8DebuggerScript::~V8DebuggerScript() =
default;
459 void V8DebuggerScript::setSourceURL(
const String16& sourceURL) {
460 if (sourceURL.length() > 0) {
461 m_hasSourceURLComment =
true;
466 bool V8DebuggerScript::setBreakpoint(
const String16& condition,
469 return script()->SetBreakpoint(toV8String(m_isolate, condition), loc,
id);