Skip to content

refactor(vtable_target): defer receiver resolution to dump time via SafeAccess#527

Merged
jbachorik merged 27 commits into
mainfrom
muse/vtable-target-jvmti-prereg
May 26, 2026
Merged

refactor(vtable_target): defer receiver resolution to dump time via SafeAccess#527
jbachorik merged 27 commits into
mainfrom
muse/vtable-target-jvmti-prereg

Conversation

@jbachorik
Copy link
Copy Markdown
Collaborator

@jbachorik jbachorik commented May 13, 2026

What does this PR do?:

Redesigns vtable_target receiver-class resolution. Instead of eagerly pre-registering every loaded class into _class_map at profiler start and on ClassPrepare, the signal handler now captures the receiver's raw VMSymbol* in a new BCI_VTABLE_RECEIVER frame, and the Symbol is read at dump time via SafeAccess — crash-safe against concurrent class unloading.

Changes:

  • New BCI BCI_VTABLE_RECEIVER = -21 (vmEntry.h): method_id is a VMSymbol*, not a jmethodID. Doc comment cross-referenced from the signal-handler write site (hotspotSupport.cpp) and the dump-time read site (flightRecorder.cpp).
  • New SafeAccess::safeCopy primitive (safeAccess.{h,cpp}): bulk byte copy through the safefetch trampoline, with an alignment-aware strategy that keeps every 4-byte load inside a single page so over-reads past src + len never spuriously fault. Replaces a memcpy that would have crashed if the Symbol's page was unmapped between the readability check and the copy.
  • Lookup::resolveVTableReceiver + resolveVTableReceiverCached (flightRecorder.{h,cpp}): SafeAccess-protected length + body read, printable-byte filter, synthetic-accessor/LambdaForm normalisation. Per-dump VMSymbol* → class_id cache so distinct Symbol addresses for the same class collapse to one MethodInfo.
  • New MethodMap::makeVTableReceiverKey(u32) (flightRecorder.h): adds a fourth key namespace (11 high-bit pattern, VTABLE_RECEIVER_MARK) so BCI_VTABLE_RECEIVER frames key by resolved class_id instead of by VMSymbol* address.
  • Deletions: Profiler::preregisterLoadedClasses (~100 lines + 3 call sites + decl), the ClassPrepare JVMTI hook block for vtable_target in vmEntry.cpp, classMapTrySharedGuard(), the shared-lock try-dance in walkVM. Conditional end-of-dump _class_map.clear() is restored to unconditional (was if (!_features.vtable_target || ...) for the previous design's persistence requirement).
  • Counter VTABLE_RECEIVER_RESOLVE_FAILED records resolution failures (Symbol page unmapped, length out of range, printable filter rejects).
  • Test renamed: VtableTargetPreregistrationTestVtableReceiverFrameTest; assertion message updated to describe the SafeAccess path.

Motivation:

The prior preregistration design forced unbounded growth of _class_map — every loaded class ever seen by GetLoadedClasses or ClassPrepare was inserted permanently, with no removal path (clearing the map would require a JVMTI-safepoint re-enumeration on every dump). Long-running JVMs with synthetic-class generators (LambdaForm, reflection accessors, Groovy/Kotlin invokedynamic, CGLIB) accumulated millions of entries indefinitely.

The new design bounds _class_map to "classes actually sampled this chunk" (cleared unconditionally at end-of-dump), removes the eager JVMTI enumeration and the ClassPrepare insert path, eliminates the shared/exclusive lock dance in the signal handler, and is robust to concurrent class unloading via SafeAccess-based dump-time reads.

Additional Notes:

  • VMSymbol lifetime / class unload between sample and dump. If the receiver class unloads after sample but before dump, three outcomes: (1) page unmapped → safeFetch32 returns sentinel → frame becomes <unresolved_vtable_receiver>, VTABLE_RECEIVER_RESOLVE_FAILED ticks. (2) memory reused for unrelated data → length / printable filter rejects → same as (1). (3) memory reused for another Symbol whose bytes pass the printable filter → wrong class name attached to the trace (silent miscorrelation). Cases (1)+(2) dominate; (3) is rare per-Symbol but non-zero in aggregate on class-unload-heavy workloads. Tracked as follow-up in PROF-14780 — class-unload breakpoint hook + Symbol-bytes shadow cache.
  • CallTrace dedup across Symbol address differences. CallTraceHashTable::calcHash mixes the raw bytes of every frame (including method_id). Two samples of the same logical class whose VMSymbol* address differs (class unload + reload within a chunk) produce distinct trace ids. Accepted: normalising at sample time would require an in-signal-handler Symbol read, which the redesign explicitly avoids. The dump-time MethodMap key is class_id-based, so the synthetic <vtable_receiver> MethodInfo does collapse across distinct Symbol addresses; only CallTrace dedup is affected.
  • SafeAccess::safeCopy correctness. Pages on supported platforms (x86_64 4 KiB; aarch64 Linux 4 KiB; aarch64 macOS 16 KiB) divide evenly by 4. A 4-byte-aligned 4-byte load therefore never crosses a page boundary, so over-reads beyond src + len are guaranteed safe as long as the start address itself is in a mapped page. For misaligned src, the front fixup fetches at the previous aligned address (same 4-byte word, same page) and discards leading k ∈ {1,2,3} bytes. Buffer is 4096 bytes (stack-allocated); names longer than that are recorded as resolve failures via the sentinel.
  • Empty _class_map is fine across chunks. JFR class IDs are per-chunk; clearing at end-of-dump is the correct steady state.
  • Adversary review surfaced and addressed: dead BCI_ALLOC branch in resolveMethod deleted (it was the previous receiver path; no other producer remains), normalisation logic consolidated into resolveVTableReceiver (no more duplicated LambdaForm$MH table). Help text in arguments.cpp updated to describe the new design.

How to test the change?:

  • Existing C++ gtest: SafeFetchTest — 19/19 passes (9 pre-existing + 7 new safeCopy_* cases covering happy path, zero-length, unmapped source, PROT_NONE source, tail near unmapped boundary now succeeds (regression for the previous design), requested-range-crosses-unmapped still legitimately fails, unaligned source for all k ∈ {1,2,3}, real data equal to a single sentinel).
  • Existing Java test: VtableReceiverFrameTest (renamed) compiles cleanly.
  • Release build: :ddprof-lib:assembleRelease succeeds on darwin-aarch64.
  • CI matrix (delegated to project CI): full gtest + Java test runs across Linux x86_64 / aarch64, musl, OpenJDK 8 / 11 / 17 / 21 / 25 — see CI.

For Datadog employees:

  • If this PR touches code that signs or publishes builds or packages, or handles credentials of any kind, I've requested a review from @DataDog/security-design-and-guidance.

  • This PR doesn't touch any of that.

  • JIRA: PROF-14618

  • Follow-up: PROF-14780 — class-unload breakpoint hook for mid-chunk unload preservation

…4618)

Restore vtable-target frame capture in CPU-only recordings by populating
_class_map from safe JVM-thread contexts:

- Profiler::preregisterLoadedClasses(jvmtiEnv*) bulk-inserts via
  GetLoadedClasses + GetClassSignature + ObjectSampler::normalizeClassSignature.
  Called inside the existing exclusive _class_map_lock at recording start
  and dump so signal-handler readers see a populated map.
- VM::ClassPrepare moved out-of-line into vmEntry.cpp; now also inserts
  newly prepared classes when StackWalkFeatures.vtable_target is set.
- Hot signal-handler path in hotspotSupport.cpp is unchanged.

New dictionary_concurrent_ut.cpp test pins the bounded_lookup(0) hit
contract after bulk pre-registration. A new VtableTargetCpuTest is
included @disabled with a TODO for the follow-up (vtable_target has
no CLI toggle yet, and the synthetic BCI_ALLOC frame is recorded as
a class id, not in the stack-trace string).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR restores vtable_target frame capture for CPU-only recordings by ensuring _class_map is populated from JVM-thread contexts (rather than relying on allocation/liveness paths that don’t run in CPU-only mode), keeping the signal-handler lookup path read-only and signal-safe.

Changes:

  • Bulk pre-registers loaded classes into _class_map during Profiler::start() and Profiler::dump() under the existing exclusive _class_map_lock.
  • Moves VM::ClassPrepare out-of-line and extends it to insert newly prepared classes into _class_map when vtable_target is enabled.
  • Adds a C++ unit test covering the “bulk insert then bounded_lookup(…, 0) hits” contract and stages a (currently disabled) Java integration test.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
ddprof-test/src/test/java/com/datadoghq/profiler/cpu/VtableTargetCpuTest.java Adds a staged (disabled) integration test outlining expected vtable-target behavior in CPU samples.
ddprof-lib/src/test/cpp/dictionary_concurrent_ut.cpp Adds a unit test validating bulk insertion visibility to bounded_lookup(..., 0) and sentinel behavior on miss.
ddprof-lib/src/main/cpp/vmEntry.h Moves VM::ClassPrepare definition out of the header into vmEntry.cpp.
ddprof-lib/src/main/cpp/vmEntry.cpp Implements VM::ClassPrepare to insert normalized class signatures into the class map when vtable_target is enabled.
ddprof-lib/src/main/cpp/profiler.h Adds Profiler::preregisterLoadedClasses(jvmtiEnv*) declaration and documents intended locking/threading constraints.
ddprof-lib/src/main/cpp/profiler.cpp Calls preregisterLoadedClasses() during start/dump class-map resets and implements the bulk JVMTI enumeration/insertion logic.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ddprof-lib/src/main/cpp/vmEntry.cpp Outdated
Comment thread ddprof-lib/src/main/cpp/profiler.h Outdated
Comment thread ddprof-lib/src/test/cpp/dictionary_concurrent_ut.cpp Outdated
- Log::warn on JVMTI error paths in preregisterLoadedClasses and ClassPrepare
  so silent skips are observable.
- Drop dead-code `if (sig != nullptr)` guards after the `|| sig == nullptr`
  short-circuit (JVMTI spec leaves output undefined on error).
- Remove disabled VtableTargetCpuTest.java — integration test deferred to a
  follow-up once vtable_target gets a CLI toggle and the synthetic-frame
  assertion shape is settled.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@dd-octo-sts
Copy link
Copy Markdown
Contributor

dd-octo-sts Bot commented May 13, 2026

CI Test Results

Run: #26456720745 | Commit: 0f710b7 | Duration: 12m 57s (longest job)

All 32 test jobs passed

Status Overview

JDK glibc-aarch64/debug glibc-amd64/debug musl-aarch64/debug musl-amd64/debug
8 - - -
8-ibm - - -
8-j9 - -
8-librca - -
8-orcl - - -
11 - - -
11-j9 - -
11-librca - -
17 - -
17-graal - -
17-j9 - -
17-librca - -
21 - -
21-graal - -
21-librca - -
25 - -
25-graal - -
25-librca - -

Legend: ✅ passed | ❌ failed | ⚪ skipped | 🚫 cancelled

Summary: Total: 32 | Passed: 32 | Failed: 0


Updated: 2026-05-26 15:23:33 UTC

@jbachorik jbachorik force-pushed the muse/vtable-target-jvmti-prereg branch from 3a34b65 to 3115f92 Compare May 13, 2026 16:45
@jbachorik jbachorik changed the base branch from main to muse/crash-sigsegv-in-std-rb-tree-increment-clean May 13, 2026 16:45
@jbachorik jbachorik force-pushed the muse/crash-sigsegv-in-std-rb-tree-increment-clean branch from b90761e to 76d919d Compare May 13, 2026 16:52
@jbachorik jbachorik force-pushed the muse/vtable-target-jvmti-prereg branch from 3115f92 to 6e825c7 Compare May 13, 2026 16:53
@jbachorik jbachorik force-pushed the muse/crash-sigsegv-in-std-rb-tree-increment-clean branch from 76d919d to 2105b61 Compare May 14, 2026 17:16
@jbachorik jbachorik force-pushed the muse/vtable-target-jvmti-prereg branch from 6e825c7 to 2dbee3f Compare May 15, 2026 06:19
@jbachorik jbachorik force-pushed the muse/crash-sigsegv-in-std-rb-tree-increment-clean branch 2 times, most recently from 6645120 to 2a9dd08 Compare May 15, 2026 14:49
@jbachorik jbachorik requested a review from Copilot May 18, 2026 16:12
@jbachorik
Copy link
Copy Markdown
Collaborator Author

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2dbee3f5a1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ddprof-lib/src/main/cpp/profiler.cpp Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (1)

ddprof-lib/src/test/cpp/dictionary_ut.cpp:292

  • The test "WritersDuringRotateProduceNoCorruption" doesn’t actually run writers during rotate: all writer threads are joined before the rotate/clearStandby loop starts. This means the test can’t catch races between concurrent lookup() calls and rotate()/clearStandby(); either rename the test to match its behavior or keep writers running while rotating to exercise the intended concurrency contract.
    std::vector<std::thread> writers;
    for (int i = 0; i < 4; i++) writers.emplace_back(writer, i);
    for (auto& t : writers) t.join();

    for (int cycle = 0; cycle < 20; cycle++) {
        dict.rotate();
        dict.clearStandby();
    }

Comment thread ddprof-lib/src/main/cpp/dictionary.h Outdated
Comment thread ddprof-lib/src/test/cpp/dictionary_ut.cpp Outdated
Comment thread ddprof-lib/src/main/cpp/profiler.cpp Outdated
Comment thread ddprof-lib/src/main/cpp/dictionary.h Outdated
- ClassPrepare: blocking SharedLockGuard + classMap()->lookup() (was best-effort lookupClass)
- preregisterLoadedClasses: filter to 'L'-type signatures; DeleteLocalRef each class
- Test/header comments rewritten to match new lock protocol and L-type filter

Addresses PR #527 review comments:
- 3233432627 (Copilot, vmEntry.cpp): ClassPrepare no longer silently skips during dump
- 3233432702 (Copilot, profiler.h/cpp): only reference types inserted into _class_map
- 3233432734 (Copilot, dictionary_concurrent_ut.cpp): no false 'exclusive lock' claim
- 3260404113 (Codex, profiler.cpp): JNI local refs released at every loop exit

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jbachorik jbachorik force-pushed the muse/vtable-target-jvmti-prereg branch from 2dbee3f to 5a06eb7 Compare May 18, 2026 19:31
@jbachorik jbachorik changed the base branch from muse/crash-sigsegv-in-std-rb-tree-increment-clean to main May 18, 2026 19:36
@jbachorik jbachorik requested a review from Copilot May 18, 2026 19:45
@jbachorik
Copy link
Copy Markdown
Collaborator Author

@codex review

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Comment thread ddprof-lib/src/main/cpp/vmEntry.cpp Outdated
Comment thread ddprof-lib/src/main/cpp/profiler.cpp Outdated
Comment thread ddprof-lib/src/main/cpp/profiler.cpp Outdated
Comment thread ddprof-lib/src/main/cpp/profiler.cpp Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5a06eb7e54

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ddprof-lib/src/main/cpp/profiler.cpp Outdated
Comment thread ddprof-lib/src/main/cpp/vmEntry.cpp Outdated
@jbachorik jbachorik requested a review from Copilot May 22, 2026 06:23
@jbachorik
Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Comment thread ddprof-lib/src/main/cpp/profiler.cpp Outdated
…ck assert

profiler.cpp: reword comment to state tryLockShared() proves no exclusive
holder but cannot detect a shared-lock caller (self-deadlock in Phase 0/2);
update assert message to only claim what the check can actually detect

Co-Authored-By: muse <muse@noreply>
@jbachorik
Copy link
Copy Markdown
Collaborator Author

@github-copilot please review

…tration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@jbachorik jbachorik dismissed rkennke’s stale review May 22, 2026 08:02

I have addressed all your concerns. I am going to dismiss the review not to block - I really need this integrated ASAP. Please, feel free to look at the PR retroactively and if there are any concerns left, I will address them then.

@datadog-datadog-prod-us1-2

This comment has been minimized.

jbachorik and others added 2 commits May 22, 2026 11:51
- Drop testClassMapPopulatedOnCpuStart: dictionary_classes_keys is always
  0 after Counters::reset() (line 1180) which runs after preregisterLoadedClasses,
  making the assertion permanently false.
- Fix testVtableReceiverFrameInCpuSamples: cpu=10ms with 1M trivial iterations
  (r*r ~3ms) produced <1 sample. Switch to cpu=1ms and ThreadLocalRandom bodies
  to ensure ~300ms of CPU-bound work and force megamorphic vtable dispatch.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@kaahos kaahos self-requested a review May 22, 2026 13:46
Copy link
Copy Markdown
Contributor

@kaahos kaahos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have found some potential bugs. Particularly a counter-ordering bug due to preregisterLoadedClasses being called before Counters::reset(), which seems to have already been noticed in commit be0e50a6 but the test was apparently dropped.

Comment thread ddprof-lib/src/main/cpp/profiler.cpp
Comment thread ddprof-lib/src/main/cpp/profiler.cpp Outdated
jbachorik and others added 8 commits May 25, 2026 12:44
- Use SharedLockGuard in Phase 2 of preregisterLoadedClasses
- Clarify test comment: jvmtiError is JVMTI fallback for fake class_id method_id

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- flightRecorder.cpp: BCI_ALLOC in resolveMethod now uses class_id
  directly as the JFR class ref with method name <vtable_receiver>
  instead of passing a fake jmethodID to fillJavaMethodInfo
- VtableTargetPreregistrationTest: assert Circle/Square/Triangle in
  stack trace next to vtable stub; add waitForProfilerReady and null
  guards
- profiler.h: fix Phase 2 doccomment (shared lock, not exclusive)
- profiler.cpp: Deallocate classes array when class_count==0

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
GeneratedConstructorAccessor, GeneratedMethodAccessor, and LambdaForm$
classes are normalised (digit suffix stripped) in fillJavaMethodInfo for
regular frames; the BCI_ALLOC vtable-receiver path bypasses that
normalisation, exposing un-normalised names that fail MetadataNormalisationTest.
Skip these classes at the insertion point in hotspotSupport.cpp.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Instead of skipping generated accessor/lambda-form classes at the
insertion point, apply the same prefix-based normalisation as
fillJavaMethodInfo in the BCI_ALLOC case of resolveMethod (dump-time,
cached per unique receiver class via method map):
GeneratedConstructorAccessor1 -> GeneratedConstructorAccessor,
LambdaForm$MH.xxx -> LambdaForm$MH, etc.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…shot

- Lookup: add _class_cache (std::map<u32,const char*>) populated once via
  initClassCache() before writeStackTraces; writeClasses reuses it instead
  of a second collect
- resolveMethod BCI_ALLOC: use _class_cache + same prefix normalisations as
  fillJavaMethodInfo (GeneratedXXXAccessor strips digit suffix, LambdaForm
  sub-types canonicalised)
- hotspotSupport.cpp: revert skip filter (normalisation now in resolveMethod)

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- arguments.cpp: document vtable_target overhead (JVMTI enum at start +
  each dump; incremental ClassPrepare; signal path is lock-free)
- profiler.cpp: clarify debug assertion — detects exclusive hold, not
  shared-holder re-entrancy; remove overclaiming comment
- profiler.h: fix Phase 2 comment causality (exclusive Phase 0 prevents
  clear(), not CAS; CAS makes concurrent shared inserts safe)
- vmEntry.cpp: document _features/_state memory-ordering invariant in
  ClassPrepare
- VtableTargetPreregistrationTest: add contains("<vtable_receiver>") to
  assert the synthetic frame itself, not just the class name substring
- flightRecorder.cpp: two-phase collect design comments (linter-staged)

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…afeAccess

Signal handler stores raw VMSymbol* in a new BCI_VTABLE_RECEIVER frame;
Lookup::resolveVTableReceiver reads the Symbol via SafeAccess at dump
time, crash-safe under concurrent class unloading. Drops preregister +
ClassPrepare hook; _class_map cleared unconditionally each dump.

MethodMap gains a class_id key namespace so two VMSymbol* addresses for
the same class collapse to one MethodInfo. SafeAccess::safeCopy added
with aligned-load strategy so over-reads stay in-page. Buffer 1024
→ 4096; failure sentinel "<unresolved_vtable_receiver>" instead of "".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jbachorik jbachorik changed the title fix(profiler): pre-register vtable receiver classes via JVMTI refactor(vtable_target): defer receiver resolution to dump time via SafeAccess May 26, 2026
JMC's STACK_TRACE_STRING HTML-escapes angle brackets in method names
(same as it does for <init>/<clinit>), so the synthetic frame renders
as "&lt;vtable_receiver&gt;". Match on the bare token so the assertion
works on every JFR-consumer rendering.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jbachorik jbachorik merged commit 37bf23a into main May 26, 2026
144 of 149 checks passed
@jbachorik jbachorik deleted the muse/vtable-target-jvmti-prereg branch May 26, 2026 15:10
@github-actions github-actions Bot added this to the 1.43.0 milestone May 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants