fix(ext/node): add v8.GCProfiler (#34158)
## Summary
Implements the `v8.GCProfiler` class for the `node:v8` module so that
Node.js code can sample garbage collections. The profiler hooks the V8
GC prologue/epilogue callbacks once per isolate (registered lazily on
the first `start()`) and captures `HeapStatistics` and
`HeapSpaceStatistics` snapshots before and after every collection. The
`stop()` method returns a Node-shaped report:
```js
const { GCProfiler } = require('node:v8');
const profiler = new GCProfiler();
profiler.start();
// ...workload...
const report = profiler.stop();
// {
// version: 1,
// startTime, endTime,
// statistics: [
// {
// gcType: 'Scavenge' | 'MarkSweepCompact' | ...,
// cost, // nanoseconds
// beforeGC: { heapStatistics, heapSpaceStatistics },
// afterGC: { heapStatistics, heapSpaceStatistics },
// },
// ...
// ],
// }
```
`Symbol.dispose` is implemented and idempotent, matching Node.
## Implementation notes
- A `GcProfilerRegistry` lives in an isolate slot and is shared via
`Rc<RefCell<…>>` between the cppgc handle and the GC callbacks so
that the callbacks can mutate per-profiler state without holding a
borrow of the isolate.
- The GC prologue/epilogue callbacks are registered on the isolate
exactly once (on the first `start()`) and remain registered for the
isolate's lifetime; they fast-bail when no profiler is active, so
the per-GC cost is negligible when nobody is sampling.
- Worker threads get their own registry via their own isolate slot, so
the in-worker variant works for free.
## Tests
Enables four Node compat tests, three of which were the failures in
`denoland/orchid#119`:
- `parallel/test-v8-collect-gc-profile.js`
- `parallel/test-v8-collect-gc-profile-exit-before-stop.js`
- `parallel/test-v8-collect-gc-profile-using.js`
- `parallel/test-v8-collect-gc-profile-in-worker.js`
## Test plan
- [x] `cargo check -p deno_node` passes
- [x] `cargo clippy -p deno_node --no-deps` passes
- [x] All four Node compat tests pass locally
- [x] Smoke test confirms the report shape matches Node's keys exactly
(`heapStatistics` and `heapSpaceStatistics` use the Node-style
camelCase keys the test fixture checks for)
Closes denoland/orchid#119
Co-authored-by: divybot <divybot@users.noreply.github.com>
Co-authored-by: Divy Srivastava <me@littledivy.com>