Commit c6a228b
refactor(format): inline custom-codec dispatch in row codecs (#3716)
## Why?
Simplify codegen and runtime codepath, net -1 frame stack depth, set
stage for future feature work
## What does this PR do?
Replace CustomTypeEncoderRegistry$Gen<N>, a per-registration
Janino-generated class whose static encode/decode/newCollection methods
the row codec called into, with one static final CustomCodec /
CustomCollectionFactory field per registered codec on the row codec
class itself. Fields are initialized at class load from
CustomTypeEncoderRegistry; encode/decode invoke the cached instance.
Per-call cost is one indirect call; the Janino compile-and-define cycle
on first registration is gone.
CustomTypeEncoderRegistry collapses to two ConcurrentHashMap lookups
plus a singleton handler view. findCodec / findCollectionFactory are
public so a row codec generated under a child classloader can reach
them.
Key the collection-factory codegen cache on (container, element) rather
than container alone, so two SortedSet-typed sibling fields with
different element types dispatch to their own factories.
## AI Contribution Checklist
- [x] Substantial AI assistance was used in this PR: `yes` / `no`
AI Usage Disclosure
- substantial_ai_assistance: yes
- scope: all
- affected_files_or_subsystems: Java row format
- ai_review: 👍
- ai_review_artifacts:
> Nothing blocking. Net is a clear win: deletes ~165 lines of
Janino-generated dispatch infrastructure, removes a class-generation
step from cold-start registration, and folds in a real bug fix for
sibling collection fields with a focused test.
> LGTM with no requested changes. Cleanly deletes the per-registration
Janino dispatch class in favor of static-final field caches on the row
codec itself, and fixes the sibling-SortedSet cache-keying bug with a
targeted test. fory-format suite is green (108/108, 4 pre-existing
skips).
> — Claude
> Overall
> Sound refactor and a meaningful simplification — a Janino
compile/define cycle per registration is removed in favor of one
monomorphic, JIT-friendly call site per codec field. The (beanType,
fieldType) key matches at both codegen-time discovery and runtime
lookup, and concurrency moves from coarse synchronized to
ConcurrentHashMap cleanly. Residual risks are minor: small
generated-class bloat if duplicate TypeRefs ever reach customEncode.
> I followed the Apache Fory AI review policy: review was performed by a
read-only subagent (no edits, commits, or pushes), with findings ordered
by severity, citing exact file/line locations, and including the
validation commands the author should run before merging.
> — Claude (Opus 4.7)
- human_verification: ✔️
- provenance_license_confirmation: ✔️
## Does this PR introduce any user-facing change?
Internal API change only
## Benchmark
> - JMH numbers across both suites, n=15 per benchmark on each side:
every measurement is within error bars of equal. No regression.
> - Inlining graphs confirm: both versions fully inline the user's
encode/decode body into the generated row codec, both call sites fully
> monomorphic (5120/5120 type profile). Baseline has one extra frame
(Gen1::encode trampoline); HEAD goes straight from toRow to
> WrappedCodec::encode. Both collapse to the same machine code in steady
state.
> Verdict: no performance regression, and the inlining shape is what the
static-final + monomorphic-INVOKEINTERFACE model predicts. The "static →
virtual" concern doesn't materialize because the old static call was
itself a thin static trampoline around an identical interface call.
Co-authored-by: Claude (on behalf of Steven Schlansker) <stevenschlansker+claude@apache.org>1 parent 598e82f commit c6a228b
3 files changed
Lines changed: 144 additions & 235 deletions
File tree
- java/fory-format/src
- main/java/org/apache/fory/format
- encoder
- type
- test/java/org/apache/fory/format/encoder
Lines changed: 69 additions & 22 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
69 | 69 | | |
70 | 70 | | |
71 | 71 | | |
| 72 | + | |
72 | 73 | | |
73 | 74 | | |
74 | 75 | | |
| |||
768 | 769 | | |
769 | 770 | | |
770 | 771 | | |
| 772 | + | |
771 | 773 | | |
772 | | - | |
773 | | - | |
774 | | - | |
| 774 | + | |
| 775 | + | |
| 776 | + | |
| 777 | + | |
| 778 | + | |
| 779 | + | |
| 780 | + | |
| 781 | + | |
775 | 782 | | |
776 | | - | |
777 | | - | |
778 | | - | |
779 | | - | |
| 783 | + | |
780 | 784 | | |
781 | 785 | | |
782 | 786 | | |
| |||
921 | 925 | | |
922 | 926 | | |
923 | 927 | | |
| 928 | + | |
| 929 | + | |
| 930 | + | |
| 931 | + | |
| 932 | + | |
| 933 | + | |
| 934 | + | |
| 935 | + | |
| 936 | + | |
| 937 | + | |
| 938 | + | |
| 939 | + | |
| 940 | + | |
| 941 | + | |
| 942 | + | |
| 943 | + | |
| 944 | + | |
| 945 | + | |
| 946 | + | |
| 947 | + | |
| 948 | + | |
| 949 | + | |
| 950 | + | |
| 951 | + | |
| 952 | + | |
| 953 | + | |
| 954 | + | |
| 955 | + | |
| 956 | + | |
| 957 | + | |
| 958 | + | |
| 959 | + | |
| 960 | + | |
| 961 | + | |
| 962 | + | |
| 963 | + | |
| 964 | + | |
| 965 | + | |
| 966 | + | |
| 967 | + | |
| 968 | + | |
| 969 | + | |
| 970 | + | |
| 971 | + | |
| 972 | + | |
| 973 | + | |
| 974 | + | |
| 975 | + | |
924 | 976 | | |
925 | | - | |
926 | | - | |
927 | | - | |
928 | | - | |
| 977 | + | |
| 978 | + | |
| 979 | + | |
| 980 | + | |
929 | 981 | | |
930 | | - | |
931 | | - | |
932 | | - | |
| 982 | + | |
933 | 983 | | |
934 | 984 | | |
935 | 985 | | |
936 | | - | |
937 | | - | |
938 | | - | |
939 | | - | |
| 986 | + | |
| 987 | + | |
| 988 | + | |
| 989 | + | |
940 | 990 | | |
941 | | - | |
942 | | - | |
943 | | - | |
944 | | - | |
| 991 | + | |
945 | 992 | | |
946 | 993 | | |
0 commit comments