diff --git a/internal-api/src/main/java/datadog/trace/api/function/Strategy.java b/internal-api/src/main/java/datadog/trace/api/function/Strategy.java new file mode 100644 index 00000000000..ef4329ac5e4 --- /dev/null +++ b/internal-api/src/main/java/datadog/trace/api/function/Strategy.java @@ -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 static-polymorphism strategy: a stateless, concrete-typed policy object that lets + * one shared algorithm specialize to straight-line code per caller, without runtime virtual + * dispatch. + * + *
What "static polymorphism" means here. 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 concrete 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 structural (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. + * + *
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 + * not yet enforced — hold to it by hand until the checker lands. + * + *
On a type ({@link ElementType#TYPE}): this type is a strategy. To get the + * specialization a caller must hold it in a {@code static final} field declared with the + * concrete type (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. + * + *
On a parameter ({@link ElementType#PARAMETER}): this parameter is a strategy slot. The + * argument at each call site should be a {@code static final} constant or a non-capturing + * 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. + * + *
The failure mode is silent. 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 {} diff --git a/internal-api/src/main/java/datadog/trace/api/function/StrategyConsumer.java b/internal-api/src/main/java/datadog/trace/api/function/StrategyConsumer.java new file mode 100644 index 00000000000..448eba1ea7b --- /dev/null +++ b/internal-api/src/main/java/datadog/trace/api/function/StrategyConsumer.java @@ -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 consumes {@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. + * + *
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 {}