Adds a JacksonWarmup type that serializes a representative set of
payload shapes through fresh server and dialogue/client ObjectMappers
(constructed via the same conjure-java factories used at runtime) so the
JIT settles on the bimorphic BeanPropertyWriter.serializeAsField branch
(typed vs untyped serializer) with full type-profile coverage before
customer traffic perturbs it.
This works around OpenJDK C2 JIT deoptimization storm where
uncommon_trap isnonnull triggers continuous deoptimization as seen in
https://bugs.openjdk.org/browse/JDK-8330258 &
https://bugs.openjdk.org/browse/JDK-8374307 . The repeated
deoptimization can be observed by `jdk.Deoptimization` JFR events at
`com.fasterxml.jackson.databind.ser.BeanPropertyWriter` `if
(_typeSerializer == null)` site, and then re-enters unstable_if deopt
thrash on the JSON serialization path when a perturbing workload
arrives.
The warmup payloads interleave monomorphic fields (concrete types) with
polymorphic fields (sealed interface + `@JsonTypeInfo`) in the same
object so each iteration exercises both branches, letting C2 record a
bimorphic profile during the warmup pass.
Warmup failures are caught and logged rather than aborting as a degraded
JIT profile is preferable to refusing to serve traffic.
Before this PR
OpenJDK could encounter pathological C2 JIT deoptimization storm in Jackson BeanPropertyWriter.java:731 leading to ~10x performance degradation and significant increases in CPU utilization.
See https://bugs.openjdk.org/browse/JDK-8330258 & https://bugs.openjdk.org/browse/JDK-8374307
OpenJDK has an open PR openjdk/jdk#28966 that may address this issue by switching from checking
too_many_trapstotoo_many_traps_or_recompiles.After this PR
==COMMIT_MSG==
Adds a JacksonWarmup type that serializes a representative set of payload shapes through fresh server and dialogue/client
ObjectMappers (constructed via the same conjure-java factories used at runtime) so the JIT settles on the bimorphicBeanPropertyWriter.serializeAsFieldbranch (typed vs untyped serializer) with full type-profile coverage before customer traffic perturbs it.This works around OpenJDK C2 JIT deoptimization storm where
uncommon_trapisnonnulltriggers continuous deoptimization as seen in https://bugs.openjdk.org/browse/JDK-8330258 &https://bugs.openjdk.org/browse/JDK-8374307 . The repeated deoptimization can be observed by
jdk.DeoptimizationJFR events atcom.fasterxml.jackson.databind.ser.BeanPropertyWriterif (_typeSerializer == null)site, and then re-entersunstable_ifdeopt thrash on the serialization path when a perturbing workload arrives.The warmup payloads interleave monomorphic fields (concrete types) with polymorphic fields (sealed interface +
@JsonTypeInfo) in the same object so each iteration exercises both branches, letting C2 record a bimorphic profile during the warmup pass.Warmup failures are caught and logged rather than aborting as a degraded JIT profile is preferable to refusing to serve traffic.
==COMMIT_MSG==
Possible downsides?