-
Notifications
You must be signed in to change notification settings - Fork 344
Add @Strategy marker annotation for static-polymorphism strategies #11984
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
Merged
gh-worker-dd-mergequeue-cf854d
merged 4 commits into
master
from
dougqh/strategy-annotation
Jul 20, 2026
+72
−0
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
da64961
Add @Strategy / @StrategyConsumer marker annotations for static-polym…
dougqh e8b1f8f
Explain static polymorphism inline in @Strategy javadoc
dougqh 338e105
Merge branch 'master' into dougqh/strategy-annotation
dougqh 120469d
Merge branch 'master' into dougqh/strategy-annotation
dougqh File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
50 changes: 50 additions & 0 deletions
50
internal-api/src/main/java/datadog/trace/api/function/Strategy.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| package datadog.trace.api.function; | ||
|
|
||
| import java.lang.annotation.Documented; | ||
| import java.lang.annotation.ElementType; | ||
| import java.lang.annotation.Inherited; | ||
| import java.lang.annotation.Retention; | ||
| import java.lang.annotation.RetentionPolicy; | ||
| import java.lang.annotation.Target; | ||
|
|
||
| /** | ||
| * Marks a <b>static-polymorphism strategy</b>: a stateless, concrete-typed policy object that lets | ||
| * one shared algorithm specialize to straight-line code per caller, without runtime virtual | ||
| * dispatch. | ||
| * | ||
| * <p><b>What "static polymorphism" means here.</b> Ordinary (dynamic) polymorphism resolves the | ||
| * implementation at run time — an {@code invokevirtual}/{@code invokeinterface} that can go | ||
| * megamorphic on a shared call site. Static polymorphism instead makes the implementation known to | ||
| * the JIT: hold the strategy in a {@code static final} field of its <i>concrete</i> type (a stable | ||
| * constant of exact type), keep its methods small, and let the consuming method inline. The call | ||
| * site then sees the exact type, so the JIT devirtualizes the strategy's calls and inlines them, | ||
| * and the one generic algorithm compiles to specialized, monomorphic, allocation-free code per | ||
| * caller — C++-template-like specialization, driven by the JIT rather than a code generator. The | ||
| * win is <b>structural</b> (it follows from the exact-typed constant), not a speculative bet on | ||
| * class-hierarchy analysis or type profiling that a second implementation or a polluted profile | ||
| * could quietly undo. | ||
| * | ||
| * <p>This is a documentation-and-tooling marker; it changes no behavior. It exists to telegraph the | ||
| * pattern to readers and to give a future checker something to verify. The discipline it names is | ||
| * <b>not yet enforced</b> — hold to it by hand until the checker lands. | ||
| * | ||
| * <p><b>On a type</b> ({@link ElementType#TYPE}): this type is a strategy. To get the | ||
| * specialization a caller must hold it in a {@code static final} field <i>declared with the | ||
| * concrete type</i> (not an abstract base or interface), and the consuming method must inline so | ||
| * the call site sees the exact type. Keep the methods small so they inline. | ||
| * | ||
| * <p><b>On a parameter</b> ({@link ElementType#PARAMETER}): this parameter is a strategy slot. The | ||
| * argument at each call site should be a {@code static final} constant or a <i>non-capturing</i> | ||
| * lambda, so it stays a single monomorphic, allocation-free instance. A parameter can carry this | ||
| * marker even when its type cannot — e.g. a {@code java.util.function.Function} slot we don't own. | ||
| * | ||
| * <p><b>The failure mode is silent.</b> Held at an abstract/interface type, filled with a capturing | ||
| * lambda, or called from a site that doesn't inline, it still compiles and runs correctly — it just | ||
| * stays megamorphic and/or allocates, quietly losing the win. Verify the hot ones with {@code | ||
| * -XX:+PrintInlining}. | ||
| */ | ||
| @Documented | ||
| @Inherited | ||
| @Retention(RetentionPolicy.SOURCE) | ||
| @Target({ElementType.TYPE, ElementType.PARAMETER}) | ||
| public @interface Strategy {} | ||
22 changes: 22 additions & 0 deletions
22
internal-api/src/main/java/datadog/trace/api/function/StrategyConsumer.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| package datadog.trace.api.function; | ||
|
|
||
| import java.lang.annotation.Documented; | ||
| import java.lang.annotation.ElementType; | ||
| import java.lang.annotation.Retention; | ||
| import java.lang.annotation.RetentionPolicy; | ||
| import java.lang.annotation.Target; | ||
|
|
||
| /** | ||
| * Marks a higher-order method that <b>consumes</b> {@link Strategy} objects — one whose strategy | ||
| * parameters only specialize if this method itself inlines, so each call site sees the exact | ||
| * strategy type (see {@link Strategy}). Keep it small so it inlines. | ||
| * | ||
| * <p>Documentation-and-tooling marker; it changes no behavior. It pairs with {@link Strategy}: a | ||
| * strategy type/parameter says "I am a strategy / a strategy slot," while this says "I am the site | ||
| * where they must specialize." A future checker can enforce that the arguments filling those slots | ||
| * at these call sites are {@code static final} constants or non-capturing lambdas. | ||
| */ | ||
| @Documented | ||
| @Retention(RetentionPolicy.SOURCE) | ||
| @Target(ElementType.METHOD) | ||
| public @interface StrategyConsumer {} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
@Inheritedhas no affect on source-only annotations, so this could be dropped(it also has no affect on parameter annotations - it's only really useful on class annotations: https://docs.oracle.com/javase/8/docs/api/java/lang/annotation/Inherited.html)
Uh oh!
There was an error while loading. Please reload this page.
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.
Yes, I thought about that. Ultimately, I decided to keep it to show the intent -- that the concept transfers from parent to child -- including abstract child classes.