compiler/project.xml now passes --backend native --debug-opdf for the
blaise-compiler module, so local builds of the compiler and TestRunner
exercise the native x86-64 backend end-to-end and are debuggable with
pdr. The shipped default backend remains QBE.
Compiling the compiler itself natively (never done before) exposed two
pre-existing native codegen bugs, both fixed:
- Local dynamic-array variables were not zero-initialised. SetLength
reads the old data pointer and the epilogue releases it, so stack
garbage in the slot corrupted the heap — the unit→.o iface-embed
path crashed in the allocator. Dyn-array locals now start nil like
string/class/record locals. New e2e test
TestRun_Native_LocalDynArray_DirtyStack pins this with a
dirty-stack helper.
- P[I] := Chr(N) stored the low byte of the _Chr-allocated STRING
POINTER instead of N: the native backend lacked the QBE backend's
EmitByteRhs short-circuit. Added EmitByteRhsToEax (Chr folds to its
argument, single-char literals to their ordinal) and applied it at
every byte-sized store site (PChar subscript, dyn/static array
byte elements, P^ byte writes, byte array-field elements). This
corrupted every ELF header patch in uElfObject, producing .o files
with garbage e_shoff/e_shnum.
With both fixes the full separate-compilation round trip works under
the all-native toolchain and the complete suite passes (2959 tests)
with a natively-built compiler and TestRunner.
uDebugOPDF: interface-typed globals are two labels (Name_obj/_itab);
recGlobalVar now references Name_obj so --debug-opdf links for
programs with interface globals (e.g. the compiler's own CG).
Separate always-linked runtime code (system.pas, ARC, strings, platform
abstraction) from opt-in standard library units (sysutils, classes, math,
dateutils, generics, etc.). This mirrors the Go runtime/ vs stdlib, Rust
core vs std, and Swift SwiftRuntime vs SwiftCore patterns.
- runtime/ contains code linked into every binary + C shims
- stdlib/ contains units imported explicitly via uses clause
- Single platform abstraction layer (rtl.platform.*) in runtime/,
shared by both runtime/ and stdlib/ units
- bcl.testing renamed to blaise.testing across all 95+ test files
- Updated PasBuild project.xml, fixpoint.sh, README, unit search paths
- All 1931 tests pass, fixpoint OK (stage-3/stage-4)
Switch pasbuild test goal to use Blaise as compiler by adding the RTL
unit path to the build <unitPaths> in compiler/project.xml. This mirrors
the fixpoint pipeline exactly: Blaise compiles itself, then compiles the
test runner.
Core fixes to make the Blaise-compiled test suite green:
bcl.testing.pas: rename duplicate on E: variable names (EAF/EIT/ETO)
to prevent ARC triple-release of the caught exception object (KI-3).
bcl.testing.runner.text.pas: implement --suite / --suite Class.Method
CLI filtering (Step 15); also adds TestClassName() via typeinfo[2]
read for the class name lookup. Fixes 0-based Pos split for --suite
argument parsing.
uParser.pas, uSemantic.pas: guard explicit-receiver .Free + reassign
patterns with { FPC} so ARC does not double-release the field
slot (KI-2). Three call sites: GID.IntfDef, GD.ClassDef in the
parser, and GII.IntfDef in InstantiateGenericInterface.
cp.test.sets.pas: rename duplicate on ESE/EEx exception variables.
cp.test.exceptions.pas, cp.test.multiwrite.pas: fix PosEx loop
termination — Blaise returns -1 (not 0) for not-found; start index
is 0-based.
cp.test.arc.pas and seven other test files: fix absence checks that
used Pos(...) = 0 (FPC not-found sentinel); changed to < 0.
cp.test.stringops.pas: replace emoji literal '😀' with 'AB' to work
around parser limitation with bytes > 127 in string literals (KI-1);
test still exercises the same CoerceToCharOrd semantic-error path.
Result: pasbuild test -m blaise-compiler --compiler ./compiler/target/blaise
passes with 1053 tests, 0 failures, 0 errors.
- Move RTL unitPath from <build> to <test> section in project.xml —
FPC picks up Blaise's system.pas when RTL is on the build path
- Guard IR caching code (TSearchRec/FindFirst) with { FPC} —
Blaise doesn't support these SysUtils types
- Add LineEnding constant under { FPC} in bcl.testing for
Blaise-compiled test units
- Replace empty array literal [] with 3-arg CompileAndRun overload
- Migrate cp.test.tokenkindname from fpcunit to bcl.testing; replace
Format/Low/High with Blaise-compatible alternatives
- Increase QBE NString from 80 to 160 — method names like
TInterfaceTests_TestSemantic_ClassWithInterfaceAsFirstParent_
InheritsFromTObject exceed the old limit
On the exception path of a try/finally block, release in-scope string
variables before re-raising so that heap-allocated string buffers are
freed even when exceptions unwind through the frame.
After each StringRelease the stack slot is zeroed so that nested
finally handlers see a nil pointer and take the no-op release path,
preventing double-free on deep exception chains.
Adds FCurrentBlock field and EmitExcPathArcCleanup to TCodeGenQBE.
Two new codegen tests verify position and zeroing behaviour.