Greetings,

Please review this change to improve JFR’s reporting of JVMTI agents and, for 
better separation of concerns, the responsibilities and lifetimes of JVMTI 
agents.

## Problem

Tools commonly reuse `Agent_OnAttach` as a control channel—for example, to 
start and stop profiling. Previously, each successful startup invocation was 
counted as a new agent instance, producing duplicate and misleading JFR 
reporting.

This change associates reporting with JVMTI environment lifetimes established 
during agent startup, while separating those lifetimes from library lookup and 
`Agent_OnUnload` notifications.

For further details and a before-and-after profiling demonstration, see 
[JDK-8392584](https://bugs.openjdk.org/browse/JDK-8392584).

## Model and responsibilities

The model separates agent startup from loading its underlying OS library. An 
agent startup invocation of an entry point may establish a new registered agent 
instance or simply issue a command to an already existing agent.

The responsibilities are divided as follows:

- `JvmtiAgent` represents a startup invocation and holds its identity, JVMTI 
environment association, startup state, and initialization timing.
- `JvmtiAgentSet` manages startup attribution, JVMTI environment association 
and disposal, and the append-only registry of registered JvmtiAgents.
- `JvmtiResolver` represents shared library-resolution identity and manages 
native-lookup eligibility and `Agent_OnUnload` registration.
- `JvmtiAgentLifecycle` handles OS library loading, agent startup entry-point 
resolution, invocation of startup entry-points, and unload notifications.

Dynamically loaded OS libraries are identified by their OS handles. Statically 
linked JvmtiAgents are distinguished by normalized names.

## JVMTI environment association and retention

The first successfully created JVMTI environment on the startup thread is 
associated with the innermost executing startup invocation. This environment 
becomes the `JvmtiAgent`'s identity over its lifetime.

The association has some constraints:

- Disposing the associated environment does not make the `JvmtiAgent` eligible 
for reassociation.
- Additional environments created by an inner startup invocation do not fall 
through to an outer invocation.
- Environment creation outside a startup invocation issued by the JVM does not 
establish a tracked `JvmtiAgent` instance.

This direct association replaces attribution through callback addresses and 
hardcoded knowledge of the JPLIS environment-local-storage layout.

The decision to retain or discard a `JvmtiAgent` depends on whether the 
associated environment remains live after startup completion, regardless of the 
startup return code. A failed `Agent_OnAttach` invocation can therefore leave a 
retained `JvmtiAgent` instance, while a successful control command carried by a 
`JvmtiAgent` without a new JVMTI environment is not retained.

Accordingly, the boolean returned by `JvmtiAgentSet::startup` means **retain 
this instance**, rather than **startup succeeded**.

## JFR events

The `jdk.JavaAgent` and `jdk.NativeAgent` events gain a `disposalTime` field. 
`JvmtiEnv` disposal complements periodic event emitting of live agents, 
including cases where a JVMTI environment is created and disposed within one 
startup invocation.

Disposal event emission may be deferred until the startup entry point or the 
`VMInit` callback returns, so that initialization timing is complete; the 
disposal timestamp records when disposal is emitted, not necessarily when the 
JVMTI environment was disposed.

The change also fixes incorrect native-agent library paths caused by stale 
contents in a shared path buffer.

## Native lookup and Agent_OnUnload notifications

Native-lookup eligibility and `Agent_OnUnload` registration are managed 
independently of registered `JvmtiAgent` lifetimes:

- Successful `JvmtiAgent` startup enables native lookup, independently of JVMTI 
environment creation, in first-successful-startup order.
- Later startup failure or JVMTI environment disposal does not revoke native 
lookup.
- Returning from `Agent_OnLoad` or `Agent_OnAttach`, including their statically 
linked variants, registers the associated `JvmtiResolver` to be notified via 
`Agent_OnUnload`. This includes failed `Agent_OnAttach` invocations. If a 
specific startup entry point is not found in the corresponding OS library, that 
`JvmtiResolver` instance is not registered for `Agent_OnUnload`.
- During VM shutdown, the JVM resolves and invokes the registered 
`Agent_OnUnload` entry points, at most once per registered resolver, provided 
the entry point exists.
- Unconverted `-Xrun` agents retain previous behavior: `JVM_OnLoad` startup 
does not register them for native lookup or `Agent_OnUnload`.

Loaded OS libraries remain resident for the VM lifetime, including after failed 
`Agent_OnAttach` invocations. This changes the previous failure behavior 
because third-party library code may already have started native threads, 
making unloading unsafe.

## Concurrency and ownership

`JvmtiAgent` registration, JVMTI environment association and disposal, and 
interning of `JvmtiResolver` s are all guarded by the `JvmtiThreadState_lock`, 
except during the single-threaded VM bootstrap `JVMTI_PHASE_ONLOAD` phase.

Registered `JvmtiAgent`s are never removed, even if their JVMTI environment is 
disposed; this enables lock-free traversal.

`JvmtiAgent` startup, JVMTI environment association, and initialization timing 
have separate states.

## Suggested review order

1. Start with `JvmtiAgent` and its state model. Then review how JvmtiAgents are 
selected for registration or deletion, in `JvmtiAgentSet`.
2. Next, inspect `JvmtiResolver` for shared identity, native-lookup, and 
`Agent_OnUnload` registration.
3. Finally, review the OS library loading and startup entry-point invocations 
in `JvmtiAgentLifecycle` and the hook in `jni_GetEnv`, JVMTI environment 
disposal, and VM initialization.

## Testing

- Tiers 1–6
- `vmTestbase_nsk_jvmti_quick`
- `vmTestbase_nsk_jvmti`
- `open/test/hotspot/jtreg/serviceability/jvmti`
- Tests in `test/hotspot/jtreg/serviceability/jvmti/model` exercise the agent 
model and externally observable JVMTI behavior independently of JFR.
- Tests in `test/hotspot/jtreg/serviceability/jvmti/jfr` verify JFR event 
emission over the new agent model.
- Stress testing
- Non-JVMTI enabled builds
- Non-JFR enabled builds

Broader validation results and the before-and-after profiling demonstration are 
documented in [JDK-8392584](https://bugs.openjdk.org/browse/JDK-8392584).

---

- [x] I confirm that I make this contribution in accordance with the [OpenJDK 
Interim AI Policy](https://openjdk.org/legal/ai).

-------------

Commit messages:
 - 8392584

Changes: https://git.openjdk.org/jdk/pull/33700/files
  Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=33700&range=00
  Issue: https://bugs.openjdk.org/browse/JDK-8392584
  Stats: 7014 lines in 61 files changed: 5786 ins; 1043 del; 185 mod
  Patch: https://git.openjdk.org/jdk/pull/33700.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/33700/head:pull/33700

PR: https://git.openjdk.org/jdk/pull/33700

Reply via email to