From 1655f395f2ad74128813ae462b10c619ee09385c Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Sun, 19 Aug 2018 12:23:27 -0400 Subject: [PATCH] Demangle symbols when reading them out of the symbol table. This also adds our first wasm module and updates the configuration so that that's possible. I've used wasm-pack to publish a gecko-profiler-demangle module to npm instead of copying the generated code into this repository. I'm not sure if that was a good or a bad idea; I mostly did it so that our Flow and ESLint rules wouldn't be applied to the wasm-bindgen generated code. I've also needed to autogenerate a flow libdef for this module. wasm-bindgen doesn't create those automatically yet: https://github.com/rustwasm/wasm-bindgen/issues/180 I could have created one manually and included it in the published package, but I don't know if wasm-pack would have included my additional files in the published package (via `wasm-pack publish`). --- .babelrc | 6 ++-- package.json | 6 +++- src/profile-logic/symbol-store.js | 23 ++++++++++--- src/test/gecko-profiler-demangle-mock.js | 15 +++++++++ .../npm/gecko-profiler-demangle_vx.x.x.js | 32 +++++++++++++++++++ webpack.config.js | 2 +- yarn.lock | 15 +++++++++ 7 files changed, 91 insertions(+), 8 deletions(-) create mode 100644 src/test/gecko-profiler-demangle-mock.js create mode 100644 src/types/libdef/npm/gecko-profiler-demangle_vx.x.x.js diff --git a/.babelrc b/.babelrc index ff17ad52ecc..f2955dce6aa 100644 --- a/.babelrc +++ b/.babelrc @@ -15,7 +15,8 @@ ], plugins: [ "transform-class-properties", - [ "transform-object-rest-spread", { "useBuiltIns": true }] + [ "transform-object-rest-spread", { "useBuiltIns": true }], + "syntax-dynamic-import" ], env: { // Needed for tests, as node doesn't support ES2015 modules yet. @@ -28,7 +29,8 @@ ], plugins: [ "transform-class-properties", - [ "transform-object-rest-spread", { "useBuiltIns": true }] + [ "transform-object-rest-spread", { "useBuiltIns": true }], + "dynamic-import-node" ], } } diff --git a/package.json b/package.json index 36433b66e34..b7404efff5b 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,8 @@ "dependencies": { "array-move": "^1.0.0", "array-range": "^1.0.1", + "babel-plugin-dynamic-import-node": "^2.0.0", + "babel-plugin-syntax-dynamic-import": "^6.18.0", "babel-runtime": "^6.26.0", "bisection": "0.0.3", "clamp": "^1.0.1", @@ -46,6 +48,7 @@ "common-tags": "^1.7.2", "copy-to-clipboard": "^3.0.8", "escape-string-regexp": "^1.0.5", + "gecko-profiler-demangle": "^0.1.0", "jszip": "^3.1.5", "memoize-immutable": "^3.0.0", "mixedtuplemap": "^1.0.0", @@ -134,7 +137,8 @@ ], "moduleNameMapper": { "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/src/test/fixtures/mocks/file-mock.js", - "\\.(css|less)$": "/src/test/fixtures/mocks/style-mock.js" + "\\.(css|less)$": "/src/test/fixtures/mocks/style-mock.js", + "^gecko-profiler-demangle$": "/src/test/gecko-profiler-demangle-mock.js" }, "restoreMocks": true, "resetMocks": true, diff --git a/src/profile-logic/symbol-store.js b/src/profile-logic/symbol-store.js index 4ca60b04d06..c742c7a0474 100644 --- a/src/profile-logic/symbol-store.js +++ b/src/profile-logic/symbol-store.js @@ -7,6 +7,8 @@ import SymbolStoreDB from './symbol-store-db'; import { SymbolsNotFoundError } from './errors'; import bisection from 'bisection'; +const demangleModulePromise = import('gecko-profiler-demangle'); + import type { RequestedLib } from '../types/actions'; import type { SymbolTableAsTuple } from './symbol-store-db'; @@ -113,7 +115,8 @@ export class SymbolStore { // This format is documented at the SymbolTableAsTuple flow type definition. _readSymbolsFromSymbolTable( addresses: Set, - symbolTable: SymbolTableAsTuple + symbolTable: SymbolTableAsTuple, + demangleCallback: string => string ): Map { const [symbolTableAddrs, symbolTableIndex, symbolTableBuffer] = symbolTable; const addressArray = Uint32Array.from(addresses); @@ -150,7 +153,9 @@ export class SymbolStore { const startOffset = symbolTableIndex[symbolIndex]; const endOffset = symbolTableIndex[symbolIndex + 1]; const subarray = symbolTableBuffer.subarray(startOffset, endOffset); - currentSymbol = decoder.decode(subarray); + // C++ or rust symbols in the symbol table may have mangled names. + // Demangle them here. + currentSymbol = demangleCallback(decoder.decode(subarray)); currentSymbolIndex = symbolIndex; } results.set(address, { @@ -268,10 +273,16 @@ export class SymbolStore { // symbolication for the libraries for which we found symbol tables in the // database. This is delayed until after the request has been kicked off // because it can take some time. + // We also need a demangling function for this, which is in an async module. + const demangleCallback = (await demangleModulePromise).demangle_any; for (const { request, symbolTable } of requestsForCachedLibs) { successCb( request, - this._readSymbolsFromSymbolTable(request.addresses, symbolTable) + this._readSymbolsFromSymbolTable( + request.addresses, + symbolTable, + demangleCallback + ) ); } @@ -312,7 +323,11 @@ export class SymbolStore { // Did not throw, option 3 was successful! successCb( request, - this._readSymbolsFromSymbolTable(addresses, symbolTable) + this._readSymbolsFromSymbolTable( + addresses, + symbolTable, + demangleCallback + ) ); // Store the symbol table in the database. diff --git a/src/test/gecko-profiler-demangle-mock.js b/src/test/gecko-profiler-demangle-mock.js new file mode 100644 index 00000000000..e9202af8b2e --- /dev/null +++ b/src/test/gecko-profiler-demangle-mock.js @@ -0,0 +1,15 @@ +// This module replaces the wasm-pack generated module 'gecko-profiler-demangle' +// in our tests. +// The reason for this replacement is the fact that wasm-pack (or rather, +// wasm-bindgen), when targeting the browser + webpack, generates an ES6 module +// that node cannot deal with. Most importantly, it uses the syntax +// "import * as wasm from './gecko_profiler_demangle_bg';" in order to load +// the wasm module, which is currently only supported by webpack. + +// @flow + +// There's only one exported function. +// Do the simplest thing possible: no demangling. +export function demangle_any(s: string): string { + return s; +} diff --git a/src/types/libdef/npm/gecko-profiler-demangle_vx.x.x.js b/src/types/libdef/npm/gecko-profiler-demangle_vx.x.x.js new file mode 100644 index 00000000000..641e62c0d2d --- /dev/null +++ b/src/types/libdef/npm/gecko-profiler-demangle_vx.x.x.js @@ -0,0 +1,32 @@ +// flow-typed signature: e6f43a673a1ad489aea31817e5e11e45 +// flow-typed version: <>/gecko-profiler-demangle_v^0.1.0/flow_v0.70.0 + +/** + * This is an autogenerated libdef stub for: + * + * 'gecko-profiler-demangle' + * + * Fill this stub out by replacing all the `any` types. + * + * Once filled out, we encourage you to share your work with the + * community by sending a pull request to: + * https://github.com/flowtype/flow-typed + */ + +declare module 'gecko-profiler-demangle' { + declare module.exports: any; +} + +/** + * We include stubs for each file inside this npm package in case you need to + * require those files directly. Feel free to delete any files that aren't + * needed. + */ +declare module 'gecko-profiler-demangle/gecko_profiler_demangle' { + declare module.exports: any; +} + +// Filename aliases +declare module 'gecko-profiler-demangle/gecko_profiler_demangle.js' { + declare module.exports: $Exports<'gecko-profiler-demangle/gecko_profiler_demangle'>; +} diff --git a/webpack.config.js b/webpack.config.js index 39d213758be..4fc9d52d0c7 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -18,7 +18,7 @@ const config = { 'redux-devtools': path.join(__dirname, '..', '..', 'src'), react: path.join(__dirname, 'node_modules', 'react'), }, - extensions: ['.js'], + extensions: ['.js', '.wasm'], }, devtool: 'source-map', module: { diff --git a/yarn.lock b/yarn.lock index 7b150df8f3b..d823aea3c36 100644 --- a/yarn.lock +++ b/yarn.lock @@ -892,6 +892,13 @@ babel-plugin-check-es2015-constants@^6.22.0: dependencies: babel-runtime "^6.22.0" +babel-plugin-dynamic-import-node@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.0.0.tgz#d6fc3f6c5e3bdc34e49c15faca7ce069755c0a57" + dependencies: + babel-plugin-syntax-dynamic-import "^6.18.0" + object.assign "^4.1.0" + babel-plugin-istanbul@^4.1.6: version "4.1.6" resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz#36c59b2192efce81c5b378321b74175add1c9a45" @@ -913,6 +920,10 @@ babel-plugin-syntax-class-properties@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" +babel-plugin-syntax-dynamic-import@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" + babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" @@ -3912,6 +3923,10 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" +gecko-profiler-demangle@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/gecko-profiler-demangle/-/gecko-profiler-demangle-0.1.0.tgz#7bc08d43e3572e64a6c09c4ed6680e4bc4ce356e" + get-caller-file@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"