Skip to content

[CoreCLR/NativeAOT] Migrate JNI reference logging to printf#12150

Merged
jonathanpeppers merged 10 commits into
mainfrom
dev/simonrozsival/nativeaot-jni-reference-printf-logging
Jul 20, 2026
Merged

[CoreCLR/NativeAOT] Migrate JNI reference logging to printf#12150
jonathanpeppers merged 10 commits into
mainfrom
dev/simonrozsival/nativeaot-jni-reference-printf-logging

Conversation

@simonrozsival

Copy link
Copy Markdown
Member

Summary

Continue the printf-style logging migration introduced by #12140 by converting shared CoreCLR/NativeAOT JNI reference logging in OSBridge.

The src/native/clr/ location is shared infrastructure: the NativeAOT host explicitly compiles clr/host/os-bridge.cc, while MonoVM uses its separate mono/monodroid/osbridge.cc implementation. This PR therefore affects CoreCLR and NativeAOT, but not MonoVM.

Base/dependency: #12140 must merge first. This PR targets dev/simonrozsival/nativeaot-printf-logging so its diff contains only this migration.

Part of #12139.

Scope

Only two files change:

  • src/native/clr/host/os-bridge.cc
  • src/native/clr/include/host/os-bridge.hh

This does not overlap the open sibling work:

Changes

Format reference records once

  • add a private printf-checked OSBridge::log_itf() helper;
  • use vasprintf() to produce one NUL-terminated reference-log line;
  • pass the same formatted line to the existing logcat and file-writing path;
  • release the C allocation after both destinations have consumed it;
  • on allocation failure, fall back to the static format string rather than throwing from a noexcept std::format path.

Migrate JNI reference events

Replace six owning std::format constructions:

  • new global reference;
  • deleted global reference;
  • new weak global reference;
  • deleted weak global reference;
  • new local reference;
  • deleted local reference.

The replacements use %d, %p, %c, and %s with compiler format checking from the private helper declaration.

Remove ranges-heavy stack-trace splitting

  • replace std::views::split with an in-place std::string_view newline scan;
  • preserve empty, consecutive, and trailing lines;
  • preserve logcat-only, file-only, and combined output behavior;
  • write non-NUL-terminated line views with explicit lengths;
  • convert stack-trace and raw gref logcat forwarding to %.*s / %s.

Responsibility boundary with #12141

  • GCBridge ([NativeAOT] Use POSIX primitives for GC bridge processing #12141) controls when and where a bridge round runs: callback handoff, worker thread, semaphore synchronization, and Java GC triggering.
  • OSBridge (this PR) tracks and logs JNI reference events: gref/weak-gref counters, reference creation/deletion lines, and optional stack traces.

The classes call each other through existing stable helpers, but this PR changes no GC scheduling, graph processing, callback lifecycle, or synchronization state.

Behavior preserved

  • reference counters are incremented/decremented at the same points;
  • logging remains gated by LOG_GREF / LOG_LREF before formatting;
  • each reference line is still emitted to logcat and, when configured, the corresponding file;
  • stack traces retain one output line per newline-delimited segment, including empty segments;
  • logcat/file flushing behavior is unchanged;
  • pointer, reference-type, thread-name, thread-id, and counter fields retain the same ordering and textual structure.

Measured impact

Android arm64 Release NativeAOT os-bridge.cc object, compiled with the repository-generated production NDK command:

Artifact Before After Difference
os-bridge.cc.o 168,784 B 31,288 B -137,496 B (-81.46%)
format/basic-string symbols 21 6 -15

The remaining C++ string symbols come from other shared header functionality; the six std::format reference-log instantiations are removed.

Non-goals

  • no new logging test framework is introduced;
  • no GC bridge synchronization or graph-processing code changes;
  • no MonoVM osbridge.cc changes;
  • no changes to the public logging helpers introduced by [Native] Add printf-style native logging #12140.

Validation

Introduce printf-style native logging and abort helpers while preserving the existing std::format APIs for MonoVM and CoreCLR. Migrate the NativeAOT-specific formatted call sites to the new primitives.

Refs #12139

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 187b207a-083b-461e-9071-e9aab61c9d07
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 70f63eb7-6599-414c-a947-d860705aa0fa
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 70f63eb7-6599-414c-a947-d860705aa0fa
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 70f63eb7-6599-414c-a947-d860705aa0fa
Keep the printf logging PR focused on the runtime implementation instead of introducing new host-native logging test infrastructure.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 70f63eb7-6599-414c-a947-d860705aa0fa
Format gref/lref records once with C varargs, preserve logcat/file output, and remove std::format and ranges-heavy splitting from OSBridge.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 70f63eb7-6599-414c-a947-d860705aa0fa
Copilot AI review requested due to automatic review settings July 17, 2026 10:32
@simonrozsival simonrozsival added the drop-libcpp Work to remove the libc++ dependency from Android NativeAOT label Jul 17, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 continues the NativeAOT/CoreCLR printf-style logging migration by updating OSBridge’s JNI reference logging to avoid std::format (and std::views::split) while preserving the existing dual-destination behavior (logcat + optional files).

Changes:

  • Introduces a private OSBridge::log_itf() helper that formats a single reference-log record via vasprintf() and forwards the same formatted line to logcat/file paths.
  • Migrates gref/weak-gref/lref create/delete reference event logging to printf formatting (%d, %p, %c, %s) with compile-time format checking.
  • Replaces ranges-based stack-trace splitting with an in-place std::string_view newline scan that preserves empty/trailing segments and writes non-NUL-terminated segments safely using explicit lengths.
Show a summary per file
File Description
src/native/clr/include/host/os-bridge.hh Updates the private logging helper signatures to use std::string_view and adds a printf-checked log_itf() declaration.
src/native/clr/host/os-bridge.cc Implements log_itf() using vasprintf(), migrates reference event logging away from std::format, and replaces ranges-based stack-trace splitting with a manual string_view scan.

Copilot's findings

  • Files reviewed: 2/2 changed files
  • Comments generated: 0

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 70f63eb7-6599-414c-a947-d860705aa0fa
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 70f63eb7-6599-414c-a947-d860705aa0fa
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 70f63eb7-6599-414c-a947-d860705aa0fa
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 70f63eb7-6599-414c-a947-d860705aa0fa
simonrozsival added a commit that referenced this pull request Jul 20, 2026
## Summary

Introduce printf-style native logging primitives and migrate the initial NativeAOT formatted logging call sites to them.

This is the first implementation step from #12139 toward removing the Android NativeAOT dependency on libc++.

## Changes

- add `log_writev()`, `log_writef()`, `log_debugf()`, `log_infof()`, `log_warnf()`, and `log_errorf()` alongside the existing `std::format` APIs;
- implement the same printf helpers in the CLR and MonoVM shared logging backends so shared runtime code can use one logging path;
- add `Helpers::abort_applicationf()` for formatted fatal messages without truncating tombstone text;
- include `<cstdio>` explicitly for `vasprintf()`;
- omit an unused `log_fatalf()` wrapper; formatted fatal termination uses `abort_applicationf()` instead;
- replace the NativeAOT GC-user-peer initialization error's `std::format`;
- replace the NativeAOT JNI on-load debug message's `{}` formatting;
- avoid `std::format` inside `Helpers::abort_application()`.

The existing `std::format` APIs remain available so unrelated call sites can be migrated incrementally. The current stacked migrations are #12148 (shared runtime utilities), #12150 (JNI reference logging), #12153 (timing logging), and #12155 (configuration diagnostics).

## Runtime behavior

- NativeAOT and CoreCLR use the CLR shared logging implementation.
- MonoVM uses its own shared logging implementation with the same printf helper surface.
- category filtering and Android log priorities remain unchanged.
- null format pointers are logged as `<null>` rather than passed to `__android_log_vprint()`.

## Validation

- `git diff --check`;
- Release build of `src/native/native-nativeaot.csproj`;
- Release build of `src/native/native-clr.csproj`;
- NDK Clang C++23 syntax compilation of the CLR helper changes across NativeAOT/CoreCLR configurations;
- NDK Clang C++23 syntax compilation of the MonoVM printf implementation in 8 Android configurations;
- focused review of `va_list`, category filtering, format checking, source-location behavior, and Android log-priority mapping;
- latest head: `09f0690da`.

Part of #12139.
Base automatically changed from dev/simonrozsival/nativeaot-printf-logging to main July 20, 2026 13:44
jonathanpeppers pushed a commit that referenced this pull request Jul 20, 2026
## Summary

Continue the printf-style logging migration introduced by #12140 in the shared native timing infrastructure.

The timing headers are used by MonoVM, CoreCLR, and NativeAOT. All three runtimes now use the same printf-style path for variable timing diagnostics rather than maintaining MonoVM-only `std::format` branches.

**Base/dependency:** #12140 must merge first. This PR targets `dev/simonrozsival/nativeaot-printf-logging` so its diff contains only the timing migration.

Part of #12139.

## Scope

Only two shared timing headers change:

- `src/native/common/include/runtime-base/timing.hh`
- `src/native/common/include/runtime-base/timing-internal.hh`

These files do not overlap #12141, #12142, #12145, #12148, #12150, or #12155.

## Changes

### Managed timing records

- replace the owning `std::format` result in `Timing::do_log()` with `log_writef()` for every runtime;
- preserve the exact `message; elapsed: seconds:milliseconds::nanoseconds` field order;
- pass duration values as explicitly converted `unsigned long long` values matching `%llu`.

### Fast timing diagnostics

Migrate variable diagnostics to `log_warnf()` for every runtime:

- timing event buffer reallocation sizes;
- `CLOCK_MONOTONIC_RAW` errors;
- unknown event-kind values;
- invalid event-index source method names.

Constant warning messages continue using the existing non-formatting `string_view` overload.

## Behavior preserved

- timing enablement and category gating are unchanged;
- timing sequence acquisition/release is unchanged;
- elapsed duration units, values, and output order are unchanged;
- event-buffer growth, clock error handling, unknown-event fallback, and index validation are unchanged;
- no timing data structures, locks, vectors, strings, or event lifecycle code change.

## Runtime behavior

| Runtime | Result |
|---|---|
| NativeAOT | Uses #12140 printf helpers for variable timing diagnostics |
| CoreCLR | Uses #12140 printf helpers for variable timing diagnostics |
| MonoVM | Uses the matching MonoVM printf helper implementation from #12140 |

## Measured impact

Representative Android arm64 Release objects compiled before the MonoVM path was unified:

| Runtime/object | Before | After | Difference |
|---|---:|---:|---:|
| CoreCLR `internal-pinvokes-clr.cc.o` | 145,472 B | 17,080 B | -128,392 B (-88.26%) |
| NativeAOT `host.cc.o` | 176,104 B | 175,960 B | -144 B |

CoreCLR's representative object drops from 58 formatting symbols to zero. NativeAOT's representative object still contains formatting symbols from other included functionality, but the timing call sites migrated here no longer instantiate them.

## Non-goals

- no new timing tests or logging test framework;
- no change to timing data ownership or synchronization;
- no changes to the logging helper implementation introduced by #12140;
- no attempt to migrate unrelated timing output/file-generation code outside these shared timing headers.

## Validation

- `git diff --check`;
- NDK Clang C++23 syntax compilation of all 36 Android arm64 Release NativeAOT source variants;
- NDK Clang C++23 syntax compilation of all 38 Android arm64 Release CoreCLR source variants;
- NDK Clang C++23 syntax compilation of all 31 Android arm64 Release MonoVM source variants;
- representative before/after object compilation, size comparison, and symbol inspection;
- focused review of chrono values, integer format widths, source-location output, and category semantics;
- latest head: `21ff66b26`.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers
jonathanpeppers merged commit d892a5a into main Jul 20, 2026
44 checks passed
@jonathanpeppers
jonathanpeppers deleted the dev/simonrozsival/nativeaot-jni-reference-printf-logging branch July 20, 2026 16:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

drop-libcpp Work to remove the libc++ dependency from Android NativeAOT

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants