From d56a90e5ed984b10ce192d3197e72fba5b4e184c Mon Sep 17 00:00:00 2001 From: Sven/Sarah Barth Date: Thu, 27 May 2021 07:17:15 +0200 Subject: [PATCH] * keep track of symbols that are accessed from a nested/anonymous function that belong to a surrounding scope --- compiler/nld.pas | 2 ++ compiler/procinfo.pas | 7 ++++++ compiler/symdef.pas | 53 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/compiler/nld.pas b/compiler/nld.pas index f66462273f..4fd32fba46 100644 --- a/compiler/nld.pas +++ b/compiler/nld.pas @@ -385,6 +385,8 @@ implementation internalerror(200309289); left:=cloadparentfpnode.create(tprocdef(symtable.defowner),lpf_forload); current_procinfo.set_needs_parentfp(tprocdef(symtable.defowner).parast.symtablelevel); + { reference this as a captured symbol } + current_procinfo.add_captured_sym(symtableentry,fileinfo); { reference in nested procedures, variable needs to be in memory } { and behaves as if its address escapes its parent block } make_not_regable(self,[ra_different_scope]); diff --git a/compiler/procinfo.pas b/compiler/procinfo.pas index 22caeb40ed..98aaddfdd8 100644 --- a/compiler/procinfo.pas +++ b/compiler/procinfo.pas @@ -185,6 +185,8 @@ unit procinfo; procedure add_local_ref_def(def:tdef); procedure export_local_ref_defs; + procedure add_captured_sym(sym:tsym;const fileinfo:tfileposinfo); + function create_for_outlining(const basesymname: string; astruct: tabstractrecorddef; potype: tproctypeoption; resultdef: tdef; entrynodeinfo: tnode): tprocinfo; { Add to parent's list of nested procedures even if parent is a 'main' procedure } @@ -357,6 +359,11 @@ implementation end; end; + procedure tprocinfo.add_captured_sym(sym:tsym;const fileinfo:tfileposinfo); + begin + procdef.add_captured_sym(sym,fileinfo); + end; + function tprocinfo.create_for_outlining(const basesymname: string; astruct: tabstractrecorddef; potype: tproctypeoption; resultdef: tdef; entrynodeinfo: tnode): tprocinfo; begin result:=cprocinfo.create(self); diff --git a/compiler/symdef.pas b/compiler/symdef.pas index fa76e7a1e8..e898c7d887 100644 --- a/compiler/symdef.pas +++ b/compiler/symdef.pas @@ -769,6 +769,13 @@ interface end; pinlininginfo = ^tinlininginfo; + tcapturedsyminfo = record + sym : tsym; + { the location where the symbol was first encountered } + fileinfo : tfileposinfo; + end; + pcapturedsyminfo = ^tcapturedsyminfo; + timplprocdefinfo = record resultname : pshortstring; parentfpstruct: tsym; @@ -782,6 +789,7 @@ interface interfacedef : boolean; hasforward : boolean; is_implemented : boolean; + capturedsyms : tfplist; end; pimplprocdefinfo = ^timplprocdefinfo; @@ -829,6 +837,7 @@ interface procedure SetHasInliningInfo(AValue: boolean); function Getis_implemented: boolean; procedure Setis_implemented(AValue: boolean); + function Getcapturedsyms:tfplist; function getparentfpsym: tsym; public messageinf : tmessageinf; @@ -915,6 +924,8 @@ interface function get_funcretsym_info(out ressym: tsym; out resdef: tdef): boolean; virtual; function get_safecall_funcretsym_info(out ressym: tsym; out resdef: tdef): boolean; virtual; + procedure add_captured_sym(sym:tsym;const filepos:tfileposinfo); + { returns whether the mangled name or any of its aliases is equal to s } function has_alias_name(const s: TSymStr):boolean; @@ -959,6 +970,8 @@ interface property parentfpsym: tsym read getparentfpsym; { true if the implementation part for this procdef has been handled } property is_implemented: boolean read Getis_implemented write Setis_implemented; + { valid if the procdef captures any symbols from outer scopes } + property capturedsyms:tfplist read Getcapturedsyms; end; tprocdefclass = class of tprocdef; @@ -6075,6 +6088,15 @@ implementation end; + function tprocdef.Getcapturedsyms:tfplist; + begin + if not assigned(implprocdefinfo) then + result:=nil + else + result:=implprocdefinfo^.capturedsyms; + end; + + function tprocdef.store_localst: boolean; begin result:=has_inlininginfo or (df_generic in defoptions); @@ -6483,10 +6505,19 @@ implementation procedure tprocdef.freeimplprocdefinfo; + var + i : longint; begin if assigned(implprocdefinfo) then begin stringdispose(implprocdefinfo^.resultname); + if assigned(implprocdefinfo^.capturedsyms) then + begin + for i:=0 to implprocdefinfo^.capturedsyms.count-1 do + dispose(pcapturedsyminfo(implprocdefinfo^.capturedsyms[i])); + end; + implprocdefinfo^.capturedsyms.free; + implprocdefinfo^.capturedsyms:=nil; freemem(implprocdefinfo); implprocdefinfo:=nil; end; @@ -6784,6 +6815,28 @@ implementation end; + procedure tprocdef.add_captured_sym(sym:tsym;const filepos:tfileposinfo); + var + i : longint; + capturedsym : pcapturedsyminfo; + begin + if not assigned(implprocdefinfo) then + internalerror(2021052601); + if not assigned(implprocdefinfo^.capturedsyms) then + implprocdefinfo^.capturedsyms:=tfplist.create; + for i:=0 to implprocdefinfo^.capturedsyms.count-1 do + begin + capturedsym:=pcapturedsyminfo(implprocdefinfo^.capturedsyms[i]); + if capturedsym^.sym=sym then + exit; + end; + new(capturedsym); + capturedsym^.sym:=sym; + capturedsym^.fileinfo:=filepos; + implprocdefinfo^.capturedsyms.add(capturedsym); + end; + + function tprocdef.has_alias_name(const s: TSymStr): boolean; var item : TCmdStrListItem;