Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
a01e79b
feat: add container memory budget
chaokunyang Jun 26, 2026
c3086ec
fix: repair container memory budget CI
chaokunyang Jun 26, 2026
649b436
fix(cpp): use portable container budget estimates
chaokunyang Jun 30, 2026
45106e4
docs: pair benchmark cases for perf comparisons
chaokunyang Jun 30, 2026
f34e7c3
feat: add lower-bound container memory budget
chaokunyang Jun 30, 2026
21134f4
fix: enforce generated container memory budgets
chaokunyang Jun 30, 2026
d0b27b1
fix: budget Swift Any materialization
chaokunyang Jun 30, 2026
fb7a7d2
fix: expose C# container budget accounting to generated code
chaokunyang Jun 30, 2026
04c1220
fix: keep compatible array reader native-image safe
chaokunyang Jun 30, 2026
ee85d4f
perf: add container memory budget
chaokunyang Jun 30, 2026
f9478dd
fix: remove stray Java rebase artifacts
chaokunyang Jun 30, 2026
4128004
refactor: clarify container budget reservation names
chaokunyang Jun 30, 2026
c4d0fbb
refactor: remove redundant Java size readers
chaokunyang Jun 30, 2026
e5bec05
feat: add root graph memory budget
chaokunyang Jun 30, 2026
8c5beb9
perf: trim graph memory budget hot paths
chaokunyang Jun 30, 2026
ec743cb
feat: use fixed root graph memory budget
chaokunyang Jun 30, 2026
dff4a9c
perf(cpp): trim graph budget root init
chaokunyang Jun 30, 2026
c3bc40f
perf(go): trim graph budget root read overhead
chaokunyang Jul 1, 2026
6b0c403
docs: fix graph memory budget guidance
chaokunyang Jul 1, 2026
d7b0a2d
fix: align graph budget collection owners
chaokunyang Jul 1, 2026
d373183
fix(csharp): clean graph budget read ownership
chaokunyang Jul 2, 2026
81d1ebc
fix: address graph budget CI breaks
chaokunyang Jul 2, 2026
53e103d
fix: unblock graph budget ci checks
chaokunyang Jul 2, 2026
ad543b2
style(js): satisfy graph budget lint rules
chaokunyang Jul 2, 2026
29a3298
style(python): apply graph budget formatter
chaokunyang Jul 2, 2026
e30de03
style(cpp): apply graph budget clang format
chaokunyang Jul 2, 2026
3cc6a02
style(swift): apply swift-format after rebase
chaokunyang Jul 2, 2026
51bf5f9
style(js): remove unrelated operator formatting diff
chaokunyang Jul 2, 2026
e765fad
style(js): apply javascript formatter
chaokunyang Jul 2, 2026
065bbc2
refactor: clean graph memory budget owner paths
chaokunyang Jul 2, 2026
c1857ec
refactor: rename graph memory limit error helper
chaokunyang Jul 2, 2026
e0d568a
refactor: clean graph memory collection readers
chaokunyang Jul 2, 2026
3a10256
refactor: simplify graph memory read state
chaokunyang Jul 2, 2026
fc9ce85
fix: enforce positive graph memory budgets
chaokunyang Jul 2, 2026
04c7089
refactor: remove graph budget cleanup leftovers
chaokunyang Jul 2, 2026
6456dce
refactor: tighten graph memory cleanup
chaokunyang Jul 2, 2026
216301f
refactor(rust): remove unused resolver harness paths
chaokunyang Jul 2, 2026
bb0e0dc
refactor(csharp): simplify union read return
chaokunyang Jul 2, 2026
2be1e51
refactor(dart): simplify graph budget checks
chaokunyang Jul 2, 2026
6d71b10
refactor(go): remove graph budget cleanup drift
chaokunyang Jul 2, 2026
d97dc71
refactor: move graph budget root charges to owners
chaokunyang Jul 2, 2026
5e4304a
fix(go): keep union roots on generic read path
chaokunyang Jul 2, 2026
80d652e
refactor: remove graph budget limit mirrors
chaokunyang Jul 3, 2026
c2c4dec
refactor: clean graph budget read-state drift
chaokunyang Jul 3, 2026
8c53f75
docs: remove stale container budget wording
chaokunyang Jul 3, 2026
1274207
refactor: remove stale graph budget helpers
chaokunyang Jul 3, 2026
3ad18ec
fix(swift): restore read context any readers
chaokunyang Jul 3, 2026
2a6e22e
refactor: simplify graph memory collection readers
chaokunyang Jul 3, 2026
1c86021
refactor(swift): use read context any helpers
chaokunyang Jul 3, 2026
16aa1fc
refactor(swift): keep any readers in read context
chaokunyang Jul 3, 2026
82ed7be
perf(swift): trim graph budget read overhead
chaokunyang Jul 3, 2026
12d842d
perf(go): trim graph budget root reads
chaokunyang Jul 3, 2026
cca5774
fix: clean graph memory budget ownership
chaokunyang Jul 3, 2026
b7f1a25
perf(java): trim graph budget read overhead
chaokunyang Jul 3, 2026
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
7 changes: 3 additions & 4 deletions .agents/docs-and-formatting.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,9 @@ Load this file when changing documentation, public APIs, protocol specs, benchma
- Python code, including `compiler/`, `benchmarks/`, `integration_tests/`, and `python/`:
`python -m ruff format <changed-python-files>` and
`python -m ruff check --fix <changed-python-files>`
- JavaScript/TypeScript under `javascript/`: use the package's ESLint-owned formatting path
(`npm run lint -- --fix` when fixing style, `npm run lint -- --quiet` when checking). Do not run
Prettier on JavaScript or TypeScript files unless that package has an explicit Prettier config or
script; otherwise it creates unrelated formatting churn.
- JavaScript/TypeScript under `javascript/`: use the package formatter scripts
(`npm run format` when fixing style, `npm run format-check` when checking). They run Prettier
before ESLint; do not use raw ESLint as the formatting gate.
- Repo-wide format and lint sweep: `bash ci/format.sh --all`

When code changes touch `compiler/` or `benchmarks/`, format those changed source files with the
Expand Down
23 changes: 23 additions & 0 deletions .agents/languages/cpp.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,29 @@ Load this file when changing `cpp/`, Cython build plumbing, or C++ xlang behavio
- Do not redesign alias-based or low-level public type shapes to add convenience methods unless the user explicitly asks for that API change.
- For cross-language feature ports, match protocol behavior but use idiomatic C++ ownership and layering instead of mirroring Java structure literally.
- Compatible scalar, list-array, and binary/uint8-array adaptations are immediate-field-only. Recursive matched-field comparison for collection elements, array elements, map keys, and map values must require exact nullability, ref tracking, generic arity, and type shape except documented user-type family normalization.
- Root deserialization graph budgets are owned by `ReadContext` and initialized by the root
`Fory::deserialize` overload. Keep `max_graph_memory_bytes` as a fixed-default graph limit:
unset/default is `128 MiB`, positive explicit values override it, and explicit non-positive
values are invalid at config creation. Byte and stream roots use the same
configured/default budget behavior. Root `Fory` overloads reset the budget only; they must not
pre-reserve root type or root self bytes.
Do not mirror the configured max into a second active-limit field; use config plus mutable
remaining budget.
Reserve estimated shallow graph-owner memory before allocation while preserving existing
byte-availability checks and their non-empty metadata ordering. `ReadContext` may expose only raw
byte reservation; collection, map, array, struct, and object
formulas belong in serializer owners. Skip dedicated string, binary, primitive scalar, primitive
vector, and primitive dense-array leaf owners; `std::vector<bool>` charges rounded packed-bit
storage. General `std::vector<T>` for non-primitive `T` is inline value storage and must be
reserved by the vector owner.
- C++ graph budget formulas must be portable lower-bound estimates, not STL heap-layout accounting.
Generic collection-like containers reserve `count_or_capacity * sizeof(value_type)`, map-like
containers reserve `count * (sizeof(key_type) + sizeof(mapped_type))`, and set-like containers
reserve `count * sizeof(key_type)`. Root struct/product owners and smart-pointer/box allocation
owners reserve shallow self storage exactly once; nested value serializers reserve only dynamic
storage they allocate, not their own inline self storage again. Do not add guessed
node/header/debug-STL overhead, red-black-tree fields, allocator probing, object-layout
inspection, generic per-entry pointer overhead, or unordered bucket-table guesses.

## Key Paths

Expand Down
20 changes: 20 additions & 0 deletions .agents/languages/csharp.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,26 @@ Load this file when changing `csharp/` or C# xlang behavior.
- Generated C# gRPC service companions are compiler-owned files that depend on application-provided gRPC packages, not `csharp/src/Fory`. Keep gRPC package references out of the Fory runtime package.
- C# generated schema modules are source-file owners. Service companions must use that module's `ThreadSafeFory` and must not introduce namespace-owned aliases or duplicate serializer registration paths.
- Compatible scalar, list-array, and binary/uint8-array adaptations are immediate-field-only. Recursive matched-field comparison for collection elements, array elements, map keys, and map values must require exact nullability, ref tracking, generic arity, and type shape except documented user-type family normalization.
- Root deserialization graph memory budget state belongs to `ReadContext`. C# public roots are
memory-backed today, but the graph budget uses the same fixed default for every root shape.
Root APIs reset the budget only; they must not pre-reserve root type or root self bytes.
Do not mirror the configured max into a second active-limit field; use config plus mutable
remaining budget.
`ReadContext` may expose only raw byte reservation; concrete serializers and generated
serializers must compute list, array, map, struct, and object byte formulas before calling it.
- `ReadContext` must not expose ref-publication pause/resume APIs or any non-budget owner
controls. Concrete serializers and generated serializers own ref publication timing directly,
and must not publish temporary owners.
- For C# graph budget formulas, distinguish inline value storage from reference storage: use cheap
value-type size for `List<T>`/`T[]` value paths and the 4-byte reference fallback for reference
paths. Class/reference serializers reserve their own shallow self cost plus field storage when
materialized; struct/value serializers reserve self storage only on standalone serializer,
dynamic/boxed, or root materialization entries because field, list, array, map, set, and box
holders reserve the inline storage they own. Maps reserve key plus value storage, linked/hash/tree
conversions must not add guessed node or entry overhead, and independently materialized
collection/map/array owners reserve nonzero shallow self cost.
Dedicated string, binary, primitive scalar, and primitive dense-array serializers stay skipped and
rely on byte availability checks.
- When extending C# tests from Java references, prioritize xlang spec behavior and the public C# contract before adding complex Java-specific parity cases.

## Commands
Expand Down
15 changes: 15 additions & 0 deletions .agents/languages/dart.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,21 @@ Load this file when changing `dart/`.
- Keep root numeric wrapper defaults separate from generated field metadata. Root wrapper resolution belongs in the builtin resolver, while annotations and generated metadata choose fixed, tagged, or declared-field encodings.
- Dart 64-bit carriers are optimized for each platform. Do not replace native extension-type wrappers with allocation-heavy classes or route web/native hot paths through `BigInt` unless the user approves a representation change.
- In `Buffer`, cursor, serializer, and generated-code hot paths, prefer direct byte/local integer operations and conditional import/export files over callbacks, records, holder objects, wrapper round-trips, or runtime platform branches.
- Root deserialization graph memory budgets are owned by `ReadContext`;
`maxGraphMemoryBytes` defaults to fixed `128 MiB`, positive explicit values override it, and
explicit non-positive values are invalid at config creation. Do not derive the budget from
`buffer.readableBytes`. `ReadContext` may expose only raw byte reservation; list, set, map, array,
struct, and object formulas
belong in serializer owners. Reserve Dart list/set/object-array reference
slots plus nonzero owner self cost, map key/value slots plus nonzero owner
self cost, compatible array-to-list materialization, and generated object reads before
allocation. Compatible list-to-typed-array reads skip the dense primitive-array leaf owner while
preserving byte checks. Object/struct
owners reserve nonzero shallow self memory plus shallow field storage. Skip
only dedicated string, binary, primitive scalar, `BoolList`, and typed-array
dense owner paths with byte checks. Do not add stream bytes-read accounting,
per-element accounting, extra hot-path allocations, or stale narrower-scope
formulas.
- Do not add parallel header-low/header-high slot caches or multi-slot recent caches in TypeMeta hot paths to chase benchmark gaps. Header-cache hits must use the concrete checked cache owner directly; if a hit hint is needed, cache one TypeInfo/TypeMeta object and compare the validated header identity on that object, not separate low/high header fields or benchmark-pattern state.
- If Dart TypeMeta cache ownership changes, keep the invariant in a source comment near the hit path: a checked metadata-cache hit skips the body and must not grow low-bit sentinels, accepted-header fields, parallel header slots, or benchmark-pattern state.
- Dart expected-type TypeDef reads should compare the expected `TypeInfo` object's cached local TypeDef header before consulting the parsed-metadata map. A match is a direct local-schema hit: skip the remote body, add the expected type to the per-read shared type table, and do not publish to `ParsedTypeMetaCache`, record a remote schema version, or parse/hash the body.
Expand Down
17 changes: 17 additions & 0 deletions .agents/languages/go.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,23 @@ Load this file when changing `go/fory/` or Go xlang behavior.
- Run Go commands from within `go/fory/`.
- Changes under `go/` must pass formatting and tests.
- The Go implementation focuses on reflection-based and codegen-based serialization.
- Root deserialization graph memory budgets are owned by `ReadContext`.
`WithMaxGraphMemoryBytes` uses a fixed `128 MiB` default; positive explicit
values override it, and explicit non-positive values are invalid at config creation.
Byte-slice and stream roots use the same
configured/default budget behavior. Root APIs reset the budget only; they must not pre-reserve
root type or root self bytes. Do not mirror the configured max into a second active-limit field;
root setup should update only the mutable remaining budget. `ReadContext` may expose only raw byte
reservation; slice, map, array, struct, and object
formulas belong in handwritten or generated serializer owners. Reserve Go
slices as `len * elemBytes`, maps as `len * (keyBytes + valueBytes)`,
map-backed sets, and LIST-encoded inline/value slices in the owner that
allocates that storage. Struct root materialization paths, pointer allocations, and generated
allocation entries reserve shallow value storage exactly once; nested inline
struct serializers do not charge their own self storage again. Fixed arrays
are caller-owned unless a read path materializes a temporary owner. Skip
dedicated string, binary, BufferObject, primitive scalar, primitive ARRAY
slice, and primitive array owners with byte checks.
- Set `FORY_PANIC_ON_ERROR=1` when debugging a failing Go test so you get the full call stack.
- Do not set `FORY_PANIC_ON_ERROR=1` when running the full Go test suite, because some tests assert on error contents.

Expand Down
19 changes: 19 additions & 0 deletions .agents/languages/java.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,25 @@ Load this file when changing anything under `java/` or when Java drives a cross-
values; use qualified names only when a real name conflict requires it.
- If you run temporary tests with `java -cp`, run `mvn -T16 install -DskipTests` first so local Fory jars are current.
- `WriteContext`, `ReadContext`, and `CopyContext` must stay explicit. Do not reintroduce `ThreadLocal` or ambient runtime-context patterns.
- Java root deserialization graph memory budgeting belongs to `ReadContext`
and is initialized by `Fory` root APIs. Public config is `maxGraphMemoryBytes`
with fixed `128 MiB` default. Positive explicit values override the default;
explicit non-positive values are invalid and must be rejected at config creation.
Byte-array, memory-buffer, and stream roots use the same configured/default
budget behavior. Root APIs reset the budget only; they must not pre-reserve
root type or root self bytes. Do not mirror the configured max into a second
active-limit field; use config plus mutable remaining budget. `ReadContext`
may expose only raw byte reservation;
collection, map, array, struct, and object formulas belong in the concrete
serializer or generated serializer owner. Java collection, map, and
object-array owners reserve nonzero shallow self cost plus reference storage;
referenced object serializers reserve their own nonzero shallow self memory
plus shallow field storage when materialized.
Reference fields use the 4-byte fallback when the JVM reference size is not
queried cheaply; primitive fields use their encoded storage width. Preserve
existing `checkReadableBytes` guards before backing allocation or capacity
reservation. Do not add nested serializer-path `try/finally`, per-element
work, dynamic stream bytes-read accounting, or stale narrower-scope formulas.
- Generated serializers must not retain runtime context fields. `Fory` should stay a root-operation facade rather than accumulating serializer or convenience state.
- When the serializer class and constructor shape are known at the call site, prefer direct constructor lambdas or direct instantiation over reflective `Serializers.newSerializer(...)`.
- For GraalVM, use `fory codegen` to generate serializers when building native images. Do not add reflection configuration except for JDK `proxy`.
Expand Down
12 changes: 12 additions & 0 deletions .agents/languages/javascript.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@ Load this file when changing `javascript/`.
- Runtime value carriers such as decimal or reduced-precision numeric types belong under the core `types/` ownership boundary, with imports, exports, and codegen externals updated together.
- Keep `TypeInfo` as schema metadata. Compatibility-sensitive decisions belong on `TypeResolver` or explicit operations, not as retained resolver state on metadata objects.
- Normalize optional boolean config values at config construction; do not carry `null` through runtime paths when it means `false`.
- JavaScript root deserialization graph memory budgeting belongs to `ReadContext`.
`maxGraphMemoryBytes` uses a fixed `128 MiB` default, positive explicit limits override it, and
explicit non-positive values are invalid at config creation. Do not derive the budget from the
`Uint8Array` root length. `ReadContext` may expose only raw
byte reservation; generated and dynamic
list/set/map/array/struct/object readers must reserve before allocation while preserving existing
byte checks. Lists/sets/object arrays reserve nonzero owner self cost plus 4-byte reference slots,
maps reserve nonzero owner self cost plus key/value reference storage, object/struct readers
reserve nonzero shallow self memory plus shallow field storage, compatible array-to-list reads
reserve target list materialization, and compatible list-to-typed-array reads skip the dense
primitive-array leaf owner while preserving byte checks. Keep dedicated string, binary, primitive
scalar, and dense typed-array leaf owners out of this budget.
- Regenerated compatible read serializers are remote-schema-specific. After classification marks a field as direct, compatible scalar, or skip, generated JavaScript should emit straight-line remote-field-order code. Do not add an outer matched-id switch unless the current regenerated shape cannot preserve those semantics.
- Compatible scalar codegen must decide the exact remote/local scalar pair before emitting source. Generate the concrete `reader.readXxx()` call plus inline trivial conversions such as boolean-to-string or numeric widening, and keep helpers only for semantic validation such as range checks, exactness checks, decimal parsing/formatting, and string-to-bool. Do not call a generic hot-path converter that redispatches on `remoteTypeId`, `localTypeId`, field descriptors, or field names.
- Compatible scalar conversion is immediate-field-only. Recursive schema comparison for collection elements, array elements, map keys, and map values must reject scalar mismatches instead of applying the top-level scalar conversion matrix.
Expand Down
14 changes: 14 additions & 0 deletions .agents/languages/python.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,20 @@ Load this file when changing `python/`, Cython serialization, or Python xlang be
- Cython mode owns the hot runtime path. Do not duplicate core runtime types between Python and Cython, tunnel Python facade methods into hidden Cython internals, or keep dead shims unless the user explicitly needs a compatibility module path.
- Use explicit Cython fields and methods for fixed hot-path shapes. Avoid `__getattr__`, generic `object` fields, public bridge internals, or `Fory` backreferences where ownership can stay explicit.
- Keep Python and Cython context/ref-tracking branch conditions and stack mutations semantically aligned unless a documented intentional difference exists.
- Root deserialization graph memory budgets are owned by pure-Python and Cython `ReadContext`.
Keep `max_graph_memory_bytes` public on `pyfory.Fory`/`Config`; the default effective limit is
fixed `128 MiB`, positive explicit values override it, and explicit non-positive values are
invalid at config creation. Byte and stream roots use the same
configured/default budget behavior. Do not mirror the configured max into a
second active-limit field; keep one configured max plus mutable remaining
budget. `ReadContext` may expose only raw
byte reservation; collection, dict, array, struct, and object
formulas belong in the pure-Python or Cython serializer owner. Lists, tuples, sets, and
object-dtype ndarray item storage reserve nonzero owner self cost plus `count * PyObject*`; dicts
reserve nonzero owner self cost plus `entryCount * 2 * PyObject*`. Python object owners reserve a
nonzero shallow self cost plus shallow field/reference storage. Keep string, bytes, primitive
scalar, `array.array`, primitive dense array, and primitive ndarray owners skipped, and preserve
byte-availability checks after budget reservation.
- Public value constructors should accept normal Python values. Raw-bit, raw-buffer, and memoryview entry points should be explicit low-level APIs, and packed carriers should expose the buffer protocol from the actual storage owner when appropriate.
- When debugging runtime or benchmark behavior, install the local package into the exact interpreter under test instead of relying on mixed `PYTHONPATH` state.
- For wheel or extension pipeline changes, derive extension-module paths from current build targets, packaging config, or wheel payload discovery rather than historical module names.
Expand Down
Loading
Loading