From 24f410430b33aaf1f288b83ea37e18fa959e9d3e Mon Sep 17 00:00:00 2001 From: _ov4 Date: Tue, 27 Oct 2026 13:30:54 +0000 Subject: docs(memory): describe standard-library allocation and explicit imports Co-Authored-By: Claude Opus 5.5 --- AGENTS/ARCH/LAYOUT.md | 2 +- AGENTS/CONVENTIONS/CALLS.md | 16 ++++++------ AGENTS/CONVENTIONS/EXCEPTIONS_AND_UNITS.md | 6 +++-- AGENTS/CONVENTIONS/STRINGS.md | 2 +- AGENTS/EXTENDING.md | 4 +-- AGENTS/PITFALLS/modules-and-stdlib.md | 8 ++++-- AGENTS/SUBSYSTEMS.md | 4 +-- AGENTS/SUBSYSTEMS/CLASS_LIFETIME.md | 5 ++-- AGENTS/SUBSYSTEMS/MEMORY.md | 40 +++++++++++++++++++----------- AGENTS/SUBSYSTEMS/STDLIB.md | 13 ++++++++-- AGENTS/TESTING.md | 2 +- 11 files changed, 65 insertions(+), 37 deletions(-) (limited to 'AGENTS') diff --git a/AGENTS/ARCH/LAYOUT.md b/AGENTS/ARCH/LAYOUT.md index dc8696e..c2cfee2 100644 --- a/AGENTS/ARCH/LAYOUT.md +++ b/AGENTS/ARCH/LAYOUT.md @@ -23,7 +23,7 @@ | `lib/CodeGen/Designator.cc`, `TypeCheckGen.cc` | TYPE pre-pass, member lookup/calls and lvalue access; type admission and user-kind binary operators | | `lib/CodeGen/CTypeGen.cc` | CodeGen methods for native C scalar conversions, casts, arithmetic and input/output | | `lib/CodeGen/NativeTypeSystem.cc` | Builtin registration, native C type imports/aliases and scalar promotion | -| `lib/CodeGen/MemoryHandler.cc` | Explicit raw memory allocation, resizing and release with a live-address tracking list | +| `lib/CodeGen/MemoryGen.cc` | Keyword NEW/DELETE calls to visible EXTERN helpers in memory.cps; memory.cc owns allocation tracking | | `lib/CodeGen/FileHandler.cc`, `FileRuntimeIO.cc` | File runtime setup/lookup/open and call entry points; read/write/close/EOF helper bodies | | `lib/CodeGen/ArrayHandler.cc`, `ArrayParameters.cc`, `ArrayOutput.cc` | Array allocation/indexing, parameter binding/arguments and whole/subarray output | | `include/cps/CABI.h`, `lib/CodeGen/CABI/ClangABI.cc`, `lib/CodeGen/CABI/Lowering.cc` | EXTERN C ABI: the ABI description, the only file that includes clang CodeGen headers, and the generic lowering of signatures, arguments and returns | diff --git a/AGENTS/CONVENTIONS/CALLS.md b/AGENTS/CONVENTIONS/CALLS.md index 3fc2daa..55b3647 100644 --- a/AGENTS/CONVENTIONS/CALLS.md +++ b/AGENTS/CONVENTIONS/CALLS.md @@ -32,9 +32,10 @@ bridge C void* and nominal pseudocode pointer types. An expression's expected result type filters overloads when present. Overload sets, visibility filtering and exact selection: [SUBSYSTEMS/FUNCTIONS.md](../SUBSYSTEMS/FUNCTIONS.md#signatures-and-call-resolution). -- In all cases, `emitPrototype` rejects names that collide with runtime/libc symbols - (`isReservedRuntimeName`), builtins, or enum values. Signatures retain the first - declaration spelling for LLVM lookup, independently of call-site casing. +- `emitPrototype` rejects builtin and enum names. Ordinary non-EXTERN, non-OVERLOAD + definitions also reject runtime/libc names (`isReservedRuntimeName`); OVERLOAD + definitions have signature-mangled symbols and cannot replace libc symbols. + Signatures retain the first declaration spelling for LLVM lookup, independently of call-site casing. - Methods use `Class.Method` names and a hidden leading receiver address; their FuncSig parameters contain only explicit source parameters. @@ -52,11 +53,12 @@ callback CodeGen injects into FunctionGen). BYVAL arrays copy their buffer at ca entry and clone STRING-bearing elements; BYREF binds the caller's buffer. **Builtins are plain identifiers backed by one table.** Builtins -(EOF/MALLOC/FREE/REALLOC) parse as ordinary calls — no lexer/parser support, and the +(EOF/INT) parse as ordinary calls — no lexer/parser support, and the names are not reserved words. The inline constexpr `Builtins` table in the internal `lib/CodeGen/Builtins.h` ({Name, Arity, ReturnTypeName}) is the single source of truth: `emitCall` checks arity against it before dispatching to the per-builtin emit branches (still an if-chain, ahead of the user-function fallback), and -`getExprTypeInfo` reads return types from it. EOF and the memory builtins consume the -call source line for runtime diagnostics; they touch mutable runtime state and can -throw. +`getExprTypeInfo` reads return types from it. EOF and INT consume the call source +line for runtime diagnostics and can throw. +MALLOC/REALLOC/FREE are ordinary OVERLOAD functions in memory.cps, with no builtin +dispatch or type rules in the compiler. diff --git a/AGENTS/CONVENTIONS/EXCEPTIONS_AND_UNITS.md b/AGENTS/CONVENTIONS/EXCEPTIONS_AND_UNITS.md index deed7ec..8ee97ec 100644 --- a/AGENTS/CONVENTIONS/EXCEPTIONS_AND_UNITS.md +++ b/AGENTS/CONVENTIONS/EXCEPTIONS_AND_UNITS.md @@ -41,8 +41,10 @@ it only on non-library to library calls. Runtime helper line arguments use RuntimeCheck::lineValue too. Compiler diagnostics retain the owning file location. **Default standard library.** The driver extracts embedded std.cps, its imported units -and matching objects to a temporary directory that survives linking/execution. User +and matching objects to a content-keyed cache (or temporary fallback) that survives +linking/execution. User units implicitly import std.cps; normal transitive visibility applies. -no-std -suppresses all default library inputs and objects. Explicit libraries retain the +suppresses all default library inputs and objects. std.cps imports string.cps and +memory.cps; keyword NEW/DELETE require the latter even with -no-std. Explicit libraries retain the ordinary INCLUDE/command-line rules. Source files and objects are embedded by a build-time Perl generator. Saved -S output remains IR only. diff --git a/AGENTS/CONVENTIONS/STRINGS.md b/AGENTS/CONVENTIONS/STRINGS.md index 9bb81cf..d07c217 100644 --- a/AGENTS/CONVENTIONS/STRINGS.md +++ b/AGENTS/CONVENTIONS/STRINGS.md @@ -26,5 +26,5 @@ handles. Records and BYVAL arrays containing STRING recursively copy their string-bearing fields/elements; RETURN and temporary cleanup preserve ownership. C_STRING casts borrow a STRING buffer or construct an owning STRING copy in the other direction. FileHandler owns copied open-file names and frees them on close; READFILE -buffers are copied into STRING and released. Explicit MemoryHandler allocations remain +buffers are copied into STRING and released. Explicit memory-library allocations remain separate from these internal objects. diff --git a/AGENTS/EXTENDING.md b/AGENTS/EXTENDING.md index 5728ac5..358e80e 100644 --- a/AGENTS/EXTENDING.md +++ b/AGENTS/EXTENDING.md @@ -23,7 +23,7 @@ already terminated the block. `Builtins` table in the internal `lib/CodeGen/Builtins.h` (single source of truth — arity checking in `emitCall`, the return type in `getExprTypeInfo`, and the reject-user-redefinition check all read it), then implement IR emission as a method on the fitting handler -(for example MemoryHandler) or inline, and add the name intercept in `CodeGen::emitCall` — null-check every emitted argument before use, like the existing +(for example FileHandler) or inline, and add the name intercept in `CodeGen::emitCall` — null-check every emitted argument before use, like the existing branches do. `emitCall` lives in `ExpressionGen.cc`. Builtins are plain identifiers — nothing is needed in lexer/parser. **New binary operator:** token (if multi-char) → one line in `BinopPrecedence` @@ -80,4 +80,4 @@ also be registered in EmbeddedRunner for static-runtime JIT symbol lookup. `setupExternalFunctions()` (re-declaring the same symbol in two handlers is fine — it dedupes by name). -**Standard-library functions:** define ordinary functions/operators in pseudocode-lib/string.cps with C ABI helpers in string.cc as needed. std.cps imports all public library units. CMake rebuilds and embeds source/object changes; do not add string functions to Builtins.h. Ordinary string literals need STRING.NEW(C_STRING); the compiler bridges OUTPUT/casts/files through C_STR(), INPUT through READ_INPUT(), and READFILE through assignment from C_STRING. +**Standard-library functions:** define ordinary functions/operators in the appropriate pseudocode-lib/*.cps unit with C ABI helpers in the matching .cc as needed. std.cps imports all public library units. CMake rebuilds and embeds source/object changes; do not add standard-library functions to Builtins.h. Memory allocation functions live in memory.cps/memory.cc; only keyword NEW/DELETE need the MemoryGen bridge. Ordinary string literals need STRING.NEW(C_STRING); the compiler bridges OUTPUT/casts/files through C_STR(), INPUT through READ_INPUT(), and READFILE through assignment from C_STRING. diff --git a/AGENTS/PITFALLS/modules-and-stdlib.md b/AGENTS/PITFALLS/modules-and-stdlib.md index 4f6c446..5394d78 100644 --- a/AGENTS/PITFALLS/modules-and-stdlib.md +++ b/AGENTS/PITFALLS/modules-and-stdlib.md @@ -13,11 +13,15 @@ Part of the [pitfalls index](../PITFALLS.md). - GLOBAL accepts only the five primitive scalar types and literal initializers; arrays, user types and computed initializers are rejected. - Own top-level constants remain positional, imported constants do not. -- **Default standard library.** std.cps and its imported STRING library are embedded +- **Default standard library.** std.cps and its imported STRING and memory libraries are embedded and automatically linked. - Use -no-std before explicitly supplying a replacement STRING class/library; otherwise duplicate definitions fail. - Ordinary literals require a visible STRING class with NEW(C_STRING). - C_TYPE/INCLUDE/EXTERN syntax strings are parser metadata and do not construct STRING. - - -S emits IR only; manual linking needs string.o and the C++ runtime. + - Keyword NEW/DELETE and MALLOC/REALLOC/FREE require memory.cps; -no-std users + must explicitly import it. Ordinary constructor/destructor methods still work + without it. + - -S emits IR only; default-library manual linking needs string.o, memory.o and + the C++ runtime. diff --git a/AGENTS/SUBSYSTEMS.md b/AGENTS/SUBSYSTEMS.md index d3a7dba..4753ab1 100644 --- a/AGENTS/SUBSYSTEMS.md +++ b/AGENTS/SUBSYSTEMS.md @@ -18,8 +18,8 @@ Deep-dives on the CodeGen helper subsystems, split by topic under `SUBSYSTEMS/`. - [Runtime checks and exceptions](SUBSYSTEMS/RUNTIME_CHECKS_EXCEPTIONS.md): `RuntimeCheck`, TRY/CATCH/THROW lowering, cleanup pads, EH runtime per platform. - [Files](SUBSYSTEMS/FILES.md): `FileHandler` text-file runtime and open-file table. -- [Explicit memory](SUBSYSTEMS/MEMORY.md): `MemoryHandler` allocation tracking, - MALLOC/REALLOC/FREE. +- [Explicit memory](SUBSYSTEMS/MEMORY.md): standard-library MALLOC/REALLOC/FREE, + allocation tracking and keyword NEW/DELETE bridging. - [Standard library](SUBSYSTEMS/STDLIB.md): `pseudocode-lib/`, embedding, STRING class. - [Templates](SUBSYSTEMS/TEMPLATES.md): template declarations, resolution, cloning, instantiation, body emission. diff --git a/AGENTS/SUBSYSTEMS/CLASS_LIFETIME.md b/AGENTS/SUBSYSTEMS/CLASS_LIFETIME.md index eb7f039..98693e5 100644 --- a/AGENTS/SUBSYSTEMS/CLASS_LIFETIME.md +++ b/AGENTS/SUBSYSTEMS/CLASS_LIFETIME.md @@ -18,7 +18,7 @@ Part of the [subsystem notes](../SUBSYSTEMS.md). Builds on [classes](CLASSES.md) class parameters; `symbolAddress` loads their current object address for all value, lvalue, address-of, receiver and BYREF paths. Field aliases, this and BYREF parameters bind addresses directly. -- Assignment-only `NewExprAST` uses checked MemoryHandler allocation (at least one byte +- Assignment-only `NewExprAST` uses checked memory-library allocation (at least one byte for method-only classes), zero initialization and construction, then rebinds reference slots or copies into other destinations. - Ordinary assignment invokes an exact member OPERATOR<- when available, otherwise it @@ -31,7 +31,8 @@ Part of the [subsystem notes](../SUBSYSTEMS.md). Builds on [classes](CLASSES.md) ordinary DELETE method first, then fields in reverse declaration order. Explicit DELETE method calls remain ordinary calls without field recursion. - Keyword DELETE resolves a class lvalue, validates its allocation start through - MemoryHandler before any destruction, destroys it, then releases it through FREE; + the memory-library validator before any destruction, destroys it, then releases it + through the same runtime as FREE; aliases remain dangling. - Stack lifetimes use a per-function `StackObjects` list saved/restored around function emission. DECLARE and BYVAL copies share ownership registration, including arrays and diff --git a/AGENTS/SUBSYSTEMS/MEMORY.md b/AGENTS/SUBSYSTEMS/MEMORY.md index 8b0ccfc..40cfe9e 100644 --- a/AGENTS/SUBSYSTEMS/MEMORY.md +++ b/AGENTS/SUBSYSTEMS/MEMORY.md @@ -3,29 +3,39 @@ Part of the [subsystem notes](../SUBSYSTEMS.md). Related: [class lifetime](CLASS_LIFETIME.md). -**Explicit memory** (`MemoryHandler`): lazily emits internal allocation/find/release/ -resize helpers and a linked list of live allocation start addresses. +**Explicit memory** lives in `pseudocode-lib/memory.cps` and `memory.cc`. +MALLOC/REALLOC/FREE are ordinary OVERLOAD functions calling `_memory_impl_*` +EXTERN "C" helpers. `lib/CodeGen/MemoryGen.cc` only bridges keyword NEW/DELETE to +visible helper declarations, checking their signatures and using FunctionGen's +C ABI lowering, library call-line hook and exception-aware calls. ## Tracking -- Explicit MALLOC/REALLOC and keyword NEW allocations enter the list; STRING/ARRAY - internals are not tracked here and keep their own ownership. -- Helpers use RuntimeCheck and ExceptionHandler, including source-line arguments and - per-function unwind preparation. -- Sizes accept INTEGER and C integers and convert to native size_t. +- memory.cc owns a linked list of live allocation start addresses. Explicit + MALLOC/REALLOC and keyword NEW share it; STRING/ARRAY internals keep their own + ownership outside the list. +- Errors print the existing reason with __cps_user_line and throw 0. The #LIB call + hook supplies the user line, including keyword NEW/DELETE helper calls. +- Sizes accept INTEGER and every supported C integer (including _Bool) through + ordinary overloads. Wrappers explicitly cast to unsigned long long; C++ converts + that value to native size_t, preserving the old integer conversion behavior. +- std.cps imports memory.cps. With -no-std, explicitly import and supply memory.cps, + including for keyword NEW/DELETE. Missing visible helpers are compiler errors. ## Operations -- `emitValidate` always calls the find helper, including for null, so keyword DELETE +- `_memory_impl_validate` always searches, including for null, so keyword DELETE validates before running destructors. -- FREE validates non-null addresses, unlinks and frees the tracking node, releases the - block and returns the original address. +- FREE validates non-null addresses, unlinks the tracking node, releases the block + and node, and returns the original address. Null is returned without searching. - Zero-byte allocation returns null. -- REALLOC validates non-null addresses before its zero-size release path; null behaves - as MALLOC. Positive-size resizing updates the node only after success, leaving the old - block and record intact on failure. -- Node allocation precedes the user allocation; if the latter fails, its node is freed - before the diagnostic and anonymous throw. +- REALLOC validates non-null addresses before its zero-size release path; null + behaves as MALLOC. Positive-size resizing updates the node only after success, + leaving the old block and record intact on failure. +- Node allocation precedes the user allocation; if the latter fails, its node is + freed before the diagnostic and anonymous throw. +- Keyword NEW reserves at least one byte for method-only classes. NEW constructs + objects and DELETE destroys them; FREE/REALLOC never invoke destruction. ## Limitation diff --git a/AGENTS/SUBSYSTEMS/STDLIB.md b/AGENTS/SUBSYSTEMS/STDLIB.md index d43899f..6c7b14c 100644 --- a/AGENTS/SUBSYSTEMS/STDLIB.md +++ b/AGENTS/SUBSYSTEMS/STDLIB.md @@ -15,10 +15,19 @@ import rules: [CONVENTIONS/EXCEPTIONS_AND_UNITS.md](../CONVENTIONS/EXCEPTIONS_AN reused when identical, otherwise published by atomic rename; the cache is never deleted, so a killed run leaks nothing. Only if no cache directory is usable does it fall back to a temporary `cpsc-std` directory removed on exit. The driver - implicitly imports std.cps unless -no-std is set. std.cps imports string.cps. + implicitly imports std.cps unless -no-std is set. std.cps imports string.cps and memory.cps. - Source/object resources are embedded in installed/released cpsc, which needs no separate library directory; manually linking saved IR still requires the matching - string.o and the C++ runtime. + string.o, memory.o and the C++ runtime for default-library builds. + +## Explicit memory + +- memory.cps defines ordinary OVERLOAD MALLOC/REALLOC/FREE wrappers over memory.cc + C ABI helpers. Sizes support INTEGER and all supported C integers. +- Keyword NEW/DELETE call visible EXTERN helpers through MemoryGen and FunctionGen; + no compiler allocation list or memory builtin dispatch remains. With -no-std, + explicitly import memory.cps, including when only keyword NEW/DELETE is needed. +- Runtime errors print __cps_user_line and throw 0. See [MEMORY.md](MEMORY.md). ## STRING and I/O bridging diff --git a/AGENTS/TESTING.md b/AGENTS/TESTING.md index f3628d2..c00843c 100644 --- a/AGENTS/TESTING.md +++ b/AGENTS/TESTING.md @@ -24,4 +24,4 @@ Perl generators use Random.pm's SHA-256 sequence with explicit big-endian extrac Before committing a test change, build the affected references and run the affected CTest cases. Compiler defects may fail: inspect retained diagnostics and document the failure accurately. Workflow changes follow the commit checks in [ARCH/NIGHTLY.md](ARCH/NIGHTLY.md). No compiler implementation changes belong in a tests-only task. -The explicit STRING library integration fixture lives in `tests/library/exp-string`. CMake copies it to the build tree as `test-cases/i/exp-string`, where relative source paths reach the built library and its object file. It passes -no-std to avoid loading a second library copy. Manifests may supply compiler_args for every native/IR/runner compiler invocation. It uses the ordinary native/runner harness and appears as `i/exp-string` in CTest. +The explicit library integration fixtures live in `tests/library/exp-string` and `tests/library/exp-memory`. CMake copies them to the build tree under `test-cases/i/`, where relative source paths reach the built libraries and their objects. Both pass -no-std to avoid loading a second library copy. exp-string imports std.cps, including memory.cps for its keyword NEW/DELETE; exp-memory imports only memory.cps and checks C integer sizes and shared tracking with NEW/DELETE. Manifests may supply compiler_args for every native/IR/runner compiler invocation. Both use the ordinary native/runner harness and appear as `i/exp-string` and `i/exp-memory` in CTest. -- cgit v1.3.1-4-g156e