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
1 change: 1 addition & 0 deletions CHANGELIST.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ Z3 SMT solver bindings as a dynamic module, dasLLVM-style.
- **Unwind tables on emitted functions** when the host uses C++ exceptions (#3347)
- **JIT debug tooling** (#3511); **`llvm_tune` per-box UX** (#3403) - scope / policy / `--tune`, self-tuning servers, `-exe` fix
- **AOT batch-composition hash fix** (`g_isInAot` leak) + `aot_cpp` made AOT-linkable (#3409); **AOT fuzzer-failure hardening** (#3303)
- **Standalone contexts link C++ modules** (#3947) - a `-ctx` context that reaches dasHV, fio or any handled type registers the modules it links (the builtin set in the C++ registrar's order, then dependencies-first) on first construction through a process-wide list (`include/daScript/simulate/standalone_modules.h`), so several generated contexts in one binary share one registry lifetime that ends with `Module::ShutdownStandalone` when the last context is destroyed; a builtin module the program calls at run time keeps its AOT header, the function table is dense (a slot per function the context still reaches), and `examples/standalone/06_full_runtime` (dasHV + fio, static, compiles nothing at run time, loads no shared module) is the worked example and a small-lane test
- **LLVM-AOT in a large embedding host** (#3715) - scalar call ABI matched at bool/reference seams, target triple + data layout pinned on emitted objects, `-dll-path`/`DAS_DLL_PATH` dasbind search, per-object glob-init deferred to first link

#### Runtime, Tooling, and Hosting
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ Task-specific instructions are split into skill files under `skills/`. You MUST
| `skills/internal/documentation_rst.md` | Editing RST in `doc/source/`, `//!` doc-comments in `daslib/*.das`, tutorial RST pages |
| `skills/internal/tutorials.md` | Anything that looks like a tutorial - they live under `/tutorials/<area>/`, NEVER `modules/<X>/tutorial/` |
| `skills/internal/tutorial_prose.md` | WRITING or revising general-reader doc/tutorial prose (`documentation_rst.md` is mechanics, this is the words) |
| `skills/cpp_integration.md` | Embedding daslang in C++; binding types/functions/enums; shipping without the compiler (`libDaScriptNano`) |
| `skills/cpp_integration.md` | Embedding daslang in C++; binding types/functions/enums; shipping without the compiler (`libDaScriptNano`, or a standalone context on the full runtime) |
| `skills/internal/cpp_codebase_notes.md` | Working on daslang's own C++ - where inference/builtins/errors/parser live, AST function flags |
| `skills/internal/clang_bind_build.md` | Enabling `dasClangBind` / bumping the libclang SDK / running any `bind_*.das` self-binder |
| `skills/daslib_modules.md` | Working with `daslib/` modules or extending the stdlib |
Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1771,6 +1771,7 @@ SET(DAS_SIMULATE_INCLUDES
include/daScript/simulate/simulate_visit_op.h
include/daScript/simulate/simulate_visit_op_undef.h
include/daScript/simulate/standalone_ctx_utils.h
include/daScript/simulate/standalone_modules.h
)

install(FILES
Expand Down
54 changes: 54 additions & 0 deletions daslib/ARCHITECTURE_EMIT.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,20 @@ Companion to `ARCHITECTURE.md` in this folder; section numbers are unique across
`set_aot_main_module_name` writes the daslib global AND forwards to
`set_aot_main_module_name_cpp`; a spelling rule changed on one side only produces a TU
where the definition and its debug-info references disagree.
- **`fromExtraDependency` describes the host process, not the program being emitted.** The
flag is set when the host first loaded a shared module as an extra dependency (a `-jit`
host loads `strings`, `fio_core` and `math` that way) and stays on the shared module for
every later compile in the process. `getRequiredModulesFor` skips such modules only on the
regular AOT path; a standalone context decides by its linked set alone, otherwise a
generator running under a `-jit` host (the JIT test lane) prunes the modules the program
calls.
- **`DEFAULT_MODULE_ORDER` mirrors `register_builtin_modules_impl`** in
`src/builtin/modules.cpp` - the same builtin C++ modules in the same order, a
daslib-to-C++ pair `tests/aot/test_standalone_emit.das` reads back from the C++ source and
pins. A standalone context registers these first because
module constructors `Module::require` earlier ones by name (`fio_core` takes `strings`,
dasHV takes `rtti_core`). A module missing from the daslib list still registers, only in
the dependencies-first pass that follows; a module added to the C++ side joins the list.

## 6. aot_standalone

Expand Down Expand Up @@ -79,6 +93,46 @@ Companion to `ARCHITECTURE.md` in this folder; section numbers are unique across
`fnByMangledName` call that would crash at runtime. `prepareProgramForEmission` runs
`NoAotMarker` first (the regular AOT paths run it too; standalone must match) and
then `checkAllUsedFunctionsCanAot` walks used, non-builtin functions.
- **The function table is dense** - `addFunctionInfo` numbers the emitted rows in emission
order and the ctor sizes `context.functions` by that count, not by the program's
`totalFunctions`. The program count includes every function the interpreter simulated
(externs among them), while the context emits only what it still reaches; a table sized
by the larger count leaves rows of uninitialized memory that the destructor's shutdown
walk (`runShutdownScript`) reads. Nothing reads a function by program index: AOT calls
are direct, function pointers resolve through `fnByMangledName`, and `FillFunction`
matches rows by AOT hash.
- **A context links the modules the program reaches, and registers the C++ ones itself.**
`aot_cpp.das`'s `collectLinkedModules` marks the module of every used function, of every
function a used function or global calls (`UseTypeMarker` reads the callee of each call,
operator and `@@` address - externs carry no `used` flag of their own), and of every
struct, enum and handled type; a program that reaches no C++ module beyond the builtin one
links exactly that set. A nano program reaches none by contract (every builtin module is
absent there), so its output stays registry-free.
Once it reaches one, the default C++ modules the compiler loaded and every linked C++
module's `module_for_each_dependency` closure join the set, because module constructors
`Module::require` those by name (dasHV takes `rtti_core` this way). The pruned modules
(`compile time only, not linked`) get no `aotRequire` include and no registration.
`standaloneModuleRegistration` orders the C++ subset and ranks it: `DEFAULT_MODULE_ORDER`
first (the pair it mirrors is recorded in sec. 5), then the rest dependencies-first, ranked
by dependency depth. Each generated TU emits its list as a `StandaloneModule` table added to
the process-wide list before main, and the context class takes `StandaloneModuleScope`
(`include/daScript/simulate/standalone_modules.h`, inline so every TU shares one copy) as
its FIRST base, ahead of `Context`: constructed before it, destroyed after it. The first
scope constructed registers the union, rank order, and initializes once; the last scope
destroyed shuts down - inside main, after the last context's own teardown and while the
runtime's statics still stand. A static destructor cannot do this: it runs after main,
when statics constructed later than it (libhv's, the runtime's own) are already gone, and
on Windows that shutdown corrupts the heap - the exit-time race the `-exe` path avoids by
shutting down before main returns. Two contexts with different module sets in one binary
therefore share one lifetime. A host that registered the builtin module owns the registry
instead: the context registers nothing and stops the program, by name, on a linked module
the host did not register - the runtime cannot add to an initialized registry and keep
`Initialize`/`Shutdown` balanced, and a second shutdown would walk a registry the first
one deleted. The shutdown is `Module::ShutdownStandalone`, never `Module::Shutdown`: the
latter resets the fusion engine through a function pointer only the interpreter's
`simulate_fusion.cpp` installs, and a standalone binary links no interpreter. Handled
types need the registry because `TypeInfo::resolveAnnotation` walks the bound
environment's module list; a context with none dereferences a null environment.
- **Type definitions live in the header, once** - struct/enum definitions (the
dependency dump plus the entry module's own `declarations` capture) are emitted into
the `.das.h`, which the `.das.cpp` includes; the source never redefines them. They sit
Expand Down
8 changes: 4 additions & 4 deletions daslib/REVIEW.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ survives into the sibling loop's exit path and unbalances its counter.

**A diff that adds or changes a daslib fact - code or a `//!` contract - whose truth is
decided by a C++-side definition, with no test, lint, or compile error failing when the two
sides no longer match, records the pair in the architecture doc, in its module's section,
naming both sides.**
sides no longer match, records the pair in the architecture doc, in the section of the file
the daslib side lives in, naming both sides.**

**When a diff changes one side of a recorded daslib/C++ pair so the two no longer match, it
changes the other side and updates the pair's architecture-doc entry in the same diff.**
Expand Down Expand Up @@ -117,8 +117,8 @@ set without the cap is a silently missed finding; raising a cap without the over
suggestion that does not compile.

**A diff that adds or changes an emit entry point - a function that runs the emit visitor
(`CppAot` or any subclass of it) and then returns or writes the generated C++ - keeps the
error check ahead of that return or write.** The error check is the program's
(`CppAot` or any subclass of it) and then writes the generated C++ to a file - keeps the
error check ahead of that file write.** The error check is the program's
`macroException`/`failToCompile` state, read directly or through `log_aot_emit_errors`; a
codegen exception mid-visit leaves partial C++.

Expand Down
Loading
Loading