diff --git a/compiler/src/main/pascal/Blaise.pas b/compiler/src/main/pascal/Blaise.pas index 5f6a555..171e0ee 100644 --- a/compiler/src/main/pascal/Blaise.pas +++ b/compiler/src/main/pascal/Blaise.pas @@ -941,6 +941,7 @@ begin else CG := TCodeGenQBE.Create(); CG.SetDebugMode(DebugMode); + CG.SetOpdfMode(OPDFEnabled); if IsUnitMode then begin { Unit-as-top-level: emit just the unit's bodies, no program wrapping, no @main. } diff --git a/compiler/src/main/pascal/blaise.codegen.native.pas b/compiler/src/main/pascal/blaise.codegen.native.pas index 64afa5e..80aed06 100644 --- a/compiler/src/main/pascal/blaise.codegen.native.pas +++ b/compiler/src/main/pascal/blaise.codegen.native.pas @@ -57,6 +57,7 @@ type procedure GenerateUnit(AUnit: TUnit); procedure SetSymbolTable(ASymTable: TSymbolTable); procedure SetDebugMode(AEnabled: Boolean); + procedure SetOpdfMode(AEnabled: Boolean); procedure AppendUnit(AUnit: TUnit); procedure AppendProgram(AProg: TProgram); function GetOutput: string; @@ -125,6 +126,13 @@ begin FDebugMode := AEnabled; end; +procedure TCodeGenNative.SetOpdfMode(AEnabled: Boolean); +begin + { No-op: OPDF debug info is not yet wired through the native backend. Its + own vtables are already emitted .globl (see EmitClassSection), so there is + nothing to toggle here. } +end; + procedure TCodeGenNative.Generate(AProg: TProgram); begin Self.EnsureBackend(); diff --git a/compiler/src/main/pascal/uCodeGen.pas b/compiler/src/main/pascal/uCodeGen.pas index 676a83d..39ea269 100644 --- a/compiler/src/main/pascal/uCodeGen.pas +++ b/compiler/src/main/pascal/uCodeGen.pas @@ -44,6 +44,13 @@ type { Enable backend debug/leak-tracking behaviour. } procedure SetDebugMode(AEnabled: Boolean); + { Enable OPDF-debug code shaping. When on, the backend emits class vtables + as exported (global) symbols so the separately-assembled .opdf section can + reference them across object files (the OPDF class record stores each + class's VMTAddress for runtime dynamic-type resolution). Off by default, + so normal builds are byte-for-byte unchanged. } + procedure SetOpdfMode(AEnabled: Boolean); + { Multi-unit compilation: append unit IR to existing output without resetting the output buffer or string-literal table. } procedure AppendUnit(AUnit: TUnit); diff --git a/compiler/src/main/pascal/uCodeGenQBE.pas b/compiler/src/main/pascal/uCodeGenQBE.pas index 336a441..d961ab2 100644 --- a/compiler/src/main/pascal/uCodeGenQBE.pas +++ b/compiler/src/main/pascal/uCodeGenQBE.pas @@ -154,6 +154,9 @@ type procedure EmitMainHeader; procedure EmitMainFooter; procedure EmitTypeInfoDefs(AProg: TProgram); + { 'export data ' when OPDF-debug mode is on (so the .opdf section can + reference the vtable across object files), else plain 'data '. } + function VTableDataPrefix: string; procedure EmitVTableDefs(AProg: TProgram); procedure EmitMethodDefs(AProg: TProgram); procedure EmitInterfaceDefs(AProg: TProgram); @@ -373,6 +376,7 @@ type public FDebugMode: Boolean; FExportAll: Boolean; + FOpdfMode: Boolean; constructor Create; destructor Destroy; override; procedure Generate(AProg: TProgram); @@ -386,6 +390,7 @@ type the units contain class type definitions. Prog.SymbolTable is correct. } procedure SetSymbolTable(ASymTable: TSymbolTable); procedure SetDebugMode(AEnabled: Boolean); + procedure SetOpdfMode(AEnabled: Boolean); procedure SetExportAll(AEnabled: Boolean); procedure AppendUnit(AUnit: TUnit); { Append program IR to existing output (companion to AppendUnit). @@ -6098,8 +6103,11 @@ begin if (TDesc = nil) or not (TDesc is TRecordTypeDesc) then Continue; RT := TRecordTypeDesc(TDesc); if not RT.HasVTable() then Continue; - { TypeInfo pointer is always the first vtable entry } - Line := 'data $vtable_' + ClassSymName(TD.Name) + + { TypeInfo pointer is always the first vtable entry. In OPDF-debug mode the + vtable is exported so the separately-assembled .opdf section can reference + it (the OPDF class record stores each class's VMTAddress); otherwise it + stays a local symbol, keeping non-debug output unchanged. } + Line := VTableDataPrefix() + '$vtable_' + ClassSymName(TD.Name) + ' = { l $typeinfo_' + ClassSymName(TD.Name); for S := 0 to RT.VTableCount() - 1 do begin @@ -6123,7 +6131,7 @@ begin RT := TRecordTypeDesc(GI.TypeDesc); if not RT.HasVTable() then Continue; MName := QBEMangle(GI.TypeName); - Line := 'data $vtable_' + MName + ' = { l $typeinfo_' + MName; + Line := VTableDataPrefix() + '$vtable_' + MName + ' = { l $typeinfo_' + MName; for S := 0 to RT.VTableCount() - 1 do begin E := RT.VTableEntryAt(S); @@ -11191,6 +11199,19 @@ begin FDebugMode := AEnabled; end; +procedure TCodeGenQBE.SetOpdfMode(AEnabled: Boolean); +begin + FOpdfMode := AEnabled; +end; + +function TCodeGenQBE.VTableDataPrefix: string; +begin + if FOpdfMode then + Result := 'export data ' + else + Result := 'data '; +end; + procedure TCodeGenQBE.SetExportAll(AEnabled: Boolean); begin FExportAll := AEnabled;