[fpc-devel] Overlapping addresses between 2 procedures in dwarf info / 3.2.0
I am looking at some oddity I found following up https://forum.lazarus.freepascal.org/index.php/topic,57568.0.html Unfortunately, I have no code yet to reproduce it. I have looked at the generated debug info, as given by objdump. file format pei-x86-64 Compilation Unit @ offset 0x0: Length: 0xa1 (32-bit) Version: 2 Abbrev Offset: 0x0 Pointer Size: 8 <0>: Abbrev Number: 1 (DW_TAG_compile_unit) <18> DW_AT_producer : Free Pascal 3.2.0 2021/02/21 The following part of the info looks wrong to me (original names replaced): <1>: Abbrev Number: 8 (DW_TAG_subprogram) DW_AT_name : FOO DW_AT_prototyped : 1 DW_AT_calling_convention: 65 (user defined) DW_AT_external : 1 DW_AT_low_pc : 0x10004a990 DW_AT_high_pc : 0x10004adc4 < NOTE THE END ADDR <1>: Abbrev Number: 9 (DW_TAG_subprogram) DW_AT_name : fin$00B0 DW_AT_prototyped : 1 DW_AT_calling_convention: 65 (user defined) DW_AT_low_pc : 0x10004a950 DW_AT_high_pc : 0x10004a988 <1>: Abbrev Number: 8 (DW_TAG_subprogram) DW_AT_name : XYZ DW_AT_low_pc : 0x0 < code not included, not used/called DW_AT_high_pc : 0x0 <1>: Abbrev Number: 6 (DW_TAG_subprogram) ... Several other DW_TAG_subprogram, with address BEFORE FOO, and (as far as I checked also line-numbers before FOO. ... I guess those are included here, because they did not get called before, and the compiler adds the debug info only now ??? ... Or could there be other reasons for the out-of-order inclusion??? <1>: Abbrev Number: 8 (DW_TAG_subprogram) DW_AT_name : BAR DW_AT_prototyped : 1 DW_AT_calling_convention: 65 (user defined) DW_AT_external : 1 DW_AT_low_pc : 0x10004adb0 < NOTE THE START ADDR DW_AT_high_pc : 0x10004ae26 BAR starts within FOO. That seems wrong? (also see the line info below) From the code samples I received from the author, this is NOT a nested proc. This (and the line-info) leads to a crash of the app, when run under gdb, as gdb adjusts the position of breakpoints, and ends setting it into the middle of an asm instruction. According to the author, the crash only happens if there are no calls to XYZ. Otherwise the crash does not happen. I do not have info (yet), if the overlapping addresses are present or not, if XYZ is used. The inclusion/exclusion of XYZ triggers https://gitlab.com/freepascal.org/fpc/source/-/issues/38117 which can be seen in the line-info of this app too (i.e. line info contains none relocated entries that compute to invalid addresses for those lines). ** The line-info of "FOO" [0x00011cee] Extended opcode 2: set Address to 0x10004a990 [0x00011cf9] Set column to 1 [0x00011cfb] Advance Line by 2452 to 2453 [0x00011cfe] Copy [0x00011cff] Advance PC by 37 to 0x10004a9b5 [0x00011d01] Copy [0x00011d5b] Advance Line by -2 to 2453 [0x00011d5d] Copy [0x00011d5e] Advance PC by 9 to 0x10004ad95 [0x00011d60] Special opcode 22: advance Address by 0 to 0x10004ad95 and Line by 23 to 2476 [0x00011d61] Extended opcode 2: set Address to 0x10004adc4 [0x00011d6c] Extended opcode 1: End of Sequence It advances all the way to line 2476 / 0x10004ad95 Then it goes to address 0x10004adc4 (before "End of Sequence") This is inside of "BAR". ** The line info shows that the next line (2484) is within the "not included / not called" proc XYZ [0x00011d6f] Extended opcode 2: set Address to 0x0 [0x00011d7a] Set column to 1 [0x00011d7c] Advance Line by 2483 to 2484 [0x00011d7f] Copy [0x00011d80] Advance PC by 13 to 0xd ** The line-info of "BAR" This continues from the line-info of XYZ (as seen by the none relocated entries) [0x00011db8] Special opcode 9: advance Address by 0 to 0x12c and Line by 10 to 2500 [0x00011dc2] Special opcode 0: advance Address by 0 to 0x17c and Line by 1 to 2504 [0x00011dc3] Advance PC by 80 to 0x1cc [0x00011dc5] Set column to 1 [0x00011dc7] Special opcode 12: advance Address by 0 to 0x1cc and Line by 13 to 2517 [0x00011dc8] Extended opcode 2: set Address to 0x0 [0x00011dd3] Extended opcode 1: End of Sequence ** BAR [0x00011dd6] Extended opcode 2: set Address to 0x10004adb0 [0x00011de1] Set column to 1 [0x00011de3] Advance Line by 2521 to 2522 [0x00011de6] Copy [0x00011de7] Advance PC by 21 to 0x10004adc5 [0x00011de9] Set column to 3 [0x00011deb] Special opcode 0: advance Address by 0 to 0x10004adc5 and Line by 1 to 2523 BAR starts at line 2522 (confirmed by the author). The address 0x10004adb0 could be correct, as procs should afaik start at 16 byte boundaries? Line 2522 at 0x10004adb0 is an entry in the line info table, made by the "copy" statement. - So in conclusion something is wrong there. As for
[fpc-devel] $modeswitch Closures
The attached modeswitch_closures.patch introduces {$modeswitch Closures}; it is included in {$mode Delphi}. There is a distinction between anonymous routines (defined in-place, without a name) and closures (capture the context they are invoked with). The switch encompasses both, but goes for the shorter and catchier name. -- βþ # HG changeset patch # User Blaise.ru # Date 1640457371 -10800 # Sat Dec 25 21:36:11 2021 +0300 + new {$modeswitch Closures}, included in {$mode Delphi} diff -r d880e6695537 -r 3ecaef5e9a49 globals.pas --- a/globals.pas Mon Dec 20 20:55:22 2021 +0300 +++ b/globals.pas Sat Dec 25 21:36:11 2021 +0300 @@ -55,7 +55,7 @@ m_pointer_2_procedure,m_autoderef,m_tp_procvar,m_initfinal,m_default_ansistring, m_out,m_default_para,m_duplicate_names,m_hintdirective, m_property,m_default_inline,m_except,m_advanced_records, - m_array_operators,m_prefixed_attributes]; + m_closures,m_array_operators,m_prefixed_attributes]; delphiunicodemodeswitches = delphimodeswitches + [m_systemcodepage,m_default_unicodestring]; fpcmodeswitches = [m_fpc,m_string_pchar,m_nested_comment,m_repeat_forward, diff -r d880e6695537 -r 3ecaef5e9a49 globtype.pas --- a/globtype.pas Mon Dec 20 20:55:22 2021 +0300 +++ b/globtype.pas Sat Dec 25 21:36:11 2021 +0300 @@ -520,6 +520,7 @@ ansistring; similarly, char becomes unicodechar rather than ansichar } m_type_helpers,{ allows the declaration of "type helper" for all supported types (primitive types, records, classes, interfaces) } + m_closures,{ anonymous routines and closures } m_blocks, { support for http://en.wikipedia.org/wiki/Blocks_(C_language_extension) } m_isolike_io, { I/O as it required by an ISO compatible compiler } m_isolike_program_para, { program parameters as it required by an ISO compatible compiler } @@ -712,6 +713,7 @@ 'FINALFIELDS', 'UNICODESTRINGS', 'TYPEHELPERS', + 'CLOSURES', 'CBLOCKS', 'ISOIO', 'ISOPROGRAMPARAS', ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
[fpc-devel] Functors
I propose that the support for https://en.wikipedia.org/wiki/Function_object be added to the FPC. A subset of such functionality already existed as a part of my implementation of closures, so I extended that part to implement the core feature for allowing functors -- overloading of the call operator: when round brackets are applied to an instance of a record, object/class, or interface type, they are translated into a call to the method Invoke of that instance. The attached proof-of-concept functors-1.patch allows the following test case to be compiled: ---8<--- type I = interface procedure Invoke; end; type C = class(TInterfacedObject, I) class function Invoke(const N: Integer): Integer; overload; procedure Invoke; overload; end; class function C.Invoke(const N: Integer): Integer; begin result := N + 9 end; procedure C.Invoke; begin writeln(ClassName, '.Invoke') end; type H = class helper for C procedure Invoke(const S: string); overload; end; procedure H.Invoke(const S: string); begin writeln('H.Invoke("', S, '")') end; var aC: C; var anI: I; begin aC := C.Create; writeln( aC(33) ); aC('hello'); anI := aC; anI() end. ---8<--- Important design points: 1) Applying round brackets to instances does not collide with the existing syntax; 2) Naturally, helpers are able to turn helpees into functors; 3) Operator () cannot be applied to types -- that would clash with explicit type conversions; 4) Explicit empty argument lists are required -- unorthogonal to routines and procedural variables, but clarity must win here; 5) {$modeswitch Closures} is required (modeswitch_closures.patch from https://lists.freepascal.org/pipermail/fpc-devel/2021-December/044261.html) -- functors are closure-adjacent in the area of functional programming. The parts that are currently missing: 1) Implicit conversion from functors to method pointers -- should be fairly trivial to implement; 2) Support for generics -- should be straightforward as well; 3) The OPERATOR keyword instead of PROCEDURE/FUNCTION for methods Invoke -- should we choose to require it -- would be somewhat more complicated. -- βþ # HG changeset patch # User Blaise.ru # Date 1640402948 -10800 # Sat Dec 25 06:29:08 2021 +0300 + Functors: applying round brackets to instances calls their method Invoke diff -r 3ecaef5e9a49 -r 0ac7231ddc94 pexpr.pas --- a/pexpr.pas Sat Dec 25 21:36:11 2021 +0300 +++ b/pexpr.pas Sat Dec 25 06:29:08 2021 +0300 @@ -2762,45 +2762,73 @@ else begin - { is this a procedure variable ? } - if assigned(p1.resultdef) and - (p1.resultdef.typ=procvardef) then -begin - { Typenode for typecasting or expecting a procvar } - if (p1.nodetype=typen) or - ( - assigned(getprocvardef) and - equal_defs(p1.resultdef,getprocvardef) - ) then + if assigned(p1.resultdef) then +case p1.resultdef.typ of + { a procedural variable } + procvardef: begin - if try_to_consume(_LKLAMMER) then + { Typenode for typecasting or expecting a procvar } + if (p1.nodetype=typen) or + ( + assigned(getprocvardef) and + equal_defs(p1.resultdef,getprocvardef) + ) then begin - p1:=comp_expr([ef_accept_equal]); - consume(_RKLAMMER); - p1:=ctypeconvnode.create_explicit(p1,p1.resultdef); + if try_to_consume(_LKLAMMER) then +begin + p1:=comp_expr([ef_accept_equal]); + consume(_RKLAMMER); + p1:=ctypeconvnode.create_explicit(p1,p1.resultdef); +end + else +again:=false end else -again:=false -end +begin + if try_to_consume(_LKLAMMER) then +begin + p2:=parse_paras(false,false,_RKLAMMER); + consume(_RKLAMMER); + p1:=ccallnode.create_procvar(p2,p1); + { proc():= is never possible } + if token=_ASSIGNMENT then +begin + Message(parser_e_illegal_expression); + p1.free; + p1:=cer