[wasm] Deduplicate wasm scripts

R=clemensb@chromium.org

Bug: v8:6847
Change-Id: I4509a7011a0d32f5bbd2eabf3d2ee6ef5304263d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2124320
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
Reviewed-by: Clemens Backes <clemensb@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66981}
This commit is contained in:
Thibaud Michaud 2020-04-02 15:10:56 +02:00 committed by Commit Bot
parent 1bb1d634e1
commit 6ebccbd1f4
5 changed files with 96 additions and 17 deletions

View File

@ -1604,10 +1604,9 @@ void AsyncCompileJob::PrepareRuntimeObjects() {
DCHECK(module_object_.is_null());
const WasmModule* module = native_module_->module();
auto source_url = stream_ ? stream_->url() : Vector<const char>();
Handle<Script> script = CreateWasmScript(
isolate_, native_module_->wire_bytes(), VectorOf(module->source_map_url),
auto script = isolate_->wasm_engine()->GetOrCreateScript(
isolate_, native_module_.get(), VectorOf(module->source_map_url),
module->name, source_url);
Handle<WasmModuleObject> module_object =
WasmModuleObject::New(isolate_, native_module_, script);

View File

@ -131,6 +131,31 @@ class WasmGCForegroundTask : public CancelableTask {
Isolate* isolate_;
};
class WeakScriptHandle {
public:
explicit WeakScriptHandle(Handle<Script> handle) {
auto global_handle =
handle->GetIsolate()->global_handles()->Create(*handle);
location_ = std::make_unique<Address*>(global_handle.location());
GlobalHandles::MakeWeak(location_.get());
}
WeakScriptHandle(WeakScriptHandle&&) V8_NOEXCEPT = default;
~WeakScriptHandle() {
if (location_) {
GlobalHandles::Destroy(*location_);
}
}
Handle<Script> handle() { return Handle<Script>(*location_); }
private:
// Store the location in a unique_ptr so that its address stays the same even
// when this object is moved/copied.
std::unique_ptr<Address*> location_;
};
} // namespace
std::shared_ptr<NativeModule> NativeModuleCache::MaybeGetNativeModule(
@ -320,6 +345,9 @@ struct WasmEngine::IsolateInfo {
// grows, never shrinks).
std::set<NativeModule*> native_modules;
// Scripts created for each native module in this isolate.
std::unordered_map<NativeModule*, WeakScriptHandle> scripts;
// Caches whether code needs to be logged on this isolate.
bool log_codes;
@ -462,9 +490,9 @@ MaybeHandle<WasmModuleObject> WasmEngine::SyncCompile(
#endif
Handle<Script> script =
CreateWasmScript(isolate, bytes.module_bytes(),
VectorOf(native_module->module()->source_map_url),
native_module->module()->name);
GetOrCreateScript(isolate, native_module.get(),
VectorOf(native_module->module()->source_map_url),
native_module->module()->name);
// Create the compiled module object and populate with compiled functions
// and information needed at instantiation time. This object needs to be
@ -928,6 +956,7 @@ void WasmEngine::FreeNativeModule(NativeModule* native_module) {
IsolateInfo* info = isolates_[isolate].get();
DCHECK_EQ(1, info->native_modules.count(native_module));
info->native_modules.erase(native_module);
info->scripts.erase(native_module);
// If there are {WasmCode} objects of the deleted {NativeModule}
// outstanding to be logged in this isolate, remove them. Decrementing the
// ref count is not needed, since the {NativeModule} dies anyway.
@ -1089,6 +1118,29 @@ void WasmEngine::FreeDeadCodeLocked(const DeadCodeMap& dead_code) {
}
}
Handle<Script> WasmEngine::GetOrCreateScript(Isolate* isolate,
NativeModule* native_module,
Vector<const char> source_map_url,
WireBytesRef name,
Vector<const char> source_url) {
base::MutexGuard guard(&mutex_);
DCHECK_EQ(1, isolates_.count(isolate));
auto& scripts = isolates_[isolate]->scripts;
auto it = scripts.find(native_module);
if (it != scripts.end()) {
Handle<Script> weak_global_handle = it->second.handle();
if (weak_global_handle.is_null()) {
scripts.erase(it);
} else {
return Handle<Script>::New(*weak_global_handle, isolate);
}
}
auto script = CreateWasmScript(isolate, native_module->wire_bytes(),
source_map_url, name, source_url);
scripts.emplace(native_module, WeakScriptHandle(script));
return script;
}
void WasmEngine::TriggerGC(int8_t gc_sequence_index) {
DCHECK_NULL(current_gc_info_);
DCHECK(FLAG_wasm_code_gc);

View File

@ -335,6 +335,11 @@ class V8_EXPORT_PRIVATE WasmEngine {
void FreeDeadCode(const DeadCodeMap&);
void FreeDeadCodeLocked(const DeadCodeMap&);
Handle<Script> GetOrCreateScript(Isolate*, NativeModule*,
Vector<const char> source_map_url,
WireBytesRef name,
Vector<const char> source_url = {});
// Call on process start and exit.
static void InitializeOncePerProcess();
static void GlobalTearDown();

View File

@ -1,15 +1,25 @@
Tests how wasm scripts are reported
Check that each inspector gets a wasm script at module creation time.
Session #1: Script #0 parsed. URL: wasm://wasm/7b04570e. Source map URL: , module begin: 0, module end: 0, code offset: 34
Session #2: Script #0 parsed. URL: wasm://wasm/7b04570e. Source map URL: , module begin: 0, module end: 0, code offset: 34
Session #1: Script #1 parsed. URL: wasm://wasm/ba7c35be. Source map URL: wasm://dwarf, module begin: 0, module end: 0, code offset: 34
Session #2: Script #1 parsed. URL: wasm://wasm/ba7c35be. Source map URL: wasm://dwarf, module begin: 0, module end: 0, code offset: 34
Session #1: Script #2 parsed. URL: wasm://wasm/1baa71fe. Source map URL: abc, module begin: 0, module end: 0, code offset: 34
Session #2: Script #2 parsed. URL: wasm://wasm/1baa71fe. Source map URL: abc, module begin: 0, module end: 0, code offset: 34
Session #1: Script #3 parsed. URL: wasm://wasm/95e97206. Source map URL: abc, module begin: 0, module end: 0, code offset: 34
Session #2: Script #3 parsed. URL: wasm://wasm/95e97206. Source map URL: abc, module begin: 0, module end: 0, code offset: 34
Session #1: Script #4 parsed. URL: wasm://wasm/7ab47392. Source map URL: abc, module begin: 0, module end: 0, code offset: 34
Session #2: Script #4 parsed. URL: wasm://wasm/7ab47392. Source map URL: abc, module begin: 0, module end: 0, code offset: 34
Session #1: Script #0 parsed. URL: wasm://wasm/7b04570e. Script ID: 0, Source map URL: , module begin: 0, module end: 0, code offset: 34
Session #2: Script #0 parsed. URL: wasm://wasm/7b04570e. Script ID: 0, Source map URL: , module begin: 0, module end: 0, code offset: 34
Session #1: Script #1 parsed. URL: wasm://wasm/7b04570e. Script ID: 0, Source map URL: , module begin: 0, module end: 0, code offset: 34
Session #2: Script #1 parsed. URL: wasm://wasm/7b04570e. Script ID: 0, Source map URL: , module begin: 0, module end: 0, code offset: 34
Session #1: Script #2 parsed. URL: wasm://wasm/ba7c35be. Script ID: 1, Source map URL: wasm://dwarf, module begin: 0, module end: 0, code offset: 34
Session #2: Script #2 parsed. URL: wasm://wasm/ba7c35be. Script ID: 1, Source map URL: wasm://dwarf, module begin: 0, module end: 0, code offset: 34
Session #1: Script #3 parsed. URL: wasm://wasm/1baa71fe. Script ID: 2, Source map URL: abc, module begin: 0, module end: 0, code offset: 34
Session #2: Script #3 parsed. URL: wasm://wasm/1baa71fe. Script ID: 2, Source map URL: abc, module begin: 0, module end: 0, code offset: 34
Session #1: Script #4 parsed. URL: wasm://wasm/95e97206. Script ID: 3, Source map URL: abc, module begin: 0, module end: 0, code offset: 34
Session #2: Script #4 parsed. URL: wasm://wasm/95e97206. Script ID: 3, Source map URL: abc, module begin: 0, module end: 0, code offset: 34
Session #1: Script #5 parsed. URL: wasm://wasm/7ab47392. Script ID: 4, Source map URL: abc, module begin: 0, module end: 0, code offset: 34
Session #2: Script #5 parsed. URL: wasm://wasm/7ab47392. Script ID: 4, Source map URL: abc, module begin: 0, module end: 0, code offset: 34
Session #1: Source for wasm://wasm/7b04570e:
Raw: 00 61 73 6d 01 00 00 00 01 07 02 60 00 00 60 00 00 03 03 02 00 01 07 08 01 04 6d 61 69 6e 00 01 0a 0e 02 03 00 01 0b 08 00 02 40 41 02 1a 0b 0b 00 1b 04 6e 61 6d 65 01 14 02 00 0b 6e 6f 70 46 75 6e 63 74 69 6f 6e 01 04 6d 61 69 6e
Imports: []
Exports: [main: function]
Session #2: Source for wasm://wasm/7b04570e:
Raw: 00 61 73 6d 01 00 00 00 01 07 02 60 00 00 60 00 00 03 03 02 00 01 07 08 01 04 6d 61 69 6e 00 01 0a 0e 02 03 00 01 0b 08 00 02 40 41 02 1a 0b 0b 00 1b 04 6e 61 6d 65 01 14 02 00 0b 6e 6f 70 46 75 6e 63 74 69 6f 6e 01 04 6d 61 69 6e
Imports: []
Exports: [main: function]
Session #1: Source for wasm://wasm/7b04570e:
Raw: 00 61 73 6d 01 00 00 00 01 07 02 60 00 00 60 00 00 03 03 02 00 01 07 08 01 04 6d 61 69 6e 00 01 0a 0e 02 03 00 01 0b 08 00 02 40 41 02 1a 0b 0b 00 1b 04 6e 61 6d 65 01 14 02 00 0b 6e 6f 70 46 75 6e 63 74 69 6f 6e 01 04 6d 61 69 6e
Imports: []

View File

@ -35,6 +35,15 @@ function testFunction(bytes) {
new WebAssembly.Module(new Uint8Array(bytes));
}
// Generate stable IDs.
let scriptIds = {};
function nextStableId(id) {
if (!(id in scriptIds)) {
scriptIds[id] = Object.keys(scriptIds).length;
}
return scriptIds[id];
}
contextGroup.addScript(testFunction.toString(), 0, 0, 'v8://test/testFunction');
InspectorTest.log(
@ -55,6 +64,9 @@ sessions[0].Protocol.Runtime
// no debug info
testFunction([${createModule()}]);
// shared script for identical modules
testFunction([${createModule()}]);
// DWARF
testFunction([${createModule(dwarfSection)}]);
@ -87,8 +99,9 @@ function trackScripts(debuggerParams) {
async function loadScript(
{url, scriptId, sourceMapURL, startColumn, endColumn, codeOffset}) {
let stableId = nextStableId(scriptId);
InspectorTest.log(`Session #${sessionId}: Script #${
scripts.length} parsed. URL: ${url}. Source map URL: ${
scripts.length} parsed. URL: ${url}. Script ID: ${stableId}, Source map URL: ${
sourceMapURL}, module begin: ${startColumn}, module end: ${endColumn}, code offset: ${codeOffset}`);
let {result: {scriptSource, bytecode}} =
await Protocol.Debugger.getScriptSource({scriptId});