refactor(rtl): relocate RTL units into the compiler tree (dotted-flat names)

This commit is contained in:
Graeme Geldenhuys 2026-06-25 16:05:44 +01:00
parent bdca25c99e
commit ac9e2fa0b1
33 changed files with 77 additions and 134 deletions

View file

@ -7,7 +7,8 @@
<mainSource>Blaise.pas</mainSource>
<executableName>blaise</executableName>
<unitPaths>
<path>../runtime/src/main/pascal</path>
<!-- RTL units (runtime.*) now live in this module's own source dir;
only stdlib remains a separate unit-path. -->
<path>../stdlib/src/main/pascal</path>
</unitPaths>
</build>
@ -15,7 +16,6 @@
<test>
<testSource>TestRunner.pas</testSource>
<unitPaths>
<path>../runtime/src/main/pascal</path>
<path>../stdlib/src/main/pascal</path>
</unitPaths>
</test>

View file

@ -31,7 +31,7 @@
destruction -- no TOCTOU race.
}
unit blaise_arc;
unit runtime.arc;
interface

View file

@ -6,7 +6,7 @@
See LICENSE file in the project root for full license terms.
}
unit blaise_atomic;
unit runtime.atomic;
// Atomic 32-bit add/sub primitives used by ARC reference counting.
//

View file

@ -27,7 +27,7 @@
threadvar, giving each thread its own exception chain.
}
unit blaise_exc;
unit runtime.exc;
interface

View file

@ -24,7 +24,7 @@
data_ptr + 0 : char data + NUL
}
unit blaise_float;
unit runtime.float;
interface

View file

@ -44,7 +44,7 @@
go to the wrong thread's list).
}
unit blaise_mem;
unit runtime.mem;
interface

View file

@ -28,7 +28,7 @@
writing Dest[i], so full overlap is safe.
}
unit blaise_set;
unit runtime.set;
interface

View file

@ -6,7 +6,7 @@
See LICENSE file in the project root for full license terms.
}
unit blaise_setjmp;
unit runtime.setjmp;
// setjmp/longjmp for the exception runtime (try/except, try/finally).
//

View file

@ -6,7 +6,7 @@
See LICENSE file in the project root for full license terms.
}
unit blaise_start;
unit runtime.start;
// Program entry point (x86_64, System V ABI, glibc-compatible).
//

View file

@ -29,7 +29,7 @@
RefCount = -1 marks immortal (statically-allocated string literals).
}
unit blaise_str;
unit runtime.str;
interface

View file

@ -6,7 +6,7 @@
See LICENSE file in the project root for full license terms.
}
unit blaise_thread;
unit runtime.thread;
{ POSIX thread primitives direct bindings to pthread and sysconf.
No C shim required; all functions use the standard C ABI which QBE

View file

@ -6,7 +6,7 @@
See LICENSE file in the project root for full license terms.
}
unit blaise_utf8;
unit runtime.utf8;
// UTF-8 code-point counter SIMD-accelerated (AVX2 with an SSE2 fallback and
// a scalar tail), with a one-time CPUID probe for AVX2.

View file

@ -40,7 +40,7 @@
runs and before the block is freed.
}
unit blaise_weak;
unit runtime.weak;
interface

View file

@ -750,7 +750,7 @@ begin
FCompiler := '/tmp/fp_blaise2';
if not FileExists(FCompiler) then
FCompiler := '/tmp/fp_blaise3';
FRTLPath := ProjectRoot() + 'runtime/src/main/pascal';
FRTLPath := ProjectRoot() + 'compiler/src/main/pascal';
FStdlibPath := ProjectRoot() + 'stdlib/src/main/pascal';
FRTL := ProjectRoot() + 'compiler/target/blaise_rtl.a';
FScratch := ProjectRoot() + 'compiler/target/asm_scratch/';

View file

@ -142,7 +142,7 @@ begin
FCompiler := '/tmp/fp_blaise3';
if not FileExists(FCompiler) then
FCompiler := '/tmp/fp_blaise2';
FRTLPath := ProjectRoot() + 'runtime/src/main/pascal';
FRTLPath := ProjectRoot() + 'compiler/src/main/pascal';
FStdlibPath := ProjectRoot() + 'stdlib/src/main/pascal';
FRTL := ProjectRoot() + 'compiler/target/blaise_rtl.a';
FScratch := ProjectRoot() + 'compiler/target/cli_scratch/';

View file

@ -181,11 +181,11 @@ begin
Lines := TStringList.Create();
Paths := TStringList.Create();
try
Lines.Add('unit-path=../../runtime/src/main/pascal');
Lines.Add('unit-path=../../compiler/src/main/pascal');
ParseConfigLines(Lines, '/data/devel/new-pascal-compiler/compiler/target/', Paths);
AssertEquals('one path', 1, Paths.Count);
AssertEquals('resolved',
'/data/devel/new-pascal-compiler/compiler/target/../../runtime/src/main/pascal',
'/data/devel/new-pascal-compiler/compiler/target/../../compiler/src/main/pascal',
Paths.Strings[0]);
finally
Lines.Free();

View file

@ -189,7 +189,9 @@ begin
FRTL := GetEnvironmentVariable('BLAISE_RTL');
if FRTL = '' then
FRTL := ProjectRoot() + 'runtime/target/blaise_rtl.a';
FRTLUnitPath := ProjectRoot() + 'runtime/src/main/pascal';
{ RTL units (runtime.*, rtl.platform.*) now live in the compiler's own source
tree after the RTL-unification move; the old runtime/src/main/pascal is empty. }
FRTLUnitPath := ProjectRoot() + 'compiler/src/main/pascal';
FStdlibUnitPath := ProjectRoot() + 'stdlib/src/main/pascal'
end;

View file

@ -71,7 +71,7 @@ const
{ A clean program: object is created and properly released by ARC at scope exit. }
SrcNoLeak = '''
program P;
uses blaise_arc;
uses runtime.arc;
type
TBox = class
Value: Integer;
@ -92,7 +92,7 @@ const
use-after-free. With the fix it is freed exactly once: no leak, no crash. }
SrcExceptionHandlerVar = '''
program P;
uses blaise_arc;
uses runtime.arc;
type
Exception = class
FMessage: string;
@ -116,7 +116,7 @@ const
{ Constructor with args — must not double-AddRef; object must be clean after scope. }
SrcConstructorWithArgs = '''
program P;
uses blaise_arc;
uses runtime.arc;
type
TBox = class
Value: Integer;
@ -137,7 +137,7 @@ const
{ Deliberately leaked: object assigned to a raw Pointer, bypassing ARC release. }
SrcOneLeak = '''
program P;
uses blaise_arc;
uses runtime.arc;
type
TBox = class
Value: Integer;
@ -157,7 +157,7 @@ const
{ Two distinct classes leaked to verify count and class-name reporting. }
SrcTwoLeaks = '''
program P;
uses blaise_arc;
uses runtime.arc;
type
TAlpha = class
X: Integer;
@ -182,7 +182,7 @@ const
{ Reference cycle: each object holds the other — both leak. }
SrcCycleLeak = '''
program P;
uses blaise_arc;
uses runtime.arc;
type
TNode = class
Other: TNode;
@ -204,7 +204,7 @@ const
line number where the leaking TBox.Create() call was made. }
SrcLeakWithSite = '''
program LeakSite;
uses blaise_arc;
uses runtime.arc;
type
TBox = class
Value: Integer;
@ -222,7 +222,7 @@ const
Extra AddRef prevents scope-exit release from freeing it. }
SrcStringLeak = '''
program P;
uses blaise_arc;
uses runtime.arc;
var
S: string;
begin
@ -235,7 +235,7 @@ const
{ Clean string usage: no leak expected — scope-exit ARC releases properly. }
SrcStringClean = '''
program P;
uses blaise_arc;
uses runtime.arc;
var
S: string;
begin
@ -297,7 +297,7 @@ const
allocation site as 'generics.collections:<line>', not '<program>:<line>'. }
SrcGenericAllocSite = '''
program LeakGen;
uses blaise_arc, generics.collections;
uses runtime.arc, generics.collections;
var
L: TList<Integer>;
E: TListEnumerator<Integer>;

View file

@ -349,12 +349,12 @@ begin
AssertTrue('expected several RTL members, got '
+ IntToStr(Members.Count), Members.Count >= 5);
{ A member whose name exceeds 15 chars exercises the GNU long-name (//)
table. rtl_platform_layout_linux.o is the longest current RTL member. }
table. rtl.platform.layout.linux.o is the longest current RTL member. }
SawLongName := False;
for I := 0 to Members.Count - 1 do
begin
M := Members.Get(I);
if M.Name = 'rtl_platform_layout_linux.o' then
if M.Name = 'rtl.platform.layout.linux.o' then
SawLongName := True;
{ Every member must parse as a valid x86-64 relocatable object
with at least its NULL section + one real section. }
@ -366,7 +366,7 @@ begin
Obj.Free();
end;
end;
AssertTrue('long-named member rtl_platform_layout_linux.o not found '
AssertTrue('long-named member rtl.platform.layout.linux.o not found '
+ '(GNU long-name table mishandled?)', SawLongName);
finally
for I := 0 to Members.Count - 1 do
@ -1230,7 +1230,7 @@ procedure TInternalLinkerE2ETests.SetUp;
begin
inherited SetUp();
FCompiler := ProjectRoot() + 'compiler/target/blaise';
FRTLPath := ProjectRoot() + 'runtime/src/main/pascal';
FRTLPath := ProjectRoot() + 'compiler/src/main/pascal';
FStdlibPath := ProjectRoot() + 'stdlib/src/main/pascal';
FScratch := ProjectRoot() + 'compiler/target/intlink_scratch/';
ForceDirectories(FScratch);

View file

@ -192,7 +192,7 @@ var
begin
inherited SetUp();
ExeDir := ExtractFilePath(ParamStr(0));
FRTLUnitPath := ExpandFileName(ExeDir + '../../runtime/src/main/pascal');
FRTLUnitPath := ExpandFileName(ExeDir + '../../compiler/src/main/pascal');
FStdlibUnitPath := ExpandFileName(ExeDir + '../../stdlib/src/main/pascal');
end;

View file

@ -91,7 +91,7 @@ var
begin
inherited SetUp();
ExeDir := ExtractFilePath(ParamStr(0));
FRTLUnitPath := ExpandFileName(ExeDir + '../../runtime/src/main/pascal');
FRTLUnitPath := ExpandFileName(ExeDir + '../../compiler/src/main/pascal');
FStdlibUnitPath := ExpandFileName(ExeDir + '../../stdlib/src/main/pascal');
end;

View file

@ -79,7 +79,7 @@ var
begin
inherited SetUp();
ExeDir := ExtractFilePath(ParamStr(0));
FRTLUnitPath := ExpandFileName(ExeDir + '../../runtime/src/main/pascal');
FRTLUnitPath := ExpandFileName(ExeDir + '../../compiler/src/main/pascal');
FStdlibUnitPath := ExpandFileName(ExeDir + '../../stdlib/src/main/pascal');
end;

View file

@ -122,7 +122,7 @@ var
begin
inherited SetUp();
ExeDir := ExtractFilePath(ParamStr(0));
FRTLUnitPath := ExpandFileName(ExeDir + '../../runtime/src/main/pascal');
FRTLUnitPath := ExpandFileName(ExeDir + '../../compiler/src/main/pascal');
FStdlibUnitPath := ExpandFileName(ExeDir + '../../stdlib/src/main/pascal');
end;

View file

@ -5,14 +5,19 @@
# Licensed under the Apache License v2.0 with Runtime Library Exception.
# See LICENSE file in the project root for full license terms.
#
# Each RTL unit is compiled directly via Blaise's unit-as-top-level mode: a
# single `blaise --source X.pas --output X.o` invocation produces the object.
# The RTL is now entirely pure Pascal (the four hand-written *_x86_64.s files
# were migrated to inline-asm `.pas` units), so the whole archive builds through
# Blaise's own internal assembler — no external assembler, no gcc, no .s files.
# Builds blaise_rtl.a from the RTL units. The RTL sources now live in the
# COMPILER's own source tree (compiler/src/main/pascal/runtime.*.pas — the
# dotted-flat unit names runtime.atomic, runtime.str, …) as part of the
# RTL-unification work; this Makefile is the transitional archive producer that
# keeps cold-bootstrap working from an existing release until the compiler
# itself produces the RTL object cache (see docs/rtl-unification-plan.adoc).
#
# Each RTL unit is compiled via Blaise's unit-as-top-level mode, with
# --assembler internal so the whole archive builds through Blaise's own
# in-process assembler — no external assembler, no gcc, no .s files.
SHELL = /bin/bash
PAS_SRC_DIR = src/main/pascal
PAS_SRC_DIR = ../compiler/src/main/pascal
OBJ_DIR = target
LIB = $(OBJ_DIR)/blaise_rtl.a
@ -20,37 +25,26 @@ LIB = $(OBJ_DIR)/blaise_rtl.a
# driver finds it automatically next to itself.
COMPILER_BIN = ../compiler/target
BLAISE = $(COMPILER_BIN)/blaise
# This Makefile IS a hand-managed separate-compilation system: it compiles each
# RTL unit to its own object and archives an explicit object list. The
# compiler's own incremental mode (now the default) would, on top of that, write
# per-dependency side-effect .o files next to each output and skip inlining a
# used unit's bodies — but those side-effect objects are not in the archive's
# object list, so a cross-unit symbol (e.g. typeinfo_TRtlPlatform, referenced by
# the derived TRtlPlatformPosix in another unit) ends up undefined at link.
# Force whole-program compilation per unit so every unit object is self-contained.
#
# --assembler internal: assemble each unit to its .o with Blaise's own in-process
# assembler instead of `cc -c`, so building the RTL needs no external assembler.
# Whole-program per unit (--no-incremental) so every unit object is
# self-contained (no undefined cross-unit typeinfo symbols at archive link).
BLAISE_FLAGS = --no-incremental --assembler internal
# Every RTL unit is now pure Pascal (the four hand-written *_x86_64.s files —
# start, setjmp, atomic, utf8 — were migrated to inline-asm `.pas` units). The
# RTL therefore builds entirely through Blaise's own pipeline: no $(CC), no
# external assembler, no .s files.
PAS_OBJS = $(OBJ_DIR)/blaise_start.o \
$(OBJ_DIR)/blaise_atomic.o \
$(OBJ_DIR)/blaise_setjmp.o \
$(OBJ_DIR)/blaise_utf8.o \
$(OBJ_DIR)/blaise_mem.o \
$(OBJ_DIR)/blaise_str.o \
$(OBJ_DIR)/blaise_set.o \
$(OBJ_DIR)/blaise_arc.o \
$(OBJ_DIR)/blaise_weak.o \
$(OBJ_DIR)/blaise_float.o \
$(OBJ_DIR)/blaise_thread.o \
$(OBJ_DIR)/blaise_exc.o \
$(OBJ_DIR)/rtl_platform_layout_linux.o \
$(OBJ_DIR)/rtl_platform_posix.o
# RTL unit objects. Object basenames mirror the source unit names (dots and
# all); the archive's contents are unchanged in shape from before the rename.
PAS_OBJS = $(OBJ_DIR)/runtime.start.o \
$(OBJ_DIR)/runtime.atomic.o \
$(OBJ_DIR)/runtime.setjmp.o \
$(OBJ_DIR)/runtime.utf8.o \
$(OBJ_DIR)/runtime.mem.o \
$(OBJ_DIR)/runtime.str.o \
$(OBJ_DIR)/runtime.set.o \
$(OBJ_DIR)/runtime.arc.o \
$(OBJ_DIR)/runtime.weak.o \
$(OBJ_DIR)/runtime.float.o \
$(OBJ_DIR)/runtime.thread.o \
$(OBJ_DIR)/runtime.exc.o \
$(OBJ_DIR)/rtl.platform.layout.linux.o \
$(OBJ_DIR)/rtl.platform.posix.o
OBJS = $(PAS_OBJS)
@ -61,63 +55,10 @@ all: $(LIB)
$(LIB): $(OBJS)
ar rcs $@ $^
# --- Pascal unit rules (unit-as-top-level) ---
$(OBJ_DIR)/blaise_utf8.o: $(PAS_SRC_DIR)/blaise_utf8.pas
@mkdir -p $(OBJ_DIR)
$(BLAISE) $(BLAISE_FLAGS) --source $< --unit-path $(PAS_SRC_DIR) --output $@
$(OBJ_DIR)/blaise_start.o: $(PAS_SRC_DIR)/blaise_start.pas
@mkdir -p $(OBJ_DIR)
$(BLAISE) $(BLAISE_FLAGS) --source $< --unit-path $(PAS_SRC_DIR) --output $@
$(OBJ_DIR)/blaise_atomic.o: $(PAS_SRC_DIR)/blaise_atomic.pas
@mkdir -p $(OBJ_DIR)
$(BLAISE) $(BLAISE_FLAGS) --source $< --unit-path $(PAS_SRC_DIR) --output $@
$(OBJ_DIR)/blaise_setjmp.o: $(PAS_SRC_DIR)/blaise_setjmp.pas
@mkdir -p $(OBJ_DIR)
$(BLAISE) $(BLAISE_FLAGS) --source $< --unit-path $(PAS_SRC_DIR) --output $@
$(OBJ_DIR)/blaise_mem.o: $(PAS_SRC_DIR)/blaise_mem.pas
@mkdir -p $(OBJ_DIR)
$(BLAISE) $(BLAISE_FLAGS) --source $< --unit-path $(PAS_SRC_DIR) --output $@
$(OBJ_DIR)/blaise_str.o: $(PAS_SRC_DIR)/blaise_str.pas
@mkdir -p $(OBJ_DIR)
$(BLAISE) $(BLAISE_FLAGS) --source $< --unit-path $(PAS_SRC_DIR) --output $@
$(OBJ_DIR)/blaise_set.o: $(PAS_SRC_DIR)/blaise_set.pas
@mkdir -p $(OBJ_DIR)
$(BLAISE) $(BLAISE_FLAGS) --source $< --unit-path $(PAS_SRC_DIR) --output $@
$(OBJ_DIR)/blaise_arc.o: $(PAS_SRC_DIR)/blaise_arc.pas
@mkdir -p $(OBJ_DIR)
$(BLAISE) $(BLAISE_FLAGS) --source $< --unit-path $(PAS_SRC_DIR) --output $@
$(OBJ_DIR)/blaise_weak.o: $(PAS_SRC_DIR)/blaise_weak.pas
@mkdir -p $(OBJ_DIR)
$(BLAISE) $(BLAISE_FLAGS) --source $< --unit-path $(PAS_SRC_DIR) --output $@
$(OBJ_DIR)/blaise_float.o: $(PAS_SRC_DIR)/blaise_float.pas
@mkdir -p $(OBJ_DIR)
$(BLAISE) $(BLAISE_FLAGS) --source $< --unit-path $(PAS_SRC_DIR) --output $@
$(OBJ_DIR)/blaise_thread.o: $(PAS_SRC_DIR)/blaise_thread.pas
@mkdir -p $(OBJ_DIR)
$(BLAISE) $(BLAISE_FLAGS) --source $< --unit-path $(PAS_SRC_DIR) --output $@
$(OBJ_DIR)/blaise_exc.o: $(PAS_SRC_DIR)/blaise_exc.pas
@mkdir -p $(OBJ_DIR)
$(BLAISE) $(BLAISE_FLAGS) --source $< --unit-path $(PAS_SRC_DIR) --output $@
$(OBJ_DIR)/rtl_platform_layout_linux.o: $(PAS_SRC_DIR)/rtl.platform.layout.linux.pas \
$(PAS_SRC_DIR)/rtl.platform.pas
@mkdir -p $(OBJ_DIR)
$(BLAISE) $(BLAISE_FLAGS) --source $< --unit-path $(PAS_SRC_DIR) --output $@
$(OBJ_DIR)/rtl_platform_posix.o: $(PAS_SRC_DIR)/rtl.platform.posix.pas \
$(PAS_SRC_DIR)/rtl.platform.layout.linux.pas \
$(PAS_SRC_DIR)/rtl.platform.pas
# --- Pascal unit rule (unit-as-top-level) ---
# One pattern rule now suffices: every unit compiles the same way, and the
# object basename equals the unit/source basename.
$(OBJ_DIR)/%.o: $(PAS_SRC_DIR)/%.pas
@mkdir -p $(OBJ_DIR)
$(BLAISE) $(BLAISE_FLAGS) --source $< --unit-path $(PAS_SRC_DIR) --output $@

View file

@ -10,7 +10,7 @@
program bench_blaise_mem_custom;
uses blaise_mem;
uses runtime.mem;
function _TimeNow: Int64; external name '_TimeNow';

View file

@ -25,7 +25,7 @@
program test_blaise_mem;
uses
punit, blaise_mem;
punit, runtime.mem;
{ ------------------------------------------------------------------ }
{ Test: basic GetMem returns non-nil }

View file

@ -14,7 +14,7 @@
program test_blaise_str;
uses
blaise_str;
runtime.str;
procedure _libc_puts(S: PChar); external name 'puts';

View file

@ -33,7 +33,7 @@ unit Classes;
interface
uses
blaise_arc, blaise_thread, StrUtils;
runtime.arc, runtime.thread, StrUtils;
type
TDuplicates = (dupAccept, dupIgnore, dupError);

View file

@ -16,7 +16,7 @@ unit Contnrs;
interface
uses
blaise_arc; { for _ClassRelease }
runtime.arc; { for _ClassRelease }
type
{ ------------------------------------------------------------------ }