diff options
Diffstat (limited to 'toolkit/components/extensions/ProfilerGetSymbols-worker.js')
-rw-r--r-- | toolkit/components/extensions/ProfilerGetSymbols-worker.js | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/toolkit/components/extensions/ProfilerGetSymbols-worker.js b/toolkit/components/extensions/ProfilerGetSymbols-worker.js new file mode 100644 index 0000000000..f4a10da629 --- /dev/null +++ b/toolkit/components/extensions/ProfilerGetSymbols-worker.js @@ -0,0 +1,127 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* eslint-env mozilla/chrome-worker */ + +"use strict"; + +importScripts( + "resource://gre/modules/osfile.jsm", + "resource://gre/modules/profiler_get_symbols.js" +); + +// This worker uses the wasm module that was generated from https://github.com/mstange/profiler-get-symbols. +// See ProfilerGetSymbols.jsm for more information. +// +// The worker instantiates the module, reads the binary into wasm memory, runs +// the wasm code, and returns the symbol table or an error. Then it shuts down +// itself. + +const { WasmMemBuffer, get_compact_symbol_table } = wasm_bindgen; + +// Read an open OS.File instance into the Uint8Array dataBuf. +function readFileInto(file, dataBuf) { + // Ideally we'd be able to call file.readTo(dataBuf) here, but readTo no + // longer exists. + // So instead, we copy the file over into wasm memory in 4MB chunks. This + // will take 425 invocations for a a 1.7GB file (such as libxul.so for a + // Firefox for Android build) and not take up too much memory per call. + const dataBufLen = dataBuf.byteLength; + const chunkSize = 4 * 1024 * 1024; + let pos = 0; + while (pos < dataBufLen) { + const chunkData = file.read({ bytes: chunkSize }); + const chunkBytes = chunkData.byteLength; + if (chunkBytes === 0) { + break; + } + + dataBuf.set(chunkData, pos); + pos += chunkBytes; + } +} + +// Returns a plain object that is Structured Cloneable and has name and +// description properties. +function createPlainErrorObject(e) { + // OS.File.Error has an empty message property; it constructs the error + // message on-demand in its toString() method. So we handle those errors + // specially. + if (!(e instanceof OS.File.Error)) { + // Regular errors: just rewrap the object. + if (e instanceof Error) { + const { name, message, fileName, lineNumber } = e; + return { name, message, fileName, lineNumber }; + } + // The WebAssembly code throws errors with fields error_type and error_msg. + if (e.error_type) { + return { + name: e.error_type, + message: e.error_msg, + }; + } + } + + return { + name: e instanceof OS.File.Error ? "OSFileError" : "Error", + message: e.toString(), + fileName: e.fileName, + lineNumber: e.lineNumber, + }; +} + +onmessage = async e => { + try { + const { binaryPath, debugPath, breakpadId, module } = e.data; + + if (!(module instanceof WebAssembly.Module)) { + throw new Error("invalid WebAssembly module"); + } + + // Instantiate the WASM module. + await wasm_bindgen(module); + + // Read the binary file into WASM memory. + const binaryFile = OS.File.open(binaryPath, { read: true }); + const binaryData = new WasmMemBuffer(binaryFile.stat().size, array => { + readFileInto(binaryFile, array); + }); + binaryFile.close(); + + // Do the same for the debug file, if it is supplied and different from the + // binary file. This is only the case on Windows. + let debugData = binaryData; + if (debugPath && debugPath !== binaryPath) { + const debugFile = OS.File.open(debugPath, { read: true }); + debugData = new WasmMemBuffer(debugFile.stat().size, array => { + readFileInto(debugFile, array); + }); + debugFile.close(); + } + + try { + let output = get_compact_symbol_table(binaryData, debugData, breakpadId); + const result = [ + output.take_addr(), + output.take_index(), + output.take_buffer(), + ]; + output.free(); + postMessage( + { result }, + result.map(r => r.buffer) + ); + } finally { + binaryData.free(); + if (debugData != binaryData) { + debugData.free(); + } + } + } catch (error) { + postMessage({ error: createPlainErrorObject(error) }); + } + close(); +}; |