Skip to content

Commit a059d47

Browse files
dougqhdevflow.devflow-routing-intake
andauthored
Add @strategy marker annotation for static-polymorphism strategies (#11984)
Add @strategy / @StrategyConsumer marker annotations for static-polymorphism strategies Marker-only (no enforcement yet): telegraphs the static-polymorphism strategy pattern and gives a future checker targets. @strategy marks strategy types/parameters; @StrategyConsumer marks the higher-order methods that must inline for them to specialize. Contracts live in the javadoc. Applications land in stacked PRs (FlatHashtable first). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Explain static polymorphism inline in @strategy javadoc Address review: describe 'static polymorphism' directly in the annotation rather than referring to FlatHashtable, which is a consumer of @strategy — the reference was a conceptual back-reference that left the base annotation unable to stand on its own. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Merge branch 'master' into dougqh/strategy-annotation Merge branch 'master' into dougqh/strategy-annotation Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
1 parent f698857 commit a059d47

2 files changed

Lines changed: 72 additions & 0 deletions

File tree

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package datadog.trace.api.function;
2+
3+
import java.lang.annotation.Documented;
4+
import java.lang.annotation.ElementType;
5+
import java.lang.annotation.Inherited;
6+
import java.lang.annotation.Retention;
7+
import java.lang.annotation.RetentionPolicy;
8+
import java.lang.annotation.Target;
9+
10+
/**
11+
* Marks a <b>static-polymorphism strategy</b>: a stateless, concrete-typed policy object that lets
12+
* one shared algorithm specialize to straight-line code per caller, without runtime virtual
13+
* dispatch.
14+
*
15+
* <p><b>What "static polymorphism" means here.</b> Ordinary (dynamic) polymorphism resolves the
16+
* implementation at run time — an {@code invokevirtual}/{@code invokeinterface} that can go
17+
* megamorphic on a shared call site. Static polymorphism instead makes the implementation known to
18+
* the JIT: hold the strategy in a {@code static final} field of its <i>concrete</i> type (a stable
19+
* constant of exact type), keep its methods small, and let the consuming method inline. The call
20+
* site then sees the exact type, so the JIT devirtualizes the strategy's calls and inlines them,
21+
* and the one generic algorithm compiles to specialized, monomorphic, allocation-free code per
22+
* caller — C++-template-like specialization, driven by the JIT rather than a code generator. The
23+
* win is <b>structural</b> (it follows from the exact-typed constant), not a speculative bet on
24+
* class-hierarchy analysis or type profiling that a second implementation or a polluted profile
25+
* could quietly undo.
26+
*
27+
* <p>This is a documentation-and-tooling marker; it changes no behavior. It exists to telegraph the
28+
* pattern to readers and to give a future checker something to verify. The discipline it names is
29+
* <b>not yet enforced</b> — hold to it by hand until the checker lands.
30+
*
31+
* <p><b>On a type</b> ({@link ElementType#TYPE}): this type is a strategy. To get the
32+
* specialization a caller must hold it in a {@code static final} field <i>declared with the
33+
* concrete type</i> (not an abstract base or interface), and the consuming method must inline so
34+
* the call site sees the exact type. Keep the methods small so they inline.
35+
*
36+
* <p><b>On a parameter</b> ({@link ElementType#PARAMETER}): this parameter is a strategy slot. The
37+
* argument at each call site should be a {@code static final} constant or a <i>non-capturing</i>
38+
* lambda, so it stays a single monomorphic, allocation-free instance. A parameter can carry this
39+
* marker even when its type cannot — e.g. a {@code java.util.function.Function} slot we don't own.
40+
*
41+
* <p><b>The failure mode is silent.</b> Held at an abstract/interface type, filled with a capturing
42+
* lambda, or called from a site that doesn't inline, it still compiles and runs correctly — it just
43+
* stays megamorphic and/or allocates, quietly losing the win. Verify the hot ones with {@code
44+
* -XX:+PrintInlining}.
45+
*/
46+
@Documented
47+
@Inherited
48+
@Retention(RetentionPolicy.SOURCE)
49+
@Target({ElementType.TYPE, ElementType.PARAMETER})
50+
public @interface Strategy {}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package datadog.trace.api.function;
2+
3+
import java.lang.annotation.Documented;
4+
import java.lang.annotation.ElementType;
5+
import java.lang.annotation.Retention;
6+
import java.lang.annotation.RetentionPolicy;
7+
import java.lang.annotation.Target;
8+
9+
/**
10+
* Marks a higher-order method that <b>consumes</b> {@link Strategy} objects — one whose strategy
11+
* parameters only specialize if this method itself inlines, so each call site sees the exact
12+
* strategy type (see {@link Strategy}). Keep it small so it inlines.
13+
*
14+
* <p>Documentation-and-tooling marker; it changes no behavior. It pairs with {@link Strategy}: a
15+
* strategy type/parameter says "I am a strategy / a strategy slot," while this says "I am the site
16+
* where they must specialize." A future checker can enforce that the arguments filling those slots
17+
* at these call sites are {@code static final} constants or non-capturing lambdas.
18+
*/
19+
@Documented
20+
@Retention(RetentionPolicy.SOURCE)
21+
@Target(ElementType.METHOD)
22+
public @interface StrategyConsumer {}

0 commit comments

Comments
 (0)