-
Notifications
You must be signed in to change notification settings - Fork 254
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for Rust v0 symbol mangling scheme #491
Changes from 2 commits
9560a1b
5f7f56e
1a015f0
82d7cd1
ff9c63f
5f70af5
4e75a98
a3a836c
09f41d1
a517ff5
b7a2788
6ffa4d3
5bd2d01
85c51f9
6d2eacd
62eafd9
5b58f86
8b31d4e
c317bda
faadf24
eb6926d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
node_modules | ||
.cache | ||
.parcel-cache | ||
dist | ||
.idea | ||
coverage | ||
|
Large diffs are not rendered by default.
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import {loadDemangling} from './demangle' | ||
|
||
test('demangle', async () => { | ||
const demangle = await loadDemangling() | ||
|
||
expect(demangle('a')).toBe('a') | ||
expect(demangle('someUnobfuscatedFunction')).toBe('someUnobfuscatedFunction') | ||
|
||
// C++ mangling | ||
expect(demangle('__ZNK7Support6ColorFeqERKS0_')).toBe( | ||
'Support::ColorF::operator==(Support::ColorF const&) const', | ||
) | ||
// Running a second time to test the cache | ||
expect(demangle('__ZNK7Support6ColorFeqERKS0_')).toBe( | ||
'Support::ColorF::operator==(Support::ColorF const&) const', | ||
) | ||
|
||
// Rust v0 mangling | ||
expect(demangle('_RNvCskwGfYPst2Cb_3foo16example_function')).toBe('foo::example_function') | ||
|
||
// Rust legacy mangling | ||
expect(demangle('_ZN3std2fs8Metadata7created17h8df207f105c5d474E')).toBe('std::fs::Metadata::created::h8df207f105c5d474') | ||
Check failure on line 22 in src/lib/demangle.test.ts GitHub Actions / test (18.x)
|
||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import createWasmDemangleModule from "./demangle.wasm"; | ||
Check failure on line 1 in src/lib/demangle.ts GitHub Actions / test (18.x)
|
||
|
||
const cache = new Map<string, string>() | ||
|
||
export async function loadDemangling(): Promise<(name: string) => string> { | ||
// This function converts a mangled C++ name such as "__ZNK7Support6ColorFeqERKS0_" | ||
// into a human-readable symbol (in this case "Support::ColorF::==(Support::ColorF&)") | ||
const wasmDemangleModule = await createWasmDemangleModule(); | ||
Check failure on line 8 in src/lib/demangle.ts GitHub Actions / test (18.x)
|
||
return cached(wasmDemangleModule.wasm_demangle); | ||
Check failure on line 9 in src/lib/demangle.ts GitHub Actions / test (18.x)
|
||
} | ||
|
||
function cached(demangle: (name: string) => string): (name: string) => string { | ||
return (name: string): string => { | ||
let result = cache.get(name) | ||
if (result !== undefined) { | ||
name = result | ||
} else { | ||
result = demangle(name) | ||
result = result === '' ? name : result | ||
cache.set(name, result) | ||
name = result | ||
} | ||
return name | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
interface WasmDemangleModule { | ||
wasm_demangle(mangled: string): string | ||
Check failure on line 2 in src/lib/demangle.wasm.d.ts GitHub Actions / test (18.x)
|
||
} | ||
|
||
export default function ModuleFactory(options?: unknown): Promise<WasmDemangleModule>; | ||
Check failure on line 5 in src/lib/demangle.wasm.d.ts GitHub Actions / test (18.x)
|
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,6 @@ | ||
import {lastOf, KeyedSet} from './utils' | ||
import {ValueFormatter, RawValueFormatter} from './value-formatters' | ||
import {FileFormat} from './file-format-spec' | ||
const demangleCppModule = import('./demangle-cpp') | ||
|
||
export interface FrameInfo { | ||
key: string | number | ||
|
@@ -404,16 +403,16 @@ | |
|
||
// Demangle symbols for readability | ||
async demangle() { | ||
let demangleCpp: ((name: string) => string) | null = null | ||
let demangle: ((name: string) => string) | null = null | ||
|
||
for (let frame of this.frames) { | ||
// This function converts a mangled C++ name such as "__ZNK7Support6ColorFeqERKS0_" | ||
// into a human-readable symbol (in this case "Support::ColorF::==(Support::ColorF&)") | ||
if (frame.name.startsWith('__Z')) { | ||
if (!demangleCpp) { | ||
demangleCpp = (await demangleCppModule).demangleCpp | ||
// This function converts a mangled C++ and Rust name into a human-readable symbol. | ||
if (frame.name.startsWith('__Z') || frame.name.startsWith('_R') || frame.name.startsWith('_Z')) { | ||
Check failure on line 410 in src/lib/profile.ts GitHub Actions / test (18.x)
Check failure on line 410 in src/lib/profile.ts GitHub Actions / test (20.x)
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmmm is there any other way of sanely auto-detecting this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see any other way sadly. Unless mistaken, _Z is the default mangling prefix and __Z happens mostly on macOS where symbols get an extra _. I tested with a raw undemangled C++ perf trace on Linux and speedscope didn't demsngle it. I added this as a result but should have made a separate commit to explain. |
||
if (!demangle) { | ||
const demangleModule = await import('./demangle') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The In this case, I think we want both the I think the right way of doing that is to eagerly do the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From what I read, demangle is already imported eagerly by As for diff --git a/src/lib/demangle/demangle.ts b/src/lib/demangle/demangle.ts
index b69adeb..70f17a0 100644
--- a/src/lib/demangle/demangle.ts
+++ b/src/lib/demangle/demangle.ts
@@ -1,11 +1,13 @@
import createWasmDemangleModule from './demangle.wasm'
+const wasmDemangleModulePromise = createWasmDemangleModule().then((module) => module)
+
const cache = new Map<string, string>()
export async function loadDemangling(): Promise<(name: string) => string> {
// This function converts a mangled C++ name such as "__ZNK7Support6ColorFeqERKS0_"
// into a human-readable symbol (in this case "Support::ColorF::==(Support::ColorF&)")
- const wasmDemangleModule = await createWasmDemangleModule()
+ const wasmDemangleModule = await wasmDemangleModulePromise
return cached(wasmDemangleModule.wasm_demangle)
} That way, everything is eager from |
||
demangle = await demangleModule.loadDemangling() | ||
} | ||
frame.name = demangleCpp(frame.name) | ||
frame.name = demangle(frame.name) | ||
} | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was this necessary as part of this change? I'm not opposed per-se, but I don't like upgrading dependencies as part of PRs that introduce other changes in case they need reverting
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fully understand. I added the explanation in the commit. Sadly the emscripten generated code is a raw JavaScript file that contains features that are not supported by That version of parcel-bundled hence why I had to upgrade it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.