symcreat.pas 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078
  1. {
  2. Copyright (c) 2011 by Jonas Maebe
  3. This unit provides helpers for creating new syms/defs based on string
  4. representations.
  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 symcreat;
  20. interface
  21. uses
  22. finput,tokens,scanner,globtype,
  23. aasmdata,
  24. symconst,symbase,symtype,symdef,symsym;
  25. type
  26. tscannerstate = record
  27. old_scanner: tscannerfile;
  28. old_token: ttoken;
  29. old_c: char;
  30. old_modeswitches: tmodeswitches;
  31. valid: boolean;
  32. end;
  33. { save/restore the scanner state before/after injecting }
  34. procedure replace_scanner(const tempname: string; out sstate: tscannerstate);
  35. procedure restore_scanner(const sstate: tscannerstate);
  36. { parses a (class or regular) method/constructor/destructor declaration from
  37. str, as if it were declared in astruct's declaration body
  38. WARNING: save the scanner state before calling this routine, and restore
  39. when done. }
  40. function str_parse_method_dec(str: ansistring; potype: tproctypeoption; is_classdef: boolean; astruct: tabstractrecorddef; out pd: tprocdef): boolean;
  41. { parses a (class or regular) method/constructor/destructor implementation
  42. from str, as if it appeared in the current unit's implementation section
  43. WARNINGS:
  44. * save the scanner state before calling this routine, and restore when done.
  45. * the code *must* be written in objfpc style
  46. }
  47. function str_parse_method_impl(str: ansistring; usefwpd: tprocdef; is_classdef: boolean):boolean;
  48. { parses a typed constant assignment to ssym
  49. WARNINGS:
  50. * save the scanner state before calling this routine, and restore when done.
  51. * the code *must* be written in objfpc style
  52. }
  53. procedure str_parse_typedconst(list: TAsmList; str: ansistring; ssym: tstaticvarsym);
  54. { in the JVM, constructors are not automatically inherited (so you can hide
  55. them). To emulate the Pascal behaviour, we have to automatically add
  56. all parent constructors to the current class as well.}
  57. procedure add_missing_parent_constructors_intf(obj: tobjectdef; forcevis: tvisibility);
  58. { goes through all defs in st to add implementations for synthetic methods
  59. added earlier }
  60. procedure add_synthetic_method_implementations(st: tsymtable);
  61. procedure finish_copied_procdef(var pd: tprocdef; const realname: string; newparentst: tsymtable; newstruct: tabstractrecorddef);
  62. { create "parent frame pointer" record skeleton for procdef, in which local
  63. variables and parameters from pd accessed from nested routines can be
  64. stored }
  65. procedure build_parentfpstruct(pd: tprocdef);
  66. { checks whether sym (a local or para of pd) already has a counterpart in
  67. pd's parentfpstruct, and if not adds a new field to the struct with type
  68. "vardef" (can be different from sym's type in case it's a call-by-reference
  69. parameter, which is indicated by addrparam). If it already has a field in
  70. the parentfpstruct, this field is returned. }
  71. function maybe_add_sym_to_parentfpstruct(pd: tprocdef; sym: tsym; vardef: tdef; addrparam: boolean): tsym;
  72. { given a localvarsym or paravarsym of pd, returns the field of the
  73. parentfpstruct corresponding to this sym }
  74. function find_sym_in_parentfpstruct(pd: tprocdef; sym: tsym): tsym;
  75. { replaces all local and paravarsyms that have been mirrored in the
  76. parentfpstruct with aliasvarsyms that redirect to these fields (used to
  77. make sure that references to these syms in the owning procdef itself also
  78. use the ones in the parentfpstructs) }
  79. procedure redirect_parentfpstruct_local_syms(pd: tprocdef);
  80. { finalises the parentfpstruct (alignment padding, ...) }
  81. procedure finish_parentfpstruct(pd: tprocdef);
  82. procedure maybe_guarantee_record_typesym(var def: tdef; st: tsymtable);
  83. implementation
  84. uses
  85. cutils,cclasses,globals,verbose,systems,comphook,fmodule,
  86. symtable,defutil,
  87. pbase,pdecobj,pdecsub,psub,ptconst,
  88. {$ifdef jvm}
  89. pjvm,jvmdef,
  90. {$endif jvm}
  91. node,nbas,nld,nmem,
  92. defcmp,
  93. paramgr;
  94. procedure replace_scanner(const tempname: string; out sstate: tscannerstate);
  95. var
  96. old_block_type: tblock_type;
  97. begin
  98. { would require saving of idtoken, pattern etc }
  99. if (token=_ID) then
  100. internalerror(2011032201);
  101. sstate.old_scanner:=current_scanner;
  102. sstate.old_token:=token;
  103. sstate.old_c:=c;
  104. sstate.old_modeswitches:=current_settings.modeswitches;
  105. sstate.valid:=true;
  106. { creating a new scanner resets the block type, while we want to continue
  107. in the current one }
  108. old_block_type:=block_type;
  109. current_scanner:=tscannerfile.Create('_Macro_.'+tempname);
  110. block_type:=old_block_type;
  111. { required for e.g. FpcDeepCopy record method (uses "out" parameter; field
  112. names are escaped via &, so should not cause conflicts }
  113. current_settings.modeswitches:=objfpcmodeswitches;
  114. end;
  115. procedure restore_scanner(const sstate: tscannerstate);
  116. begin
  117. if sstate.valid then
  118. begin
  119. current_scanner.free;
  120. current_scanner:=sstate.old_scanner;
  121. token:=sstate.old_token;
  122. current_settings.modeswitches:=sstate.old_modeswitches;
  123. c:=sstate.old_c;
  124. end;
  125. end;
  126. function str_parse_method_dec(str: ansistring; potype: tproctypeoption; is_classdef: boolean; astruct: tabstractrecorddef; out pd: tprocdef): boolean;
  127. var
  128. oldparse_only: boolean;
  129. begin
  130. Message1(parser_d_internal_parser_string,str);
  131. oldparse_only:=parse_only;
  132. parse_only:=true;
  133. result:=false;
  134. { inject the string in the scanner }
  135. str:=str+'end;';
  136. current_scanner.substitutemacro('meth_head_macro',@str[1],length(str),current_scanner.line_no,current_scanner.inputfile.ref_index);
  137. current_scanner.readtoken(false);
  138. { and parse it... }
  139. case potype of
  140. potype_class_constructor:
  141. pd:=class_constructor_head(astruct);
  142. potype_class_destructor:
  143. pd:=class_destructor_head(astruct);
  144. potype_constructor:
  145. pd:=constructor_head;
  146. potype_destructor:
  147. pd:=destructor_head;
  148. else
  149. pd:=method_dec(astruct,is_classdef);
  150. end;
  151. if assigned(pd) then
  152. result:=true;
  153. parse_only:=oldparse_only;
  154. end;
  155. function str_parse_method_impl(str: ansistring; usefwpd: tprocdef; is_classdef: boolean):boolean;
  156. var
  157. oldparse_only: boolean;
  158. tmpstr: ansistring;
  159. begin
  160. if ((status.verbosity and v_debug)<>0) then
  161. begin
  162. if assigned(usefwpd) then
  163. Message1(parser_d_internal_parser_string,usefwpd.customprocname([pno_proctypeoption,pno_paranames,pno_noclassmarker,pno_noleadingdollar])+str)
  164. else
  165. begin
  166. if is_classdef then
  167. tmpstr:='class '
  168. else
  169. tmpstr:='';
  170. Message1(parser_d_internal_parser_string,tmpstr+str);
  171. end;
  172. end;
  173. oldparse_only:=parse_only;
  174. parse_only:=false;
  175. result:=false;
  176. { inject the string in the scanner }
  177. str:=str+'end;';
  178. current_scanner.substitutemacro('meth_impl_macro',@str[1],length(str),current_scanner.line_no,current_scanner.inputfile.ref_index);
  179. current_scanner.readtoken(false);
  180. { and parse it... }
  181. read_proc(is_classdef,usefwpd);
  182. parse_only:=oldparse_only;
  183. result:=true;
  184. end;
  185. procedure str_parse_typedconst(list: TAsmList; str: ansistring; ssym: tstaticvarsym);
  186. var
  187. old_block_type: tblock_type;
  188. old_parse_only: boolean;
  189. begin
  190. Message1(parser_d_internal_parser_string,str);
  191. { a string that will be interpreted as the start of a new section ->
  192. typed constant parsing will stop }
  193. str:=str+'type ';
  194. old_parse_only:=parse_only;
  195. old_block_type:=block_type;
  196. parse_only:=true;
  197. block_type:=bt_const;
  198. current_scanner.substitutemacro('typed_const_macro',@str[1],length(str),current_scanner.line_no,current_scanner.inputfile.ref_index);
  199. current_scanner.readtoken(false);
  200. read_typed_const(list,ssym,ssym.owner.symtabletype in [recordsymtable,objectsymtable]);
  201. parse_only:=old_parse_only;
  202. block_type:=old_block_type;
  203. end;
  204. procedure add_missing_parent_constructors_intf(obj: tobjectdef; forcevis: tvisibility);
  205. var
  206. parent: tobjectdef;
  207. def: tdef;
  208. parentpd,
  209. childpd: tprocdef;
  210. i: longint;
  211. srsym: tsym;
  212. srsymtable: tsymtable;
  213. begin
  214. if (oo_is_external in obj.objectoptions) or
  215. not assigned(obj.childof) then
  216. exit;
  217. parent:=obj.childof;
  218. { find all constructor in the parent }
  219. for i:=0 to tobjectsymtable(parent.symtable).deflist.count-1 do
  220. begin
  221. def:=tdef(tobjectsymtable(parent.symtable).deflist[i]);
  222. if (def.typ<>procdef) or
  223. (tprocdef(def).proctypeoption<>potype_constructor) or
  224. not is_visible_for_object(tprocdef(def),obj) then
  225. continue;
  226. parentpd:=tprocdef(def);
  227. { do we have this constructor too? (don't use
  228. search_struct_member/searchsym_in_class, since those will
  229. search parents too) }
  230. if searchsym_in_record(obj,parentpd.procsym.name,srsym,srsymtable) then
  231. begin
  232. { there's a symbol with the same name, is it a constructor
  233. with the same parameters? }
  234. if srsym.typ=procsym then
  235. begin
  236. childpd:=tprocsym(srsym).find_procdef_bytype_and_para(
  237. potype_constructor,parentpd.paras,nil,
  238. [cpo_ignorehidden,cpo_ignoreuniv,cpo_openequalisexact]);
  239. if assigned(childpd) then
  240. continue;
  241. end;
  242. end;
  243. { if we get here, we did not find it in the current objectdef ->
  244. add }
  245. childpd:=tprocdef(parentpd.getcopy);
  246. if forcevis<>vis_none then
  247. childpd.visibility:=forcevis;
  248. finish_copied_procdef(childpd,parentpd.procsym.realname,obj.symtable,obj);
  249. exclude(childpd.procoptions,po_external);
  250. include(childpd.procoptions,po_overload);
  251. childpd.synthetickind:=tsk_anon_inherited;
  252. include(obj.objectoptions,oo_has_constructor);
  253. end;
  254. end;
  255. procedure implement_anon_inherited(pd: tprocdef);
  256. var
  257. str: ansistring;
  258. isclassmethod: boolean;
  259. begin
  260. isclassmethod:=
  261. (po_classmethod in pd.procoptions) and
  262. not(pd.proctypeoption in [potype_constructor,potype_destructor]);
  263. str:='begin inherited end;';
  264. str_parse_method_impl(str,pd,isclassmethod);
  265. end;
  266. procedure implement_jvm_clone(pd: tprocdef);
  267. var
  268. struct: tabstractrecorddef;
  269. str: ansistring;
  270. i: longint;
  271. sym: tsym;
  272. fsym: tfieldvarsym;
  273. begin
  274. if not(pd.struct.typ in [recorddef,objectdef]) then
  275. internalerror(2011032802);
  276. struct:=pd.struct;
  277. { anonymous record types must get an artificial name, so we can generate
  278. a typecast at the scanner level }
  279. if (struct.typ=recorddef) and
  280. not assigned(struct.typesym) then
  281. internalerror(2011032812);
  282. { the inherited clone will already copy all fields in a shallow way ->
  283. copy records/regular arrays in a regular way }
  284. str:='type _fpc_ptrt = ^'+struct.typesym.realname+'; begin clone:=inherited;';
  285. for i:=0 to struct.symtable.symlist.count-1 do
  286. begin
  287. sym:=tsym(struct.symtable.symlist[i]);
  288. if (sym.typ=fieldvarsym) then
  289. begin
  290. fsym:=tfieldvarsym(sym);
  291. if (fsym.vardef.typ=recorddef) or
  292. ((fsym.vardef.typ=arraydef) and
  293. not is_dynamic_array(fsym.vardef)) or
  294. ((fsym.vardef.typ=setdef) and
  295. not is_smallset(fsym.vardef)) then
  296. str:=str+'_fpc_ptrt(clone)^.&'+fsym.realname+':='+fsym.realname+';';
  297. end;
  298. end;
  299. str:=str+'end;';
  300. str_parse_method_impl(str,pd,false);
  301. end;
  302. procedure implement_record_deepcopy(pd: tprocdef);
  303. var
  304. struct: tabstractrecorddef;
  305. str: ansistring;
  306. i: longint;
  307. sym: tsym;
  308. fsym: tfieldvarsym;
  309. begin
  310. if not(pd.struct.typ in [recorddef,objectdef]) then
  311. internalerror(2011032810);
  312. struct:=pd.struct;
  313. { anonymous record types must get an artificial name, so we can generate
  314. a typecast at the scanner level }
  315. if (struct.typ=recorddef) and
  316. not assigned(struct.typesym) then
  317. internalerror(2011032811);
  318. { copy all fields }
  319. str:='begin ';
  320. for i:=0 to struct.symtable.symlist.count-1 do
  321. begin
  322. sym:=tsym(struct.symtable.symlist[i]);
  323. if (sym.typ=fieldvarsym) then
  324. begin
  325. fsym:=tfieldvarsym(sym);
  326. str:=str+'result.&'+fsym.realname+':=&'+fsym.realname+';';
  327. end;
  328. end;
  329. str:=str+'end;';
  330. str_parse_method_impl(str,pd,false);
  331. end;
  332. procedure implement_record_initialize(pd: tprocdef);
  333. var
  334. struct: tabstractrecorddef;
  335. str: ansistring;
  336. i: longint;
  337. sym: tsym;
  338. fsym: tfieldvarsym;
  339. begin
  340. if not(pd.struct.typ in [recorddef,objectdef]) then
  341. internalerror(2011071710);
  342. struct:=pd.struct;
  343. { anonymous record types must get an artificial name, so we can generate
  344. a typecast at the scanner level }
  345. if (struct.typ=recorddef) and
  346. not assigned(struct.typesym) then
  347. internalerror(2011032811);
  348. { walk over all fields that need initialization }
  349. str:='begin ';
  350. for i:=0 to struct.symtable.symlist.count-1 do
  351. begin
  352. sym:=tsym(struct.symtable.symlist[i]);
  353. if (sym.typ=fieldvarsym) then
  354. begin
  355. fsym:=tfieldvarsym(sym);
  356. if fsym.vardef.needs_inittable then
  357. str:=str+'system.initialize(&'+fsym.realname+');';
  358. end;
  359. end;
  360. str:=str+'end;';
  361. str_parse_method_impl(str,pd,false);
  362. end;
  363. procedure implement_empty(pd: tprocdef);
  364. var
  365. str: ansistring;
  366. isclassmethod: boolean;
  367. begin
  368. isclassmethod:=
  369. (po_classmethod in pd.procoptions) and
  370. not(pd.proctypeoption in [potype_constructor,potype_destructor]);
  371. str:='begin end;';
  372. str_parse_method_impl(str,pd,isclassmethod);
  373. end;
  374. procedure addvisibibleparameters(var str: ansistring; pd: tprocdef);
  375. var
  376. currpara: tparavarsym;
  377. i: longint;
  378. firstpara: boolean;
  379. begin
  380. firstpara:=true;
  381. for i:=0 to pd.paras.count-1 do
  382. begin
  383. currpara:=tparavarsym(pd.paras[i]);
  384. if not(vo_is_hidden_para in currpara.varoptions) then
  385. begin
  386. if not firstpara then
  387. str:=str+',';
  388. firstpara:=false;
  389. str:=str+currpara.realname;
  390. end;
  391. end;
  392. end;
  393. procedure implement_callthrough(pd: tprocdef);
  394. var
  395. str: ansistring;
  396. callpd: tprocdef;
  397. isclassmethod: boolean;
  398. begin
  399. isclassmethod:=
  400. (po_classmethod in pd.procoptions) and
  401. not(pd.proctypeoption in [potype_constructor,potype_destructor]);
  402. callpd:=tprocdef(pd.skpara);
  403. str:='begin ';
  404. if pd.returndef<>voidtype then
  405. str:=str+'result:=';
  406. str:=str+callpd.procsym.realname+'(';
  407. addvisibibleparameters(str,pd);
  408. str:=str+') end;';
  409. str_parse_method_impl(str,pd,isclassmethod);
  410. end;
  411. {$ifdef jvm}
  412. procedure implement_jvm_enum_values(pd: tprocdef);
  413. begin
  414. str_parse_method_impl('begin result:=__fpc_FVALUES end;',pd,true);
  415. end;
  416. procedure implement_jvm_enum_valuof(pd: tprocdef);
  417. begin
  418. str_parse_method_impl('begin result:=__FPC_TEnumClassAlias(inherited valueOf(JLClass(__FPC_TEnumClassAlias),__fpc_str)) end;',pd,true);
  419. end;
  420. procedure implement_jvm_enum_jumps_constr(pd: tprocdef);
  421. begin
  422. str_parse_method_impl('begin inherited create(__fpc_name,__fpc_ord); __fpc_fenumval:=__fpc_initenumval end;',pd,false);
  423. end;
  424. procedure implement_jvm_enum_fpcordinal(pd: tprocdef);
  425. var
  426. enumclass: tobjectdef;
  427. enumdef: tenumdef;
  428. begin
  429. enumclass:=tobjectdef(pd.owner.defowner);
  430. enumdef:=tenumdef(ttypesym(search_struct_member(enumclass,'__FPC_TENUMALIAS')).typedef);
  431. if not enumdef.has_jumps then
  432. str_parse_method_impl('begin result:=ordinal end;',pd,false)
  433. else
  434. str_parse_method_impl('begin result:=__fpc_fenumval end;',pd,false);
  435. end;
  436. procedure implement_jvm_enum_fpcvalueof(pd: tprocdef);
  437. var
  438. enumclass: tobjectdef;
  439. enumdef: tenumdef;
  440. isclassmethod: boolean;
  441. begin
  442. isclassmethod:=
  443. (po_classmethod in pd.procoptions) and
  444. not(pd.proctypeoption in [potype_constructor,potype_destructor]);
  445. enumclass:=tobjectdef(pd.owner.defowner);
  446. enumdef:=tenumdef(ttypesym(search_struct_member(enumclass,'__FPC_TENUMALIAS')).typedef);
  447. { convert integer to corresponding enum instance: in case of no jumps
  448. get it from the $VALUES array, otherwise from the __fpc_ord2enum
  449. hashmap }
  450. if not enumdef.has_jumps then
  451. str_parse_method_impl('begin result:=__fpc_FVALUES[__fpc_int] end;',pd,isclassmethod)
  452. else
  453. str_parse_method_impl('begin result:=__FPC_TEnumClassAlias(__fpc_ord2enum.get(JLInteger.valueOf(__fpc_int))) end;',pd,isclassmethod);
  454. end;
  455. function CompareEnumSyms(Item1, Item2: Pointer): Integer;
  456. var
  457. I1 : tenumsym absolute Item1;
  458. I2 : tenumsym absolute Item2;
  459. begin
  460. Result:=I1.value-I2.value;
  461. end;
  462. procedure implement_jvm_enum_classconstr(pd: tprocdef);
  463. var
  464. enumclass: tobjectdef;
  465. enumdef: tenumdef;
  466. str: ansistring;
  467. i: longint;
  468. enumsym: tenumsym;
  469. classfield: tstaticvarsym;
  470. orderedenums: tfpobjectlist;
  471. begin
  472. enumclass:=tobjectdef(pd.owner.defowner);
  473. enumdef:=tenumdef(ttypesym(search_struct_member(enumclass,'__FPC_TENUMALIAS')).typedef);
  474. if not assigned(enumdef) then
  475. internalerror(2011062305);
  476. str:='begin ';
  477. if enumdef.has_jumps then
  478. { init hashmap for ordinal -> enum instance mapping; don't let it grow,
  479. and set the capacity to the next prime following the total number of
  480. enum elements to minimise the number of collisions }
  481. str:=str+'__fpc_ord2enum:=JUHashMap.Create('+tostr(next_prime(enumdef.symtable.symlist.count))+',1.0);';
  482. { iterate over all enum elements and initialise the class fields, and
  483. store them in the values array. Since the java.lang.Enum doCompare
  484. method is final and hardcoded to compare based on declaration order
  485. (= java.lang.Enum.ordinal() value), we have to create them in order of
  486. ascending FPC ordinal values (which may not be the same as the FPC
  487. declaration order in case of jumps }
  488. orderedenums:=tfpobjectlist.create(false);
  489. for i:=0 to enumdef.symtable.symlist.count-1 do
  490. orderedenums.add(enumdef.symtable.symlist[i]);
  491. if enumdef.has_jumps then
  492. orderedenums.sort(@CompareEnumSyms);
  493. for i:=0 to orderedenums.count-1 do
  494. begin
  495. enumsym:=tenumsym(orderedenums[i]);
  496. classfield:=tstaticvarsym(search_struct_member(enumclass,enumsym.name));
  497. if not assigned(classfield) then
  498. internalerror(2011062306);
  499. str:=str+classfield.name+':=__FPC_TEnumClassAlias.Create('''+enumsym.realname+''','+tostr(i);
  500. if enumdef.has_jumps then
  501. str:=str+','+tostr(enumsym.value);
  502. str:=str+');';
  503. { alias for $VALUES array used internally by the JDK, and also by FPC
  504. in case of no jumps }
  505. str:=str+'__fpc_FVALUES['+tostr(i)+']:='+classfield.name+';';
  506. if enumdef.has_jumps then
  507. str:=str+'__fpc_ord2enum.put(JLInteger.valueOf('+tostr(enumsym.value)+'),'+classfield.name+');';
  508. end;
  509. orderedenums.free;
  510. str:=str+' end;';
  511. str_parse_method_impl(str,pd,true);
  512. end;
  513. procedure implement_jvm_enum_long2set(pd: tprocdef);
  514. begin
  515. str_parse_method_impl(
  516. 'var '+
  517. 'i, setval: jint;'+
  518. 'begin '+
  519. 'result:=JUEnumSet.noneOf(JLClass(__FPC_TEnumClassAlias));'+
  520. 'if __val<>0 then '+
  521. 'begin '+
  522. '__setsize:=__setsize*8;'+
  523. 'for i:=0 to __setsize-1 do '+
  524. // setsize-i because JVM = big endian
  525. 'if (__val and (jlong(1) shl (__setsize-i)))<>0 then '+
  526. 'result.add(fpcValueOf(i+__setbase));'+
  527. 'end '+
  528. 'end;',
  529. pd,true);
  530. end;
  531. procedure implement_jvm_enum_bitset2set(pd: tprocdef);
  532. begin
  533. str_parse_method_impl(
  534. 'var '+
  535. 'i, setval: jint;'+
  536. 'begin '+
  537. 'result:=JUEnumSet.noneOf(JLClass(__FPC_TEnumClassAlias));'+
  538. 'i:=__val.nextSetBit(0);'+
  539. 'while i>=0 do '+
  540. 'begin '+
  541. 'setval:=-__fromsetbase;'+
  542. 'result.add(fpcValueOf(setval+__tosetbase));'+
  543. 'i:=__val.nextSetBit(i+1);'+
  544. 'end '+
  545. 'end;',
  546. pd,true);
  547. end;
  548. procedure implement_jvm_enum_set2set(pd: tprocdef);
  549. begin
  550. str_parse_method_impl(
  551. 'var '+
  552. 'it: JUIterator;'+
  553. 'ele: FpcEnumValueObtainable;'+
  554. 'i: longint;'+
  555. 'begin '+
  556. 'result:=JUEnumSet.noneOf(JLClass(__FPC_TEnumClassAlias));'+
  557. 'it:=__val.iterator;'+
  558. 'while it.hasNext do '+
  559. 'begin '+
  560. 'ele:=FpcEnumValueObtainable(it.next);'+
  561. 'i:=ele.fpcOrdinal-__fromsetbase;'+
  562. 'result.add(fpcValueOf(i+__tosetbase));'+
  563. 'end '+
  564. 'end;',
  565. pd,true);
  566. end;
  567. procedure implement_jvm_procvar_invoke(pd: tprocdef);
  568. var
  569. pvclass: tobjectdef;
  570. procvar: tprocvardef;
  571. paraname,str,endstr: ansistring;
  572. pvs: tparavarsym;
  573. paradef,boxdef,boxargdef: tdef;
  574. i: longint;
  575. firstpara: boolean;
  576. begin
  577. pvclass:=tobjectdef(pd.owner.defowner);
  578. procvar:=tprocvardef(ttypesym(search_struct_member(pvclass,'__FPC_PROCVARALIAS')).typedef);
  579. { the procvar wrapper class has a tmethod member called "method", whose
  580. "code" field is a JLRMethod, and whose "data" field is the self pointer
  581. if any (if none is required, it's ignored by the JVM, so there's no
  582. problem with always passing it) }
  583. { force extended syntax to allow calling invokeObjectFunc() without using
  584. its result }
  585. str:='';
  586. endstr:='';
  587. { create local pointer to result type for typecasting in case of an
  588. implicit pointer type }
  589. if jvmimplicitpointertype(procvar.returndef) then
  590. str:=str+'type __FPC_returnptrtype = ^'+procvar.returndef.typename+';';
  591. str:=str+'begin ';
  592. { result handling }
  593. if not is_void(procvar.returndef) then
  594. begin
  595. str:=str+'invoke:=';
  596. if procvar.returndef.typ in [orddef,floatdef] then
  597. begin
  598. { primitivetype(boxtype(..).unboxmethod) }
  599. jvmgetboxtype(procvar.returndef,boxdef,boxargdef,false);
  600. str:=str+procvar.returndef.typename+'('+boxdef.typename+'(';
  601. endstr:=').'+jvmgetunboxmethod(procvar.returndef)+')';
  602. end
  603. else if jvmimplicitpointertype(procvar.returndef) then
  604. begin
  605. str:=str+'__FPC_returnptrtype(';
  606. { dereference }
  607. endstr:=')^';
  608. end
  609. else
  610. begin
  611. str:=str+procvar.returndef.typename+'(';
  612. endstr:=')';
  613. end;
  614. end;
  615. str:=str+'invokeObjectFunc([';
  616. { parameters are a constant array of jlobject }
  617. firstpara:=true;
  618. for i:=0 to procvar.paras.count-1 do
  619. begin
  620. { skip self/vmt/parentfp, passed separately }
  621. pvs:=tparavarsym(procvar.paras[i]);
  622. if ([vo_is_self,vo_is_vmt,vo_is_parentfp]*pvs.varoptions)<>[] then
  623. continue;
  624. if not firstpara then
  625. str:=str+',';
  626. firstpara:=false;
  627. paraname:=pvs.realname;
  628. paradef:=pvs.vardef;
  629. { Pascalize hidden high parameter }
  630. if vo_is_high_para in pvs.varoptions then
  631. paraname:='high('+tparavarsym(procvar.paras[i-1]).realname+')'
  632. else if vo_is_hidden_para in pvs.varoptions then
  633. begin
  634. if ([vo_is_range_check,vo_is_overflow_check]*pvs.varoptions)<>[] then
  635. { ok, simple boolean parameters }
  636. else
  637. internalerror(2011072403);
  638. end;
  639. { var/out/constref parameters -> pass address through (same for
  640. implicit pointer types) }
  641. if paramanager.push_addr_param(pvs.varspez,paradef,procvar.proccalloption) or
  642. jvmimplicitpointertype(paradef) then
  643. begin
  644. paraname:='@'+paraname;
  645. paradef:=java_jlobject;
  646. end;
  647. if paradef.typ in [orddef,floatdef] then
  648. begin
  649. { box primitive types; use valueOf() rather than create because it
  650. can give better performance }
  651. jvmgetboxtype(paradef,boxdef,boxargdef,false);
  652. str:=str+boxdef.typename+'.valueOf('+boxargdef.typename+'('+paraname+'))'
  653. end
  654. else
  655. str:=str+'JLObject('+paraname+')';
  656. end;
  657. str:=str+'])'+endstr+' end;';
  658. str_parse_method_impl(str,pd,false)
  659. end;
  660. procedure implement_jvm_virtual_clmethod(pd: tprocdef);
  661. var
  662. str: ansistring;
  663. callpd: tprocdef;
  664. begin
  665. callpd:=tprocdef(pd.skpara);
  666. str:='var pv: __fpc_virtualclassmethod_pv_t'+tostr(pd.defid)+'; begin '
  667. + 'pv:=@'+callpd.procsym.RealName+';';
  668. if (pd.proctypeoption<>potype_constructor) and
  669. not is_void(pd.returndef) then
  670. str:=str+'result:=';
  671. str:=str+'pv(';
  672. addvisibibleparameters(str,pd);
  673. str:=str+') end;';
  674. str_parse_method_impl(str,pd,true)
  675. end;
  676. {$endif jvm}
  677. procedure add_synthetic_method_implementations_for_struct(struct: tabstractrecorddef);
  678. var
  679. i : longint;
  680. def : tdef;
  681. pd : tprocdef;
  682. begin
  683. for i:=0 to struct.symtable.deflist.count-1 do
  684. begin
  685. def:=tdef(struct.symtable.deflist[i]);
  686. if (def.typ<>procdef) then
  687. continue;
  688. pd:=tprocdef(def);
  689. case pd.synthetickind of
  690. tsk_none:
  691. ;
  692. tsk_anon_inherited:
  693. implement_anon_inherited(pd);
  694. tsk_jvm_clone:
  695. implement_jvm_clone(pd);
  696. tsk_record_deepcopy:
  697. implement_record_deepcopy(pd);
  698. tsk_record_initialize:
  699. implement_record_initialize(pd);
  700. tsk_empty,
  701. { special handling for this one is done in tnodeutils.wrap_proc_body }
  702. tsk_tcinit:
  703. implement_empty(pd);
  704. tsk_callthrough:
  705. implement_callthrough(pd);
  706. {$ifdef jvm}
  707. tsk_jvm_enum_values:
  708. implement_jvm_enum_values(pd);
  709. tsk_jvm_enum_valueof:
  710. implement_jvm_enum_valuof(pd);
  711. tsk_jvm_enum_classconstr:
  712. implement_jvm_enum_classconstr(pd);
  713. tsk_jvm_enum_jumps_constr:
  714. implement_jvm_enum_jumps_constr(pd);
  715. tsk_jvm_enum_fpcordinal:
  716. implement_jvm_enum_fpcordinal(pd);
  717. tsk_jvm_enum_fpcvalueof:
  718. implement_jvm_enum_fpcvalueof(pd);
  719. tsk_jvm_enum_long2set:
  720. implement_jvm_enum_long2set(pd);
  721. tsk_jvm_enum_bitset2set:
  722. implement_jvm_enum_bitset2set(pd);
  723. tsk_jvm_enum_set2set:
  724. implement_jvm_enum_set2set(pd);
  725. tsk_jvm_procvar_invoke:
  726. implement_jvm_procvar_invoke(pd);
  727. tsk_jvm_virtual_clmethod:
  728. implement_jvm_virtual_clmethod(pd);
  729. {$endif jvm}
  730. else
  731. internalerror(2011032801);
  732. end;
  733. end;
  734. end;
  735. procedure add_synthetic_method_implementations(st: tsymtable);
  736. var
  737. i: longint;
  738. def: tdef;
  739. sstate: tscannerstate;
  740. begin
  741. { only necessary for the JVM target currently }
  742. if not (target_info.system in [system_jvm_java32]) then
  743. exit;
  744. sstate.valid:=false;
  745. for i:=0 to st.deflist.count-1 do
  746. begin
  747. def:=tdef(st.deflist[i]);
  748. if (def.typ=procdef) and
  749. assigned(tprocdef(def).localst) and
  750. { not true for the "main" procedure, whose localsymtable is the staticsymtable }
  751. (tprocdef(def).localst.symtabletype=localsymtable) then
  752. add_synthetic_method_implementations(tprocdef(def).localst)
  753. else if (is_javaclass(def) and
  754. not(oo_is_external in tobjectdef(def).objectoptions)) or
  755. (def.typ=recorddef) then
  756. begin
  757. if not sstate.valid then
  758. replace_scanner('synthetic_impl',sstate);
  759. add_synthetic_method_implementations_for_struct(tabstractrecorddef(def));
  760. { also complete nested types }
  761. add_synthetic_method_implementations(tabstractrecorddef(def).symtable);
  762. end;
  763. end;
  764. restore_scanner(sstate);
  765. end;
  766. procedure finish_copied_procdef(var pd: tprocdef; const realname: string; newparentst: tsymtable; newstruct: tabstractrecorddef);
  767. var
  768. sym: tsym;
  769. parasym: tparavarsym;
  770. ps: tprocsym;
  771. stname: string;
  772. i: longint;
  773. begin
  774. { associate the procdef with a procsym in the owner }
  775. if not(pd.proctypeoption in [potype_class_constructor,potype_class_destructor]) then
  776. stname:=upper(realname)
  777. else
  778. stname:=lower(realname);
  779. sym:=tsym(newparentst.find(stname));
  780. if assigned(sym) then
  781. begin
  782. if sym.typ<>procsym then
  783. internalerror(2011040601);
  784. ps:=tprocsym(sym);
  785. end
  786. else
  787. begin
  788. ps:=tprocsym.create(realname);
  789. newparentst.insert(ps);
  790. end;
  791. pd.procsym:=ps;
  792. pd.struct:=newstruct;
  793. { in case of methods, replace the special parameter types with new ones }
  794. if assigned(newstruct) then
  795. begin
  796. symtablestack.push(pd.parast);
  797. { may not be assigned in case we converted a procvar into a procdef }
  798. if assigned(pd.paras) then
  799. begin
  800. for i:=0 to pd.paras.count-1 do
  801. begin
  802. parasym:=tparavarsym(pd.paras[i]);
  803. if vo_is_self in parasym.varoptions then
  804. begin
  805. if parasym.vardef.typ=classrefdef then
  806. parasym.vardef:=tclassrefdef.create(newstruct)
  807. else
  808. parasym.vardef:=newstruct;
  809. end
  810. end;
  811. end;
  812. { also fix returndef in case of a constructor }
  813. if pd.proctypeoption=potype_constructor then
  814. pd.returndef:=newstruct;
  815. symtablestack.pop(pd.parast);
  816. end;
  817. pd.calcparas;
  818. proc_add_definition(pd);
  819. end;
  820. procedure build_parentfpstruct(pd: tprocdef);
  821. var
  822. nestedvars: tsym;
  823. nestedvarsst: tsymtable;
  824. pnestedvarsdef,
  825. nestedvarsdef: tdef;
  826. old_symtablestack: tsymtablestack;
  827. begin
  828. { make sure the defs are not registered in the current symtablestack,
  829. because they may be for a parent procdef (changeowner does remove a def
  830. from the symtable in which it was originally created, so that by itself
  831. is not enough) }
  832. old_symtablestack:=symtablestack;
  833. symtablestack:=old_symtablestack.getcopyuntil(current_module.localsymtable);
  834. { create struct to hold local variables and parameters that are
  835. accessed from within nested routines (start with extra dollar to prevent
  836. the JVM from thinking this is a nested class in the unit) }
  837. nestedvarsst:=trecordsymtable.create('$'+current_module.realmodulename^+'$$_fpc_nestedvars$'+tostr(pd.defid),current_settings.alignment.localalignmax);
  838. nestedvarsdef:=trecorddef.create(nestedvarsst.name^,nestedvarsst);
  839. {$ifdef jvm}
  840. maybe_guarantee_record_typesym(nestedvarsdef,nestedvarsdef.owner);
  841. { don't add clone/FpcDeepCopy, because the field names are not all
  842. representable in source form and we don't need them anyway }
  843. symtablestack.push(trecorddef(nestedvarsdef).symtable);
  844. maybe_add_public_default_java_constructor(trecorddef(nestedvarsdef));
  845. symtablestack.pop(trecorddef(nestedvarsdef).symtable);
  846. {$endif}
  847. symtablestack.free;
  848. symtablestack:=old_symtablestack.getcopyuntil(pd.localst);
  849. pnestedvarsdef:=getpointerdef(nestedvarsdef);
  850. nestedvars:=tlocalvarsym.create('$nestedvars',vs_var,nestedvarsdef,[]);
  851. pd.localst.insert(nestedvars);
  852. pd.parentfpstruct:=nestedvars;
  853. pd.parentfpstructptrtype:=pnestedvarsdef;
  854. pd.parentfpinitblock:=cblocknode.create(nil);
  855. symtablestack.free;
  856. symtablestack:=old_symtablestack;
  857. end;
  858. function maybe_add_sym_to_parentfpstruct(pd: tprocdef; sym: tsym; vardef: tdef; addrparam: boolean): tsym;
  859. var
  860. fieldvardef,
  861. nestedvarsdef: tdef;
  862. nestedvarsst: tsymtable;
  863. initcode: tnode;
  864. old_filepos: tfileposinfo;
  865. begin
  866. nestedvarsdef:=tlocalvarsym(pd.parentfpstruct).vardef;
  867. result:=search_struct_member(trecorddef(nestedvarsdef),sym.name);
  868. if not assigned(result) then
  869. begin
  870. { mark that this symbol is mirrored in the parentfpstruct }
  871. tabstractnormalvarsym(sym).inparentfpstruct:=true;
  872. { add field to the struct holding all locals accessed
  873. by nested routines }
  874. nestedvarsst:=trecorddef(nestedvarsdef).symtable;
  875. { indicate whether or not this is a var/out/constref/... parameter }
  876. if addrparam then
  877. fieldvardef:=getpointerdef(vardef)
  878. else
  879. fieldvardef:=vardef;
  880. result:=tfieldvarsym.create(sym.realname,vs_value,fieldvardef,[]);
  881. if nestedvarsst.symlist.count=0 then
  882. include(tfieldvarsym(result).varoptions,vo_is_first_field);
  883. nestedvarsst.insert(result);
  884. trecordsymtable(nestedvarsst).addfield(tfieldvarsym(result),vis_public);
  885. { add initialization with original value if it's a parameter }
  886. if (sym.typ=paravarsym) then
  887. begin
  888. old_filepos:=current_filepos;
  889. fillchar(current_filepos,sizeof(current_filepos),0);
  890. initcode:=cloadnode.create(sym,sym.owner);
  891. { indicate that this load should not be transformed into a load
  892. from the parentfpstruct, but instead should load the original
  893. value }
  894. include(initcode.flags,nf_internal);
  895. { in case it's a var/out/constref parameter, store the address of the
  896. parameter in the struct }
  897. if addrparam then
  898. begin
  899. initcode:=caddrnode.create_internal(initcode);
  900. include(initcode.flags,nf_typedaddr);
  901. end;
  902. initcode:=cassignmentnode.create(
  903. csubscriptnode.create(result,cloadnode.create(pd.parentfpstruct,pd.parentfpstruct.owner)),
  904. initcode);
  905. tblocknode(pd.parentfpinitblock).left:=cstatementnode.create
  906. (initcode,tblocknode(pd.parentfpinitblock).left);
  907. current_filepos:=old_filepos;
  908. end;
  909. end;
  910. end;
  911. procedure redirect_parentfpstruct_local_syms(pd: tprocdef);
  912. var
  913. nestedvarsdef: trecorddef;
  914. sl: tpropaccesslist;
  915. fsym,
  916. lsym,
  917. aliassym: tsym;
  918. i: longint;
  919. begin
  920. nestedvarsdef:=trecorddef(tlocalvarsym(pd.parentfpstruct).vardef);
  921. for i:=0 to nestedvarsdef.symtable.symlist.count-1 do
  922. begin
  923. fsym:=tsym(nestedvarsdef.symtable.symlist[i]);
  924. if fsym.typ<>fieldvarsym then
  925. continue;
  926. lsym:=tsym(pd.localst.find(fsym.name));
  927. if not assigned(lsym) then
  928. lsym:=tsym(pd.parast.find(fsym.name));
  929. if not assigned(lsym) then
  930. internalerror(2011060408);
  931. { add an absolute variable that redirects to the field }
  932. sl:=tpropaccesslist.create;
  933. sl.addsym(sl_load,pd.parentfpstruct);
  934. sl.addsym(sl_subscript,tfieldvarsym(fsym));
  935. aliassym:=tabsolutevarsym.create_ref(lsym.name,tfieldvarsym(fsym).vardef,sl);
  936. { hide the original variable (can't delete, because there
  937. may be other loadnodes that reference it)
  938. -- only for locals; hiding parameters changes the
  939. function signature }
  940. if lsym.typ<>paravarsym then
  941. hidesym(lsym);
  942. { insert the absolute variable in the localst of the
  943. routine; ignore duplicates, because this will also check the
  944. parasymtable and we want to override parameters with our local
  945. versions }
  946. pd.localst.insert(aliassym,false);
  947. end;
  948. end;
  949. function find_sym_in_parentfpstruct(pd: tprocdef; sym: tsym): tsym;
  950. var
  951. nestedvarsdef: tdef;
  952. begin
  953. nestedvarsdef:=tlocalvarsym(pd.parentfpstruct).vardef;
  954. result:=search_struct_member(trecorddef(nestedvarsdef),sym.name);
  955. end;
  956. procedure finish_parentfpstruct(pd: tprocdef);
  957. begin
  958. trecordsymtable(trecorddef(tlocalvarsym(pd.parentfpstruct).vardef).symtable).addalignmentpadding;
  959. end;
  960. procedure maybe_guarantee_record_typesym(var def: tdef; st: tsymtable);
  961. var
  962. ts: ttypesym;
  963. begin
  964. { create a dummy typesym for the JVM target, because the record
  965. has to be wrapped by a class }
  966. if (target_info.system=system_jvm_java32) and
  967. (def.typ=recorddef) and
  968. not assigned(def.typesym) then
  969. begin
  970. ts:=ttypesym.create(trecorddef(def).symtable.realname^,def);
  971. st.insert(ts);
  972. ts.visibility:=vis_strictprivate;
  973. { this typesym can't be used by any Pascal code, so make sure we don't
  974. print a hint about it being unused }
  975. addsymref(ts);
  976. end;
  977. end;
  978. end.