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..f7ca5852122 --- /dev/null +++ b/internal-api/src/main/java/datadog/trace/api/function/Strategy.java @@ -0,0 +1,38 @@ +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 the JIT + * can devirtualize and inline, so one shared algorithm specializes to straight-line code per caller + * (see the "static polymorphism" note on {@code FlatHashtable}). + * + *
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 {}