Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Inherited has 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)

@dougqh dougqh Jul 20, 2026

Copy link
Copy Markdown
Contributor Author

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.

@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE, ElementType.PARAMETER})
public @interface Strategy {}
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 {}