procdefutil.pas 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150
  1. {
  2. Copyright (c) 2018 by Jonas Maebe
  3. Copyright (c) 2011-2021 by Blaise.ru
  4. This unit provides helpers for creating procdefs
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. {$i fpcdefs.inc}
  19. unit procdefutil;
  20. interface
  21. uses
  22. globtype,procinfo,
  23. symconst,symtype,symdef,
  24. node,nbas;
  25. { create a nested procdef that will be used to outline code from a procedure;
  26. astruct should usually be nil, except in special cases like the Windows SEH
  27. exception handling funclets }
  28. function create_outline_procdef(const basesymname: string; astruct: tabstractrecorddef; potype: tproctypeoption; resultdef: tdef): tprocdef;
  29. procedure convert_to_funcref_intf(const n:tidstring;var def:tdef);
  30. function adjust_funcref(var def:tdef;sym,dummysym:tsym):boolean;
  31. { functionality related to capturing local variables for anonymous functions }
  32. function get_or_create_capturer(pd:tprocdef):tsym;
  33. function capturer_add_anonymous_proc(owner:tprocinfo;pd:tprocdef;out capturer:tsym):tobjectdef;
  34. procedure initialize_capturer(ctx:tprocinfo;var stmt:tstatementnode);
  35. procedure postprocess_capturer(ctx:tprocinfo);
  36. procedure convert_captured_syms(pd:tprocdef;tree:tnode);
  37. implementation
  38. uses
  39. cutils,cclasses,verbose,globals,
  40. fmodule,
  41. pass_1,
  42. nobj,ncal,nmem,nld,nutils,
  43. ngenutil,
  44. symbase,symsym,symtable,defutil,defcmp,
  45. pparautl,psub;
  46. function create_outline_procdef(const basesymname: string; astruct: tabstractrecorddef; potype: tproctypeoption; resultdef: tdef): tprocdef;
  47. var
  48. st:TSymTable;
  49. checkstack: psymtablestackitem;
  50. oldsymtablestack: tsymtablestack;
  51. sym:tprocsym;
  52. begin
  53. { get actual procedure symtable (skip withsymtables, etc.) }
  54. st:=nil;
  55. checkstack:=symtablestack.stack;
  56. while assigned(checkstack) do
  57. begin
  58. st:=checkstack^.symtable;
  59. if st.symtabletype in [staticsymtable,globalsymtable,localsymtable] then
  60. break;
  61. checkstack:=checkstack^.next;
  62. end;
  63. { Create a nested procedure, even from main_program_level.
  64. Furthermore, force procdef and procsym into the same symtable
  65. (by default, defs are registered with symtablestack.top which may be
  66. something temporary like exceptsymtable - in that case, procdef can be
  67. destroyed before procsym, leaving invalid pointers). }
  68. oldsymtablestack:=symtablestack;
  69. symtablestack:=nil;
  70. result:=cprocdef.create(max(normal_function_level,st.symtablelevel)+1,true);
  71. result.returndef:=resultdef;
  72. { if the parent is a generic or a specialization, the new function is one
  73. as well }
  74. if st.symtabletype=localsymtable then
  75. result.defoptions:=result.defoptions+(tstoreddef(st.defowner).defoptions*[df_generic,df_specialization]);
  76. symtablestack:=oldsymtablestack;
  77. st.insertdef(result);
  78. result.struct:=astruct;
  79. { tabstractprocdef constructor sets po_delphi_nested_cc whenever
  80. nested procvars modeswitch is active. We must be independent of this switch. }
  81. exclude(result.procoptions,po_delphi_nested_cc);
  82. result.proctypeoption:=potype;
  83. { always use the default calling convention }
  84. result.proccalloption:=pocall_default;
  85. include(result.procoptions,po_hascallingconvention);
  86. handle_calling_convention(result,hcc_default_actions_impl);
  87. sym:=cprocsym.create(basesymname+result.unique_id_str);
  88. st.insertsym(sym);
  89. result.procsym:=sym;
  90. proc_add_definition(result);
  91. { the code will be assigned directly to the "code" field later }
  92. result.forwarddef:=false;
  93. result.aliasnames.insert(result.mangledname);
  94. end;
  95. function fileinfo_to_suffix(const fileinfo:tfileposinfo):tsymstr;inline;
  96. begin
  97. result:=tostr(fileinfo.moduleindex)+'_'+
  98. tostr(fileinfo.fileindex)+'_'+
  99. tostr(fileinfo.line)+'_'+
  100. tostr(fileinfo.column);
  101. end;
  102. const
  103. anon_funcref_prefix='$FuncRef_';
  104. capturer_class_name='$CapturerClass';
  105. { the leading $ is only added when registering the var symbol }
  106. capturer_var_name='Capturer';
  107. keepalive_suffix='_keepalive';
  108. outer_self_field_name='OuterSelf';
  109. procedure convert_to_funcref_intf(const n:tidstring;var def:tdef);
  110. var
  111. oldsymtablestack : tsymtablestack;
  112. pvdef : tprocvardef absolute def;
  113. intfdef : tobjectdef;
  114. invokedef : tprocdef;
  115. psym : tprocsym;
  116. sym : tsym;
  117. st : tsymtable;
  118. i : longint;
  119. name : tidstring;
  120. begin
  121. if def.typ<>procvardef then
  122. internalerror(2021040201);
  123. if not (po_is_function_ref in tprocvardef(pvdef).procoptions) then
  124. internalerror(2021022101);
  125. if n='' then
  126. name:=anon_funcref_prefix+fileinfo_to_suffix(current_filepos)
  127. else
  128. name:=n;
  129. intfdef:=cobjectdef.create(odt_interfacecom,name,interface_iunknown,true);
  130. include(intfdef.objectoptions,oo_is_funcref);
  131. include(intfdef.objectoptions,oo_is_invokable);
  132. include(intfdef.objectoptions,oo_has_virtual);
  133. intfdef.typesym:=pvdef.typesym;
  134. pvdef.typesym:=nil;
  135. if cs_generate_rtti in current_settings.localswitches then
  136. include(intfdef.objectoptions,oo_can_have_published);
  137. oldsymtablestack:=symtablestack;
  138. symtablestack:=nil;
  139. invokedef:=tprocdef(pvdef.getcopyas(procdef,pc_normal_no_paras,'',false));
  140. invokedef.struct:=intfdef;
  141. invokedef.forwarddef:=false;
  142. include(invokedef.procoptions,po_overload);
  143. include(invokedef.procoptions,po_virtualmethod);
  144. invokedef.procsym:=cprocsym.create(method_name_funcref_invoke_decl);
  145. if cs_generate_rtti in current_settings.localswitches then
  146. invokedef.visibility:=vis_published
  147. else
  148. invokedef.visibility:=vis_public;
  149. intfdef.symtable.insertsym(invokedef.procsym);
  150. intfdef.symtable.insertdef(invokedef);
  151. if pvdef.is_generic or pvdef.is_specialization then
  152. begin
  153. if assigned(pvdef.genericdef) and (pvdef.genericdef.typ<>objectdef) then
  154. internalerror(2021040501);
  155. intfdef.genericdef:=pvdef.genericdef;
  156. intfdef.defoptions:=intfdef.defoptions+(pvdef.defoptions*[df_generic,df_specialization]);
  157. { in case of a generic we move all involved syms/defs to the interface }
  158. intfdef.genericparas:=pvdef.genericparas;
  159. pvdef.genericparas:=nil;
  160. for i:=0 to intfdef.genericparas.count-1 do
  161. begin
  162. sym:=tsym(intfdef.genericparas[i]);
  163. if sym.owner<>pvdef.parast then
  164. continue;
  165. sym.changeowner(intfdef.symtable);
  166. if (sym.typ=typesym) and (ttypesym(sym).typedef.owner=pvdef.parast) then
  167. ttypesym(sym).typedef.changeowner(intfdef.symtable);
  168. end;
  169. end;
  170. { now move the symtable over }
  171. invokedef.parast.free;
  172. invokedef.parast:=pvdef.parast;
  173. invokedef.parast.defowner:=invokedef;
  174. pvdef.parast:=nil;
  175. for i:=0 to invokedef.parast.symlist.count-1 do
  176. begin
  177. sym:=tsym(invokedef.parast.symlist[i]);
  178. if sym.typ<>paravarsym then
  179. continue;
  180. if tparavarsym(sym).vardef=pvdef then
  181. tparavarsym(sym).vardef:=intfdef;
  182. end;
  183. symtablestack:=oldsymtablestack;
  184. if invokedef.returndef=pvdef then
  185. invokedef.returndef:=intfdef;
  186. handle_calling_convention(invokedef,hcc_default_actions_intf_struct);
  187. proc_add_definition(invokedef);
  188. invokedef.calcparas;
  189. { def is not owned, so it can be simply freed }
  190. def.free;
  191. def:=intfdef;
  192. end;
  193. function adjust_funcref(var def:tdef;sym,dummysym:tsym):boolean;
  194. var
  195. sympos : tfileposinfo;
  196. name : string;
  197. begin
  198. result:=false;
  199. if (def.typ<>procvardef) and not is_funcref(def) then
  200. internalerror(2022020401);
  201. if assigned(sym) and not (sym.typ=typesym) then
  202. internalerror(2022020402);
  203. { these always support everything, no "of object" or
  204. "is_nested" is allowed }
  205. if is_nested_pd(tprocvardef(def)) or
  206. is_methodpointer(def) then
  207. cgmessage(type_e_function_reference_kind);
  208. if not (po_is_block in tprocvardef(def).procoptions) then
  209. begin
  210. if assigned(dummysym) then
  211. ttypesym(dummysym).typedef:=nil;
  212. if assigned(sym) then
  213. begin
  214. ttypesym(sym).typedef:=nil;
  215. name:=sym.name;
  216. end
  217. else
  218. name:='';
  219. convert_to_funcref_intf(name,def);
  220. if assigned(sym) then
  221. ttypesym(sym).typedef:=def;
  222. if assigned(dummysym) then
  223. ttypesym(dummysym).typedef:=def;
  224. build_vmt(tobjectdef(def));
  225. result:=true;
  226. end
  227. else
  228. begin
  229. if assigned(sym) and (sym.refs>0) then
  230. begin
  231. { find where the symbol was used and trigger
  232. a "symbol not completely defined" error }
  233. if not fileinfo_of_typesym_in_def(def,sym,sympos) then
  234. sympos:=sym.fileinfo;
  235. messagepos1(sympos,type_e_type_is_not_completly_defined,sym.realname);
  236. end;
  237. end;
  238. end;
  239. function funcref_intf_for_proc(pd:tabstractprocdef;const suffix:string):tobjectdef;
  240. var
  241. name : tsymstr;
  242. sym : tsym;
  243. symowner : tsymtable;
  244. oldsymtablestack: TSymtablestack;
  245. invokedef: tprocdef;
  246. begin
  247. if pd.is_generic then
  248. internalerror(2022010710);
  249. name:='funcrefintf_'+suffix;
  250. if pd.owner.symtabletype=globalsymtable then
  251. symowner:=current_module.localsymtable
  252. else
  253. symowner:=pd.owner;
  254. sym:=tsym(symowner.find(name));
  255. if assigned(sym) then
  256. begin
  257. if sym.typ<>typesym then
  258. internalerror(2022010708);
  259. if not is_funcref(ttypesym(sym).typedef) then
  260. internalerror(2022010709);
  261. result:=tobjectdef(ttypesym(sym).typedef);
  262. exit;
  263. end;
  264. name:='$'+name;
  265. result:=cobjectdef.create(odt_interfacecom,name,interface_iunknown,false);
  266. include(result.objectoptions,oo_is_funcref);
  267. include(result.objectoptions,oo_is_invokable);
  268. sym:=ctypesym.create(name,result);
  269. oldsymtablestack:=symtablestack;
  270. symtablestack:=nil;
  271. invokedef:=tprocdef(pd.getcopyas(procdef,pc_normal,'',false));
  272. invokedef.struct:=result;
  273. invokedef.visibility:=vis_public;
  274. invokedef.procsym:=cprocsym.create(method_name_funcref_invoke_decl);
  275. include(invokedef.procoptions,po_virtualmethod);
  276. exclude(invokedef.procoptions,po_staticmethod);
  277. exclude(invokedef.procoptions,po_classmethod);
  278. invokedef.forwarddef:=false;
  279. symtablestack:=oldsymtablestack;
  280. result.symtable.insertsym(invokedef.procsym);
  281. result.symtable.insertdef(invokedef);
  282. handle_calling_convention(invokedef,hcc_default_actions_intf_struct);
  283. proc_add_definition(invokedef);
  284. invokedef.calcparas;
  285. include(result.objectoptions,oo_has_virtual);
  286. symowner.insertsym(sym);
  287. symowner.insertdef(result);
  288. end;
  289. {.$define DEBUG_CAPTURER}
  290. function get_capturer(pd:tprocdef):tabstractvarsym;
  291. function getsym(st:tsymtable;typ:tsymtyp):tabstractvarsym;
  292. begin
  293. result:=tabstractvarsym(st.find(capturer_var_name));
  294. if not assigned(result) then
  295. internalerror(2022010703);
  296. if result.typ<>typ then
  297. internalerror(2022010704);
  298. if not is_class(result.vardef) then
  299. internalerror(2022010705);
  300. end;
  301. begin
  302. case pd.proctypeoption of
  303. potype_unitfinalize,
  304. potype_unitinit,
  305. potype_proginit:
  306. begin
  307. if not assigned(pd.owner) then
  308. internalerror(2022052401);
  309. if pd.owner.symtabletype<>staticsymtable then
  310. internalerror(2022052402);
  311. result:=getsym(pd.owner,staticvarsym);
  312. end;
  313. else
  314. begin
  315. if not assigned(pd.localst) then
  316. internalerror(2022020502);
  317. result:=getsym(pd.localst,localvarsym);
  318. end;
  319. end;
  320. end;
  321. function get_capturer_alive(pd:tprocdef):tabstractvarsym;
  322. function getsym(st:tsymtable;typ:tsymtyp):tabstractvarsym;
  323. begin
  324. result:=tabstractvarsym(st.find(capturer_var_name+keepalive_suffix));
  325. if not assigned(result) then
  326. internalerror(2022051703);
  327. if result.typ<>typ then
  328. internalerror(2022051704);
  329. if not is_interfacecom(result.vardef) then
  330. internalerror(2022051705);
  331. end;
  332. begin
  333. case pd.proctypeoption of
  334. potype_unitfinalize,
  335. potype_unitinit,
  336. potype_proginit:
  337. begin
  338. if not assigned(pd.owner) then
  339. internalerror(2022052403);
  340. if pd.owner.symtabletype<>staticsymtable then
  341. internalerror(2022052404);
  342. result:=getsym(pd.owner,staticvarsym);
  343. end;
  344. else
  345. begin
  346. if not assigned(pd.localst) then
  347. internalerror(2022051702);
  348. result:=getsym(pd.localst,localvarsym);
  349. end;
  350. end;
  351. end;
  352. function get_or_create_capturer(pd:tprocdef):tsym;
  353. var
  354. name : tsymstr;
  355. parent,
  356. def : tobjectdef;
  357. typesym : tsym;
  358. keepalive : tabstractvarsym;
  359. intfimpl : TImplementedInterface;
  360. st : tsymtable;
  361. begin
  362. if pd.has_capturer then
  363. begin
  364. result:=get_capturer(pd);
  365. end
  366. else
  367. begin
  368. parent:=tobjectdef(search_system_type('TINTERFACEDOBJECT').typedef);
  369. if not is_class(parent) then
  370. internalerror(2022010706);
  371. name:=capturer_class_name+'_'+fileinfo_to_suffix(pd.fileinfo);
  372. case pd.proctypeoption of
  373. potype_unitfinalize,
  374. potype_unitinit,
  375. potype_proginit:
  376. st:=pd.owner;
  377. else
  378. st:=pd.localst;
  379. end;
  380. def:=cobjectdef.create(odt_class,name,parent,false);
  381. typesym:=ctypesym.create(name,def);
  382. typesym.fileinfo:=pd.fileinfo;
  383. st.insertdef(def);
  384. st.insertsym(typesym);
  385. if df_generic in pd.defoptions then
  386. include(def.defoptions,df_generic);
  387. { don't set df_specialization as in that case genericdef needs to be
  388. set, but the local symtables are freed once a unit is finished }
  389. {if df_specialization in pd.defoptions then
  390. begin
  391. if not assigned(pd.genericdef) or (pd.genericdef.typ<>procdef) then
  392. internalerror(2022020501);
  393. def.genericdef:=tstoreddef(get_capturer(tprocdef(pd.genericdef)).vardef);
  394. include(def.defoptions,df_specialization);
  395. end;}
  396. if st.symtabletype=localsymtable then
  397. result:=clocalvarsym.create('$'+capturer_var_name,vs_value,def,[])
  398. else
  399. result:=cstaticvarsym.create('$'+capturer_var_name,vs_value,def,[]);
  400. result.fileinfo:=pd.fileinfo;
  401. st.insertsym(result);
  402. addsymref(result);
  403. if st.symtabletype=localsymtable then
  404. keepalive:=clocalvarsym.create('$'+capturer_var_name+keepalive_suffix,vs_value,interface_iunknown,[])
  405. else
  406. keepalive:=cstaticvarsym.create('$'+capturer_var_name+keepalive_suffix,vs_value,interface_iunknown,[]);
  407. keepalive.fileinfo:=pd.fileinfo;
  408. st.insertsym(keepalive);
  409. addsymref(keepalive);
  410. if st.symtabletype<>localsymtable then
  411. begin
  412. cnodeutils.insertbssdata(tstaticvarsym(result));
  413. cnodeutils.insertbssdata(tstaticvarsym(keepalive));
  414. end;
  415. { avoid warnings as these symbols are initialized using initialize_capturer
  416. after parsing the body }
  417. tabstractvarsym(result).varstate:=vs_readwritten;
  418. keepalive.varstate:=vs_readwritten;
  419. pd.has_capturer:=true;
  420. end;
  421. end;
  422. function can_be_captured(sym:tsym):boolean;
  423. begin
  424. result:=false;
  425. if not (sym.typ in [localvarsym,paravarsym]) then
  426. exit;
  427. if tabstractnormalvarsym(sym).varoptions*[vo_is_result,vo_is_funcret]<>[] then
  428. exit;
  429. if sym.typ=paravarsym then
  430. begin
  431. if (tparavarsym(sym).varspez in [vs_out,vs_var]) and
  432. not (vo_is_self in tparavarsym(sym).varoptions) then
  433. exit;
  434. if is_open_array(tparavarsym(sym).vardef) then
  435. exit;
  436. end;
  437. result:=true;
  438. end;
  439. type
  440. tsym_mapping = record
  441. oldsym:tsym;
  442. newsym:tsym;
  443. end;
  444. psym_mapping = ^tsym_mapping;
  445. function replace_self_sym(var n:tnode;arg:pointer):foreachnoderesult;
  446. var
  447. mapping : psym_mapping absolute arg;
  448. ld : tloadnode;
  449. begin
  450. if n.nodetype=loadn then
  451. begin
  452. ld:=tloadnode(n);
  453. if ld.symtableentry=mapping^.oldsym then
  454. begin
  455. ld.symtableentry:=mapping^.newsym;
  456. { make sure that the node is processed again }
  457. ld.resultdef:=nil;
  458. if assigned(ld.left) then
  459. begin
  460. { no longer loaded through the frame pointer }
  461. ld.left.free;
  462. ld.left:=nil;
  463. end;
  464. typecheckpass(n);
  465. end;
  466. end;
  467. result:=fen_true;
  468. end;
  469. procedure capture_captured_syms(pd:tprocdef;owner:tprocinfo;capturedef:tobjectdef);
  470. var
  471. curpd : tprocdef;
  472. subcapturer : tobjectdef;
  473. symstodo : TFPList;
  474. i : longint;
  475. sym : tsym;
  476. fieldsym : tfieldvarsym;
  477. fieldname : tsymstr;
  478. begin
  479. if not pd.was_anonymous or not assigned(pd.capturedsyms) or (pd.capturedsyms.count=0) then
  480. exit;
  481. { capture all variables that the original procdef captured }
  482. curpd:=owner.procdef;
  483. subcapturer:=capturedef;
  484. symstodo:=tfplist.create;
  485. for i:=0 to pd.capturedsyms.count-1 do
  486. if can_be_captured(pcapturedsyminfo(pd.capturedsyms[i])^.sym) then
  487. symstodo.add(pcapturedsyminfo(pd.capturedsyms[i])^.sym);
  488. while symstodo.count>0 do
  489. begin
  490. { we know we have symbols left to capture thus we either have a
  491. symbol that's located in the capturer of the current procdef or
  492. we need to put in the OuterSelf reference }
  493. if curpd=owner.procdef then
  494. subcapturer:=capturedef
  495. else
  496. subcapturer:=tobjectdef(tabstractvarsym(get_or_create_capturer(curpd)).vardef);
  497. i:=0;
  498. while i<symstodo.count do
  499. begin
  500. sym:=tsym(symstodo[i]);
  501. if (sym.owner=curpd.localst) or
  502. (sym.owner=curpd.parast) then
  503. begin
  504. {$ifdef DEBUG_CAPTURER}writeln('Symbol ',sym.name,' captured from ',curpd.procsym.name);{$endif}
  505. { the symbol belongs to the current procdef, so add a field to
  506. the capturer if it doesn't already exist }
  507. if vo_is_self in tabstractnormalvarsym(sym).varoptions then
  508. fieldname:=outer_self_field_name
  509. else
  510. fieldname:=sym.name;
  511. fieldsym:=tfieldvarsym(subcapturer.symtable.find(fieldname));
  512. if not assigned(fieldsym) then
  513. begin
  514. {$ifdef DEBUG_CAPTURER}writeln('Adding field ',fieldname,' to ',subcapturer.typesym.name);{$endif}
  515. if vo_is_self in tabstractnormalvarsym(sym).varoptions then
  516. fieldname:='$'+fieldname;
  517. fieldsym:=cfieldvarsym.create(fieldname,vs_value,tabstractvarsym(sym).vardef,[]);
  518. fieldsym.fileinfo:=sym.fileinfo;
  519. subcapturer.symtable.insertsym(fieldsym);
  520. tabstractrecordsymtable(subcapturer.symtable).addfield(fieldsym,vis_public);
  521. end;
  522. if not assigned(tabstractnormalvarsym(sym).capture_sym) then
  523. tabstractnormalvarsym(sym).capture_sym:=fieldsym
  524. else if tabstractnormalvarsym(sym).capture_sym<>fieldsym then
  525. internalerror(2022011602);
  526. symstodo.delete(i);
  527. end
  528. else
  529. inc(i);
  530. end;
  531. if symstodo.count>0 then
  532. begin
  533. if curpd.owner.symtabletype<>localsymtable then
  534. internalerror(2022011001);
  535. { there are still symbols left, so before we move to the parent
  536. procdef we add the OuterSelf field to set up the chain of
  537. capturers }
  538. {$ifdef DEBUG_CAPTURER}writeln('Initialize capturer for ',curpd.procsym.name);{$endif}
  539. { we no longer need the curpd, but we need the parent, so change
  540. curpd here }
  541. curpd:=tprocdef(curpd.owner.defowner);
  542. if curpd.typ<>procdef then
  543. internalerror(2022011002);
  544. if not assigned(subcapturer.symtable.find(outer_self_field_name)) then
  545. begin
  546. {$ifdef DEBUG_CAPTURER}writeln('Adding field OuterSelf to ',subcapturer.typesym.name);{$endif}
  547. if subcapturer.owner.symtablelevel>normal_function_level then
  548. { the outer self is the capturer of the outer procdef }
  549. sym:=get_or_create_capturer(curpd)
  550. else
  551. begin
  552. { the outer self is the self of the method }
  553. if not (curpd.owner.symtabletype in [objectsymtable,recordsymtable]) then
  554. internalerror(2022011603);
  555. sym:=tsym(curpd.parast.find('self'));
  556. if not assigned(sym) then
  557. internalerror(2022011604);
  558. end;
  559. { add the keep alive IUnknown symbol }
  560. fieldsym:=cfieldvarsym.create('$'+outer_self_field_name+keepalive_suffix,vs_value,interface_iunknown,[]);
  561. fieldsym.fileinfo:=sym.fileinfo;
  562. subcapturer.symtable.insertsym(fieldsym);
  563. tabstractrecordsymtable(subcapturer.symtable).addfield(fieldsym,vis_public);
  564. { add the capturer symbol }
  565. fieldsym:=cfieldvarsym.create('$'+outer_self_field_name,vs_value,tabstractvarsym(sym).vardef,[]);
  566. fieldsym.fileinfo:=sym.fileinfo;
  567. subcapturer.symtable.insertsym(fieldsym);
  568. tabstractrecordsymtable(subcapturer.symtable).addfield(fieldsym,vis_public);
  569. if (sym.typ=paravarsym) and (vo_is_self in tparavarsym(sym).varoptions) then
  570. begin
  571. if assigned(tparavarsym(sym).capture_sym) then
  572. internalerror(2022011705);
  573. tparavarsym(sym).capture_sym:=fieldsym;
  574. end;
  575. end;
  576. end;
  577. end;
  578. symstodo.free;
  579. end;
  580. function capturer_add_anonymous_proc(owner:tprocinfo;pd:tprocdef;out capturer:tsym):tobjectdef;
  581. var
  582. capturedef : tobjectdef;
  583. implintf : TImplementedInterface;
  584. invokename : tsymstr;
  585. i : longint;
  586. outerself,
  587. fpsym,
  588. selfsym,
  589. sym : tsym;
  590. info : pcapturedsyminfo;
  591. pi : tprocinfo;
  592. mapping : tsym_mapping;
  593. invokedef,
  594. parentdef,
  595. curpd : tprocdef;
  596. begin
  597. capturer:=nil;
  598. result:=funcref_intf_for_proc(pd,fileinfo_to_suffix(pd.fileinfo));
  599. if df_generic in pd.defoptions then
  600. begin
  601. if (po_anonymous in pd.procoptions) and
  602. assigned(pd.capturedsyms) and
  603. (pd.capturedsyms.count>0) then
  604. begin
  605. { only check whether the symbols can be captured, but don't
  606. convert anything to avoid problems }
  607. for i:=0 to pd.capturedsyms.count-1 do
  608. begin
  609. info:=pcapturedsyminfo(pd.capturedsyms[i]);
  610. if not can_be_captured(info^.sym) then
  611. MessagePos1(info^.fileinfo,sym_e_symbol_no_capture,info^.sym.realname)
  612. end;
  613. end;
  614. exit;
  615. end;
  616. capturer:=get_or_create_capturer(owner.procdef);
  617. if not (capturer.typ in [localvarsym,staticvarsym]) then
  618. internalerror(2022010711);
  619. capturedef:=tobjectdef(tabstractvarsym(capturer).vardef);
  620. if not is_class(capturedef) then
  621. internalerror(2022010712);
  622. implintf:=find_implemented_interface(capturedef,result);
  623. if assigned(implintf) then
  624. begin
  625. { this can only already be an implemented interface if a named procdef
  626. was assigned to a function ref at an earlier point, an anonymous
  627. function can be used only once }
  628. if po_anonymous in pd.procoptions then
  629. internalerror(2022010713);
  630. exit;
  631. end;
  632. implintf:=capturedef.register_implemented_interface(result,true);
  633. invokename:=method_name_funcref_invoke_decl+'$'+fileinfo_to_suffix(pd.fileinfo);
  634. if po_anonymous in pd.procoptions then
  635. begin
  636. { turn the anonymous function into a method of the capturer }
  637. pd.changeowner(capturedef.symtable);
  638. pd.struct:=capturedef;
  639. exclude(pd.procoptions,po_anonymous);
  640. exclude(pd.procoptions,po_delphi_nested_cc);
  641. pd.was_anonymous:=true;
  642. pd.procsym.ChangeOwnerAndName(capturedef.symtable,upcase(invokename));
  643. pd.parast.symtablelevel:=normal_function_level;
  644. pd.localst.symtablelevel:=normal_function_level;
  645. { retrieve framepointer and self parameters if any }
  646. fpsym:=nil;
  647. selfsym:=nil;
  648. for i:=0 to pd.parast.symlist.count-1 do
  649. begin
  650. sym:=tsym(pd.parast.symlist[i]);
  651. if sym.typ<>paravarsym then
  652. continue;
  653. if vo_is_parentfp in tparavarsym(sym).varoptions then
  654. fpsym:=sym
  655. else if vo_is_self in tparavarsym(sym).varoptions then
  656. selfsym:=sym;
  657. if assigned(fpsym) and assigned(selfsym) then
  658. break;
  659. end;
  660. { get rid of the framepointer parameter }
  661. if assigned(fpsym) then
  662. pd.parast.deletesym(fpsym);
  663. outerself:=nil;
  664. { complain about all symbols that can't be captured and add the symbols
  665. to this procdefs capturedsyms if it isn't a top level function }
  666. if assigned(pd.capturedsyms) and (pd.capturedsyms.count>0) then
  667. begin
  668. for i:=0 to pd.capturedsyms.count-1 do
  669. begin
  670. info:=pcapturedsyminfo(pd.capturedsyms[i]);
  671. if not can_be_captured(info^.sym) then
  672. MessagePos1(info^.fileinfo,sym_e_symbol_no_capture,info^.sym.realname)
  673. else if info^.sym=selfsym then
  674. begin
  675. { we need to replace the captured "dummy" self parameter
  676. with the real self parameter symbol from the surrounding
  677. method }
  678. if not assigned(outerself) then
  679. outerself:=tsym(owner.get_normal_proc.procdef.parast.find('self'));
  680. if not assigned(outerself) then
  681. internalerror(2022010905);
  682. { the anonymous function can only be a direct child of the
  683. owner }
  684. pi:=owner.get_first_nestedproc;
  685. while assigned(pi) do
  686. begin
  687. if pi.procdef=pd then
  688. break;
  689. pi:=tprocinfo(pi.next);
  690. end;
  691. if not assigned(pi) then
  692. internalerror(2022010906);
  693. mapping.oldsym:=selfsym;
  694. mapping.newsym:=outerself;
  695. { replace all uses of the captured Self by the new Self
  696. parameter }
  697. foreachnodestatic(pm_preprocess,tcgprocinfo(pi).code,@replace_self_sym,@mapping);
  698. { update the captured symbol }
  699. info^.sym:=outerself;
  700. end
  701. else if info^.sym.owner.defowner<>owner.procdef then
  702. owner.procdef.add_captured_sym(info^.sym,info^.fileinfo);
  703. end;
  704. end;
  705. { delete the original self parameter }
  706. if assigned(selfsym) then
  707. pd.parast.deletesym(selfsym);
  708. { note: don't call insert_self_and_vmt_para here, as that is later on
  709. done when building the VMT }
  710. end
  711. else
  712. internalerror(2022022201);
  713. implintf.AddMapping(upcase(result.objrealname^+'.')+method_name_funcref_invoke_find,upcase(invokename));
  714. capture_captured_syms(pd,owner,capturedef);
  715. end;
  716. function load_capturer(capturer:tabstractvarsym):tnode;inline;
  717. begin
  718. result:=cloadnode.create(capturer,capturer.owner);
  719. end;
  720. function instantiate_capturer(capturer_sym:tabstractvarsym):tnode;
  721. var
  722. capturer_def : tobjectdef;
  723. ctor : tprocsym;
  724. begin
  725. capturer_def:=tobjectdef(capturer_sym.vardef);
  726. { Neither TInterfacedObject, nor TCapturer have a custom constructor }
  727. ctor:=tprocsym(class_tobject.symtable.Find('CREATE'));
  728. if not assigned(ctor) then
  729. internalerror(2022010801);
  730. { Insert "Capturer := TCapturer.Create()" as the first statement of the routine }
  731. result:=cloadvmtaddrnode.create(ctypenode.create(capturer_def));
  732. result:=ccallnode.create(nil,ctor,capturer_def.symtable,result,[],nil);
  733. result:=cassignmentnode.create(load_capturer(capturer_sym),result);
  734. end;
  735. procedure initialize_captured_paras(pd:tprocdef;capturer:tabstractvarsym;var stmt:tstatementnode);
  736. var
  737. i : longint;
  738. psym: tparavarsym;
  739. n : tnode;
  740. begin
  741. for i:=0 to pd.paras.count-1 do
  742. begin
  743. psym:=tparavarsym(pd.paras[i]);
  744. if not psym.is_captured then
  745. continue;
  746. {$ifdef DEBUG_CAPTURER}writeln(#9'initialize captured parameter ',psym.RealName);{$endif}
  747. n:=cloadnode.create(psym,psym.owner);
  748. if psym.capture_sym.owner.defowner<>capturer.vardef then
  749. internalerror(2022010903);
  750. n:=cassignmentnode.create(
  751. csubscriptnode.create(psym.capture_sym,cloadnode.create(capturer,capturer.owner)),
  752. n
  753. );
  754. addstatement(stmt,n);
  755. end;
  756. end;
  757. procedure attach_outer_capturer(ctx:tprocinfo;capturer:tabstractvarsym;var stmt:tstatementnode);
  758. var
  759. alivefield,
  760. selffield : tfieldvarsym;
  761. outeralive,
  762. outercapturer : tabstractvarsym;
  763. alivenode,
  764. selfnode : tnode;
  765. begin
  766. if not ctx.procdef.was_anonymous and
  767. not (ctx.procdef.owner.symtabletype=localsymtable) then
  768. exit;
  769. selffield:=tfieldvarsym(tobjectdef(capturer.vardef).symtable.find(outer_self_field_name));
  770. if not assigned(selffield) then
  771. { we'll simply assume that we don't need the outer capturer }
  772. exit;
  773. alivefield:=tfieldvarsym(tobjectdef(capturer.vardef).symtable.find(outer_self_field_name+keepalive_suffix));
  774. if not assigned(alivefield) then
  775. internalerror(2022051701);
  776. if ctx.procdef.was_anonymous then
  777. begin
  778. selfnode:=load_self_node;
  779. alivenode:=selfnode.getcopy;
  780. end
  781. else
  782. begin
  783. outercapturer:=get_capturer(tprocdef(ctx.procdef.owner.defowner));
  784. if not assigned(outercapturer) then
  785. internalerror(2022011605);
  786. selfnode:=cloadnode.create(outercapturer,outercapturer.owner);
  787. outeralive:=get_capturer_alive(tprocdef(ctx.procdef.owner.defowner));
  788. if not assigned(outeralive) then
  789. internalerror(2022051706);
  790. alivenode:=cloadnode.create(outeralive,outeralive.owner);
  791. end;
  792. addstatement(stmt,cassignmentnode.create(
  793. csubscriptnode.create(
  794. selffield,
  795. cloadnode.create(
  796. capturer,
  797. capturer.owner
  798. )
  799. ),
  800. selfnode));
  801. addstatement(stmt,cassignmentnode.create(
  802. csubscriptnode.create(
  803. alivefield,
  804. cloadnode.create(
  805. capturer,
  806. capturer.owner
  807. )
  808. ),
  809. alivenode));
  810. end;
  811. procedure initialize_capturer(ctx:tprocinfo;var stmt:tstatementnode);
  812. var
  813. capturer_sym,
  814. keepalive_sym : tabstractvarsym;
  815. begin
  816. if ctx.procdef.has_capturer then
  817. begin
  818. capturer_sym:=get_capturer(ctx.procdef);
  819. {$ifdef DEBUG_CAPTURER}writeln('initialize_capturer @ ',ctx.procdef.procsym.RealName);{$endif}
  820. addstatement(stmt,instantiate_capturer(capturer_sym));
  821. attach_outer_capturer(ctx,capturer_sym,stmt);
  822. initialize_captured_paras(ctx.procdef,capturer_sym,stmt);
  823. keepalive_sym:=get_capturer_alive(ctx.procdef);
  824. if not assigned(keepalive_sym) then
  825. internalerror(2022010701);
  826. addstatement(stmt,cassignmentnode.create(cloadnode.create(keepalive_sym,keepalive_sym.owner),load_capturer(capturer_sym)));
  827. end;
  828. end;
  829. procedure postprocess_capturer(ctx: tprocinfo);
  830. var
  831. def: tobjectdef;
  832. begin
  833. if not ctx.procdef.has_capturer then
  834. exit;
  835. def:=tobjectdef(get_capturer(ctx.procdef).vardef);
  836. {$ifdef DEBUG_CAPTURER}writeln('process capturer ',def.typesym.Name);{$endif}
  837. { These two are delayed until this point because
  838. ... we have been adding fields on-the-fly }
  839. tabstractrecordsymtable(def.symtable).addalignmentpadding;
  840. { ... we have been adding interfaces on-the-fly }
  841. build_vmt(def);
  842. end;
  843. type
  844. tconvert_arg=record
  845. mappings:tfplist;
  846. end;
  847. pconvert_arg=^tconvert_arg;
  848. tconvert_mapping=record
  849. oldsym:tsym;
  850. newsym:tsym;
  851. selfnode:tnode;
  852. end;
  853. pconvert_mapping=^tconvert_mapping;
  854. function convert_captured_sym(var n:tnode;arg:pointer):foreachnoderesult;
  855. var
  856. convertarg : pconvert_arg absolute arg;
  857. mapping : pconvert_mapping;
  858. i : longint;
  859. old_filepos : tfileposinfo;
  860. begin
  861. result:=fen_true;
  862. if n.nodetype<>loadn then
  863. exit;
  864. for i:=0 to convertarg^.mappings.count-1 do
  865. begin
  866. mapping:=convertarg^.mappings[i];
  867. if tloadnode(n).symtableentry<>mapping^.oldsym then
  868. continue;
  869. old_filepos:=current_filepos;
  870. current_filepos:=n.fileinfo;
  871. n.free;
  872. n:=csubscriptnode.create(mapping^.newsym,mapping^.selfnode.getcopy);
  873. typecheckpass(n);
  874. current_filepos:=old_filepos;
  875. break;
  876. end;
  877. end;
  878. procedure convert_captured_syms(pd:tprocdef;tree:tnode);
  879. function self_tree_for_sym(selfsym:tsym;fieldsym:tsym):tnode;
  880. var
  881. fieldowner : tdef;
  882. newsym : tsym;
  883. begin
  884. result:=cloadnode.create(selfsym,selfsym.owner);
  885. fieldowner:=tdef(fieldsym.owner.defowner);
  886. newsym:=selfsym;
  887. while (tabstractvarsym(newsym).vardef<>fieldowner) do
  888. begin
  889. newsym:=tsym(tobjectdef(tabstractvarsym(newsym).vardef).symtable.find(outer_self_field_name));
  890. if not assigned(newsym) then
  891. internalerror(2022011101);
  892. result:=csubscriptnode.create(newsym,result);
  893. end;
  894. end;
  895. var
  896. i,j : longint;
  897. capturer : tobjectdef;
  898. capturedsyms : tfplist;
  899. convertarg : tconvert_arg;
  900. mapping : pconvert_mapping;
  901. invokepd : tprocdef;
  902. selfsym,
  903. sym : tsym;
  904. info: pcapturedsyminfo;
  905. begin
  906. {$ifdef DEBUG_CAPTURER}writeln('Converting captured symbols of ',pd.procsym.name);{$endif}
  907. convertarg.mappings:=tfplist.create;
  908. capturedsyms:=tfplist.create;
  909. if pd.was_anonymous and
  910. assigned(pd.capturedsyms) and
  911. (pd.capturedsyms.count>0) then
  912. begin
  913. {$ifdef DEBUG_CAPTURER}writeln('Converting symbols of converted anonymous function ',pd.procsym.name);{$endif}
  914. { this is a converted anonymous function, so rework all symbols that
  915. now belong to the new Self }
  916. selfsym:=tsym(pd.parast.find('self'));
  917. if not assigned(selfsym) then
  918. internalerror(2022010809);
  919. for i:=0 to pd.capturedsyms.count-1 do
  920. begin
  921. sym:=tsym(pcapturedsyminfo(pd.capturedsyms[i])^.sym);
  922. if not can_be_captured(sym) then
  923. continue;
  924. {$ifdef DEBUG_CAPTURER}writeln('Replacing symbol ',sym.Name);{$endif}
  925. new(mapping);
  926. mapping^.oldsym:=sym;
  927. mapping^.newsym:=tabstractnormalvarsym(sym).capture_sym;
  928. if not assigned(mapping^.newsym) then
  929. internalerror(2022010810);
  930. mapping^.selfnode:=self_tree_for_sym(selfsym,mapping^.newsym);
  931. convertarg.mappings.add(mapping);
  932. capturedsyms.add(sym);
  933. end;
  934. end;
  935. if (pd.parast.symtablelevel>normal_function_level) and
  936. assigned(pd.capturedsyms) and
  937. (pd.capturedsyms.count>0) then
  938. begin
  939. {$ifdef DEBUG_CAPTURER}writeln('Converting symbols of nested function ',pd.procsym.name);{$endif}
  940. { this is a nested function, so rework all symbols that are used from
  941. a parent function, but that might have been captured }
  942. for i:=0 to pd.capturedsyms.count-1 do
  943. begin
  944. sym:=tsym(pcapturedsyminfo(pd.capturedsyms[i])^.sym);
  945. if not can_be_captured(sym) or not assigned(tabstractnormalvarsym(sym).capture_sym) then
  946. continue;
  947. {$ifdef DEBUG_CAPTURER}writeln('Replacing symbol ',sym.Name);{$endif}
  948. new(mapping);
  949. mapping^.oldsym:=sym;
  950. mapping^.newsym:=tabstractnormalvarsym(sym).capture_sym;
  951. capturer:=tobjectdef(mapping^.newsym.owner.defowner);
  952. if not is_class(capturer) then
  953. internalerror(2022012701);
  954. if not (capturer.typesym.owner.symtabletype in [localsymtable,staticsymtable]) then
  955. internalerror(2022012702);
  956. selfsym:=tsym(capturer.typesym.owner.find(capturer_var_name));
  957. if not assigned(selfsym) then
  958. internalerror(2022012703);
  959. mapping^.selfnode:=self_tree_for_sym(selfsym,mapping^.newsym);
  960. convertarg.mappings.add(mapping);
  961. capturedsyms.add(sym);
  962. end;
  963. end;
  964. if pd.has_capturer then
  965. begin
  966. {$ifdef DEBUG_CAPTURER}writeln('Converting symbols of function ',pd.procsym.name,' with capturer');{$endif}
  967. { this procedure has a capturer, so rework all symbols that are
  968. captured in that capturer }
  969. selfsym:=get_capturer(pd);
  970. for i:=0 to pd.localst.symlist.count-1 do
  971. begin
  972. sym:=tsym(pd.localst.symlist[i]);
  973. if sym.typ<>localvarsym then
  974. continue;
  975. if assigned(tabstractnormalvarsym(sym).capture_sym) then
  976. if capturedsyms.indexof(sym)<0 then
  977. capturedsyms.add(sym);
  978. end;
  979. for i:=0 to pd.parast.symlist.count-1 do
  980. begin
  981. sym:=tsym(pd.parast.symlist[i]);
  982. if sym.typ<>paravarsym then
  983. continue;
  984. if assigned(tabstractnormalvarsym(sym).capture_sym) and
  985. { no need to adjust accesses to the outermost Self inside the
  986. outermost method }
  987. not (vo_is_self in tabstractvarsym(sym).varoptions) then
  988. if capturedsyms.indexof(sym)<0 then
  989. capturedsyms.add(sym);
  990. end;
  991. for i:=0 to capturedsyms.count-1 do
  992. begin
  993. new(mapping);
  994. mapping^.oldsym:=tsym(capturedsyms[i]);
  995. {$ifdef DEBUG_CAPTURER}writeln('Replacing symbol ',mapping^.oldsym.Name);{$endif}
  996. mapping^.newsym:=tabstractnormalvarsym(mapping^.oldsym).capture_sym;
  997. if not assigned(mapping^.newsym) then
  998. internalerror(2022010805);
  999. mapping^.selfnode:=self_tree_for_sym(selfsym,mapping^.newsym);
  1000. convertarg.mappings.add(mapping);
  1001. end;
  1002. end;
  1003. { not required anymore }
  1004. capturedsyms.free;
  1005. foreachnodestatic(pm_postprocess,tree,@convert_captured_sym,@convertarg);
  1006. for i:=0 to convertarg.mappings.count-1 do
  1007. begin
  1008. mapping:=pconvert_mapping(convertarg.mappings[i]);
  1009. mapping^.selfnode.free;
  1010. dispose(mapping);
  1011. end;
  1012. convertarg.mappings.free;
  1013. end;
  1014. end.