Commit cee2946f authored by Stephan Herhut's avatar Stephan Herhut Committed by Commit Bot

Lazily generate disassembly for WASM functions

Instead of computing the disassmebly and offset tables eagerly on
registering a WASM function with a debugger agent, only generate
it when the source or offset tables are actually required. This is
implemented using a lazy, memoizing supplier that is shared
between the debugger agent and wasm translator.

Bug: chromium:794941
Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel;master.tryserver.chromium.linux:linux_chromium_rel_ng
Change-Id: I1a2f7dd71ab65c80f91ddee4f7babbdf33d2e74b
Reviewed-on: https://chromium-review.googlesource.com/918641
Commit-Queue: Stephan Herhut <herhut@chromium.org>
Reviewed-by: 's avatarDmitry Gozman <dgozman@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51762}
parent db5affec
...@@ -69,6 +69,7 @@ ...@@ -69,6 +69,7 @@
#include "src/snapshot/natives.h" #include "src/snapshot/natives.h"
#include "src/snapshot/snapshot.h" #include "src/snapshot/snapshot.h"
#include "src/startup-data-util.h" #include "src/startup-data-util.h"
#include "src/string-hasher.h"
#include "src/tracing/trace-event.h" #include "src/tracing/trace-event.h"
#include "src/trap-handler/trap-handler.h" #include "src/trap-handler/trap-handler.h"
#include "src/unicode-cache-inl.h" #include "src/unicode-cache-inl.h"
...@@ -9467,6 +9468,25 @@ std::pair<int, int> debug::WasmScript::GetFunctionRange( ...@@ -9467,6 +9468,25 @@ std::pair<int, int> debug::WasmScript::GetFunctionRange(
static_cast<int>(func.code.end_offset())); static_cast<int>(func.code.end_offset()));
} }
uint32_t debug::WasmScript::GetFunctionHash(int function_index) {
i::DisallowHeapAllocation no_gc;
i::Handle<i::Script> script = Utils::OpenHandle(this);
DCHECK_EQ(i::Script::TYPE_WASM, script->type());
i::WasmCompiledModule* compiled_module =
i::WasmCompiledModule::cast(script->wasm_compiled_module());
i::wasm::WasmModule* module = compiled_module->shared()->module();
DCHECK_LE(0, function_index);
DCHECK_GT(module->functions.size(), function_index);
i::wasm::WasmFunction& func = module->functions[function_index];
i::SeqOneByteString* module_bytes = compiled_module->shared()->module_bytes();
i::wasm::ModuleWireBytes wire_bytes(
module_bytes->GetFlatContent().ToOneByteVector());
i::Vector<const i::byte> function_bytes = wire_bytes.GetFunctionBytes(&func);
// TODO(herhut): Maybe also take module, name and signature into account.
return i::StringHasher::HashSequentialString(function_bytes.start(),
function_bytes.length(), 0);
}
debug::WasmDisassembly debug::WasmScript::DisassembleFunction( debug::WasmDisassembly debug::WasmScript::DisassembleFunction(
int function_index) const { int function_index) const {
i::DisallowHeapAllocation no_gc; i::DisallowHeapAllocation no_gc;
......
...@@ -166,6 +166,7 @@ class WasmScript : public Script { ...@@ -166,6 +166,7 @@ class WasmScript : public Script {
std::pair<int, int> GetFunctionRange(int function_index) const; std::pair<int, int> GetFunctionRange(int function_index) const;
debug::WasmDisassembly DisassembleFunction(int function_index) const; debug::WasmDisassembly DisassembleFunction(int function_index) const;
uint32_t GetFunctionHash(int function_index);
}; };
void GetLoadedScripts(Isolate* isolate, PersistentValueVector<Script>& scripts); void GetLoadedScripts(Isolate* isolate, PersistentValueVector<Script>& scripts);
......
...@@ -493,22 +493,39 @@ void String16Builder::append(const char* characters, size_t length) { ...@@ -493,22 +493,39 @@ void String16Builder::append(const char* characters, size_t length) {
} }
void String16Builder::appendNumber(int number) { void String16Builder::appendNumber(int number) {
const int kBufferSize = 11; constexpr int kBufferSize = 11;
char buffer[kBufferSize]; char buffer[kBufferSize];
int chars = v8::base::OS::SNPrintF(buffer, kBufferSize, "%d", number); int chars = v8::base::OS::SNPrintF(buffer, kBufferSize, "%d", number);
DCHECK_GT(kBufferSize, chars); DCHECK_LE(0, chars);
m_buffer.insert(m_buffer.end(), buffer, buffer + chars); m_buffer.insert(m_buffer.end(), buffer, buffer + chars);
} }
void String16Builder::appendNumber(size_t number) { void String16Builder::appendNumber(size_t number) {
const int kBufferSize = 20; constexpr int kBufferSize = 20;
char buffer[kBufferSize]; char buffer[kBufferSize];
#if !defined(_WIN32) && !defined(_WIN64) #if !defined(_WIN32) && !defined(_WIN64)
int chars = v8::base::OS::SNPrintF(buffer, kBufferSize, "%zu", number); int chars = v8::base::OS::SNPrintF(buffer, kBufferSize, "%zu", number);
#else #else
int chars = v8::base::OS::SNPrintF(buffer, kBufferSize, "%Iu", number); int chars = v8::base::OS::SNPrintF(buffer, kBufferSize, "%Iu", number);
#endif #endif
DCHECK_GT(kBufferSize, chars); DCHECK_LE(0, chars);
m_buffer.insert(m_buffer.end(), buffer, buffer + chars);
}
void String16Builder::appendUnsignedAsHex(uint64_t number) {
constexpr int kBufferSize = 17;
char buffer[kBufferSize];
int chars =
v8::base::OS::SNPrintF(buffer, kBufferSize, "%016" PRIx64, number);
DCHECK_LE(0, chars);
m_buffer.insert(m_buffer.end(), buffer, buffer + chars);
}
void String16Builder::appendUnsignedAsHex(uint32_t number) {
constexpr int kBufferSize = 9;
char buffer[kBufferSize];
int chars = v8::base::OS::SNPrintF(buffer, kBufferSize, "%08" PRIx32, number);
DCHECK_LE(0, chars);
m_buffer.insert(m_buffer.end(), buffer, buffer + chars); m_buffer.insert(m_buffer.end(), buffer, buffer + chars);
} }
......
...@@ -112,6 +112,8 @@ class String16Builder { ...@@ -112,6 +112,8 @@ class String16Builder {
void append(const char*, size_t); void append(const char*, size_t);
void appendNumber(int); void appendNumber(int);
void appendNumber(size_t); void appendNumber(size_t);
void appendUnsignedAsHex(uint64_t);
void appendUnsignedAsHex(uint32_t);
String16 toString(); String16 toString();
void reserveCapacity(size_t); void reserveCapacity(size_t);
......
...@@ -156,9 +156,8 @@ String16 breakpointHint(const V8DebuggerScript& script, int lineNumber, ...@@ -156,9 +156,8 @@ String16 breakpointHint(const V8DebuggerScript& script, int lineNumber,
return hint; return hint;
} }
void adjustBreakpointLocation(const V8DebuggerScript& script, void adjustBreakpointLocation(V8DebuggerScript& script, const String16& hint,
const String16& hint, int* lineNumber, int* lineNumber, int* columnNumber) {
int* columnNumber) {
if (*lineNumber < script.startLine() || *lineNumber > script.endLine()) if (*lineNumber < script.startLine() || *lineNumber > script.endLine())
return; return;
if (hint.isEmpty()) return; if (hint.isEmpty()) return;
...@@ -467,7 +466,7 @@ Response V8DebuggerAgentImpl::setSkipAllPauses(bool skip) { ...@@ -467,7 +466,7 @@ Response V8DebuggerAgentImpl::setSkipAllPauses(bool skip) {
return Response::OK(); return Response::OK();
} }
static bool matches(V8InspectorImpl* inspector, const V8DebuggerScript& script, static bool matches(V8InspectorImpl* inspector, V8DebuggerScript& script,
BreakpointType type, const String16& selector) { BreakpointType type, const String16& selector) {
switch (type) { switch (type) {
case BreakpointType::kByUrl: case BreakpointType::kByUrl:
...@@ -1357,10 +1356,12 @@ bool V8DebuggerAgentImpl::isPaused() const { ...@@ -1357,10 +1356,12 @@ bool V8DebuggerAgentImpl::isPaused() const {
void V8DebuggerAgentImpl::didParseSource( void V8DebuggerAgentImpl::didParseSource(
std::unique_ptr<V8DebuggerScript> script, bool success) { std::unique_ptr<V8DebuggerScript> script, bool success) {
v8::HandleScope handles(m_isolate); v8::HandleScope handles(m_isolate);
String16 scriptSource = script->source(); if (!success) {
if (!success) script->setSourceURL(findSourceURL(scriptSource, false)); DCHECK(!script->isSourceLoadedLazily());
if (!success) String16 scriptSource = script->source();
script->setSourceURL(findSourceURL(scriptSource, false));
script->setSourceMappingURL(findSourceMapURL(scriptSource, false)); script->setSourceMappingURL(findSourceMapURL(scriptSource, false));
}
int contextId = script->executionContextId(); int contextId = script->executionContextId();
int contextGroupId = m_inspector->contextGroupId(contextId); int contextGroupId = m_inspector->contextGroupId(contextId);
...@@ -1402,13 +1403,23 @@ void V8DebuggerAgentImpl::didParseSource( ...@@ -1402,13 +1403,23 @@ void V8DebuggerAgentImpl::didParseSource(
stack && !stack->isEmpty() ? stack->buildInspectorObjectImpl(m_debugger) stack && !stack->isEmpty() ? stack->buildInspectorObjectImpl(m_debugger)
: nullptr; : nullptr;
if (success) { if (success) {
m_frontend.scriptParsed( // TODO(herhut, dgozman): Report correct length for WASM if needed for
scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(), // coverage. Or do not send the length at all and change coverage instead.
scriptRef->endLine(), scriptRef->endColumn(), contextId, if (scriptRef->isSourceLoadedLazily()) {
scriptRef->hash(), std::move(executionContextAuxDataParam), m_frontend.scriptParsed(
isLiveEditParam, std::move(sourceMapURLParam), hasSourceURLParam, scriptId, scriptURL, 0, 0, 0, 0, contextId, scriptRef->hash(),
isModuleParam, static_cast<int>(scriptRef->source().length()), std::move(executionContextAuxDataParam), isLiveEditParam,
std::move(stackTrace)); std::move(sourceMapURLParam), hasSourceURLParam, isModuleParam, 0,
std::move(stackTrace));
} else {
m_frontend.scriptParsed(
scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(),
scriptRef->endLine(), scriptRef->endColumn(), contextId,
scriptRef->hash(), std::move(executionContextAuxDataParam),
isLiveEditParam, std::move(sourceMapURLParam), hasSourceURLParam,
isModuleParam, static_cast<int>(scriptRef->source().length()),
std::move(stackTrace));
}
} else { } else {
m_frontend.scriptFailedToParse( m_frontend.scriptFailedToParse(
scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(), scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(),
......
...@@ -16,10 +16,10 @@ namespace { ...@@ -16,10 +16,10 @@ namespace {
const char hexDigits[17] = "0123456789ABCDEF"; const char hexDigits[17] = "0123456789ABCDEF";
const char kGlobalDebuggerScriptHandleLabel[] = "DevTools debugger"; const char kGlobalDebuggerScriptHandleLabel[] = "DevTools debugger";
void appendUnsignedAsHex(uint64_t number, String16Builder* destination) { void appendUnsignedAsHex(uint64_t number, String16Builder& destination) {
for (size_t i = 0; i < 8; ++i) { for (size_t i = 0; i < 8; ++i) {
UChar c = hexDigits[number & 0xF]; UChar c = hexDigits[number & 0xF];
destination->append(c); destination.append(c);
number >>= 4; number >>= 4;
} }
} }
...@@ -82,7 +82,8 @@ String16 calculateHash(const String16& str) { ...@@ -82,7 +82,8 @@ String16 calculateHash(const String16& str) {
hashes[i] = (hashes[i] + zi[i] * (prime[i] - 1)) % prime[i]; hashes[i] = (hashes[i] + zi[i] * (prime[i] - 1)) % prime[i];
String16Builder hash; String16Builder hash;
for (size_t i = 0; i < hashesSize; ++i) appendUnsignedAsHex(hashes[i], &hash); // TODO(herhut): Use String16Builder.appendUnsignedAsHex.
for (size_t i = 0; i < hashesSize; ++i) appendUnsignedAsHex(hashes[i], hash);
return hash.toString(); return hash.toString();
} }
...@@ -157,6 +158,13 @@ class ActualScript : public V8DebuggerScript { ...@@ -157,6 +158,13 @@ class ActualScript : public V8DebuggerScript {
bool isLiveEdit() const override { return m_isLiveEdit; } bool isLiveEdit() const override { return m_isLiveEdit; }
bool isModule() const override { return m_isModule; } bool isModule() const override { return m_isModule; }
const String16& source() const override { return m_source; }
int startLine() const override { return m_startLine; }
int startColumn() const override { return m_startColumn; }
int endLine() const override { return m_endLine; }
int endColumn() const override { return m_endColumn; }
bool isSourceLoadedLazily() const override { return false; }
const String16& sourceMappingURL() const override { const String16& sourceMappingURL() const override {
return m_sourceMappingURL; return m_sourceMappingURL;
} }
...@@ -241,6 +249,12 @@ class ActualScript : public V8DebuggerScript { ...@@ -241,6 +249,12 @@ class ActualScript : public V8DebuggerScript {
id); id);
} }
const String16& hash() override {
if (m_hash.isEmpty()) m_hash = calculateHash(source());
DCHECK(!m_hash.isEmpty());
return m_hash;
}
private: private:
String16 GetNameOrSourceUrl(v8::Local<v8::debug::Script> script) { String16 GetNameOrSourceUrl(v8::Local<v8::debug::Script> script) {
v8::Local<v8::String> name; v8::Local<v8::String> name;
...@@ -256,6 +270,12 @@ class ActualScript : public V8DebuggerScript { ...@@ -256,6 +270,12 @@ class ActualScript : public V8DebuggerScript {
String16 m_sourceMappingURL; String16 m_sourceMappingURL;
bool m_isLiveEdit = false; bool m_isLiveEdit = false;
bool m_isModule = false; bool m_isModule = false;
String16 m_source;
mutable String16 m_hash;
int m_startLine = 0;
int m_startColumn = 0;
int m_endLine = 0;
int m_endColumn = 0;
v8::Global<v8::debug::Script> m_script; v8::Global<v8::debug::Script> m_script;
}; };
...@@ -265,22 +285,12 @@ class WasmVirtualScript : public V8DebuggerScript { ...@@ -265,22 +285,12 @@ class WasmVirtualScript : public V8DebuggerScript {
public: public:
WasmVirtualScript(v8::Isolate* isolate, WasmTranslation* wasmTranslation, WasmVirtualScript(v8::Isolate* isolate, WasmTranslation* wasmTranslation,
v8::Local<v8::debug::WasmScript> script, String16 id, v8::Local<v8::debug::WasmScript> script, String16 id,
String16 url, String16 source) String16 url, int functionIndex)
: V8DebuggerScript(isolate, std::move(id), std::move(url)), : V8DebuggerScript(isolate, std::move(id), std::move(url)),
m_script(isolate, script), m_script(isolate, script),
m_wasmTranslation(wasmTranslation) { m_wasmTranslation(wasmTranslation),
m_functionIndex(functionIndex) {
m_script.AnnotateStrongRetainer(kGlobalDebuggerScriptHandleLabel); m_script.AnnotateStrongRetainer(kGlobalDebuggerScriptHandleLabel);
int num_lines = 0;
int last_newline = -1;
size_t next_newline = source.find('\n', last_newline + 1);
while (next_newline != String16::kNotFound) {
last_newline = static_cast<int>(next_newline);
next_newline = source.find('\n', last_newline + 1);
++num_lines;
}
m_endLine = num_lines;
m_endColumn = static_cast<int>(source.length()) - last_newline - 1;
m_source = std::move(source);
m_executionContextId = script->ContextId().ToChecked(); m_executionContextId = script->ContextId().ToChecked();
} }
...@@ -289,6 +299,22 @@ class WasmVirtualScript : public V8DebuggerScript { ...@@ -289,6 +299,22 @@ class WasmVirtualScript : public V8DebuggerScript {
bool isModule() const override { return false; } bool isModule() const override { return false; }
void setSourceMappingURL(const String16&) override {} void setSourceMappingURL(const String16&) override {}
void setSource(const String16&, bool, bool*) override { UNREACHABLE(); } void setSource(const String16&, bool, bool*) override { UNREACHABLE(); }
bool isSourceLoadedLazily() const override { return true; }
const String16& source() const override {
return m_wasmTranslation->GetSource(m_id, m_functionIndex);
}
int startLine() const override {
return m_wasmTranslation->GetStartLine(m_id, m_functionIndex);
}
int startColumn() const override {
return m_wasmTranslation->GetStartColumn(m_id, m_functionIndex);
}
int endLine() const override {
return m_wasmTranslation->GetEndLine(m_id, m_functionIndex);
}
int endColumn() const override {
return m_wasmTranslation->GetEndColumn(m_id, m_functionIndex);
}
bool getPossibleBreakpoints( bool getPossibleBreakpoints(
const v8::debug::Location& start, const v8::debug::Location& end, const v8::debug::Location& start, const v8::debug::Location& end,
...@@ -347,6 +373,13 @@ class WasmVirtualScript : public V8DebuggerScript { ...@@ -347,6 +373,13 @@ class WasmVirtualScript : public V8DebuggerScript {
return true; return true;
} }
const String16& hash() override {
if (m_hash.isEmpty()) {
m_hash = m_wasmTranslation->GetHash(m_id, m_functionIndex);
}
return m_hash;
}
private: private:
static const String16& emptyString() { static const String16& emptyString() {
static const String16 singleEmptyString; static const String16 singleEmptyString;
...@@ -359,6 +392,8 @@ class WasmVirtualScript : public V8DebuggerScript { ...@@ -359,6 +392,8 @@ class WasmVirtualScript : public V8DebuggerScript {
v8::Global<v8::debug::WasmScript> m_script; v8::Global<v8::debug::WasmScript> m_script;
WasmTranslation* m_wasmTranslation; WasmTranslation* m_wasmTranslation;
int m_functionIndex;
mutable String16 m_hash;
}; };
} // namespace } // namespace
...@@ -373,10 +408,10 @@ std::unique_ptr<V8DebuggerScript> V8DebuggerScript::Create( ...@@ -373,10 +408,10 @@ std::unique_ptr<V8DebuggerScript> V8DebuggerScript::Create(
std::unique_ptr<V8DebuggerScript> V8DebuggerScript::CreateWasm( std::unique_ptr<V8DebuggerScript> V8DebuggerScript::CreateWasm(
v8::Isolate* isolate, WasmTranslation* wasmTranslation, v8::Isolate* isolate, WasmTranslation* wasmTranslation,
v8::Local<v8::debug::WasmScript> underlyingScript, String16 id, v8::Local<v8::debug::WasmScript> underlyingScript, String16 id,
String16 url, String16 source) { String16 url, int functionIndex) {
return std::unique_ptr<WasmVirtualScript>( return std::unique_ptr<WasmVirtualScript>(
new WasmVirtualScript(isolate, wasmTranslation, underlyingScript, new WasmVirtualScript(isolate, wasmTranslation, underlyingScript,
std::move(id), std::move(url), std::move(source))); std::move(id), std::move(url), functionIndex));
} }
V8DebuggerScript::V8DebuggerScript(v8::Isolate* isolate, String16 id, V8DebuggerScript::V8DebuggerScript(v8::Isolate* isolate, String16 id,
...@@ -389,12 +424,6 @@ const String16& V8DebuggerScript::sourceURL() const { ...@@ -389,12 +424,6 @@ const String16& V8DebuggerScript::sourceURL() const {
return m_sourceURL.isEmpty() ? m_url : m_sourceURL; return m_sourceURL.isEmpty() ? m_url : m_sourceURL;
} }
const String16& V8DebuggerScript::hash() const {
if (m_hash.isEmpty()) m_hash = calculateHash(source());
DCHECK(!m_hash.isEmpty());
return m_hash;
}
void V8DebuggerScript::setSourceURL(const String16& sourceURL) { void V8DebuggerScript::setSourceURL(const String16& sourceURL) {
m_sourceURL = sourceURL; m_sourceURL = sourceURL;
} }
......
...@@ -50,7 +50,7 @@ class V8DebuggerScript { ...@@ -50,7 +50,7 @@ class V8DebuggerScript {
static std::unique_ptr<V8DebuggerScript> CreateWasm( static std::unique_ptr<V8DebuggerScript> CreateWasm(
v8::Isolate* isolate, WasmTranslation* wasmTranslation, v8::Isolate* isolate, WasmTranslation* wasmTranslation,
v8::Local<v8::debug::WasmScript> underlyingScript, String16 id, v8::Local<v8::debug::WasmScript> underlyingScript, String16 id,
String16 url, String16 source); String16 url, int functionIndex);
virtual ~V8DebuggerScript(); virtual ~V8DebuggerScript();
...@@ -59,15 +59,16 @@ class V8DebuggerScript { ...@@ -59,15 +59,16 @@ class V8DebuggerScript {
bool hasSourceURL() const { return !m_sourceURL.isEmpty(); } bool hasSourceURL() const { return !m_sourceURL.isEmpty(); }
const String16& sourceURL() const; const String16& sourceURL() const;
virtual const String16& sourceMappingURL() const = 0; virtual const String16& sourceMappingURL() const = 0;
const String16& source() const { return m_source; } virtual const String16& source() const = 0;
const String16& hash() const; virtual const String16& hash() = 0;
int startLine() const { return m_startLine; } virtual int startLine() const = 0;
int startColumn() const { return m_startColumn; } virtual int startColumn() const = 0;
int endLine() const { return m_endLine; } virtual int endLine() const = 0;
int endColumn() const { return m_endColumn; } virtual int endColumn() const = 0;
int executionContextId() const { return m_executionContextId; } int executionContextId() const { return m_executionContextId; }
virtual bool isLiveEdit() const = 0; virtual bool isLiveEdit() const = 0;
virtual bool isModule() const = 0; virtual bool isModule() const = 0;
virtual bool isSourceLoadedLazily() const = 0;
void setSourceURL(const String16&); void setSourceURL(const String16&);
virtual void setSourceMappingURL(const String16&) = 0; virtual void setSourceMappingURL(const String16&) = 0;
...@@ -95,12 +96,6 @@ class V8DebuggerScript { ...@@ -95,12 +96,6 @@ class V8DebuggerScript {
String16 m_id; String16 m_id;
String16 m_url; String16 m_url;
String16 m_sourceURL; String16 m_sourceURL;
String16 m_source;
mutable String16 m_hash;
int m_startLine = 0;
int m_startColumn = 0;
int m_endLine = 0;
int m_endColumn = 0;
int m_executionContextId = 0; int m_executionContextId = 0;
v8::Isolate* m_isolate; v8::Isolate* m_isolate;
......
This diff is collapsed.
...@@ -56,6 +56,13 @@ class WasmTranslation { ...@@ -56,6 +56,13 @@ class WasmTranslation {
int* line_number, int* line_number,
int* column_number); int* column_number);
const String16& GetSource(const String16& script_id, int func_index);
int GetStartLine(const String16& script_id, int func_index) { return 0; }
int GetStartColumn(const String16& script_id, int func_index) { return 0; }
int GetEndLine(const String16& script_id, int func_index);
int GetEndColumn(const String16& script_id, int func_index);
String16 GetHash(const String16& script_id, int func_index);
private: private:
class TranslatorImpl; class TranslatorImpl;
friend class TranslatorImpl; friend class TranslatorImpl;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment