pinline.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. {
  2. $Id$
  3. Copyright (c) 1998-2001 by Florian Klaempfl
  4. Generates nodes for routines that need compiler support
  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. unit pinline;
  19. {$i defines.inc}
  20. interface
  21. uses
  22. symtype,
  23. node,
  24. globals,
  25. cpuinfo;
  26. function new_dispose_statement(is_new:boolean) : tnode;
  27. function new_function : tnode;
  28. function inline_setlength : tnode;
  29. function inline_finalize : tnode;
  30. implementation
  31. uses
  32. {$ifdef delphi}
  33. SysUtils,
  34. {$endif}
  35. { common }
  36. cutils,
  37. { global }
  38. globtype,tokens,verbose,
  39. systems,widestr,
  40. { symtable }
  41. symconst,symbase,symdef,symsym,symtable,types,
  42. { pass 1 }
  43. pass_1,htypechk,
  44. nmat,nadd,ncal,nmem,nset,ncnv,ninl,ncon,nld,nflw,nbas,
  45. { parser }
  46. scanner,
  47. pbase,pexpr,
  48. { codegen }
  49. cgbase
  50. ;
  51. function new_dispose_statement(is_new:boolean) : tnode;
  52. var
  53. newstatement : tstatementnode;
  54. temp : ttempcreatenode;
  55. para : tcallparanode;
  56. p,p2 : tnode;
  57. again : boolean; { dummy for do_proc_call }
  58. destructorname : stringid;
  59. sym : tsym;
  60. classh : tobjectdef;
  61. destructorpos,
  62. storepos : tfileposinfo;
  63. begin
  64. consume(_LKLAMMER);
  65. p:=comp_expr(true);
  66. { calc return type }
  67. set_varstate(p,(not is_new));
  68. { constructor,destructor specified }
  69. if try_to_consume(_COMMA) then
  70. begin
  71. { extended syntax of new and dispose }
  72. { function styled new is handled in factor }
  73. { destructors have no parameters }
  74. destructorname:=pattern;
  75. destructorpos:=akttokenpos;
  76. consume(_ID);
  77. if (p.resulttype.def.deftype<>pointerdef) then
  78. begin
  79. Message1(type_e_pointer_type_expected,p.resulttype.def.typename);
  80. p.free;
  81. p:=factor(false);
  82. p.free;
  83. consume(_RKLAMMER);
  84. new_dispose_statement:=cerrornode.create;
  85. exit;
  86. end;
  87. { first parameter must be an object or class }
  88. if tpointerdef(p.resulttype.def).pointertype.def.deftype<>objectdef then
  89. begin
  90. Message(parser_e_pointer_to_class_expected);
  91. p.free;
  92. new_dispose_statement:=factor(false);
  93. consume_all_until(_RKLAMMER);
  94. consume(_RKLAMMER);
  95. exit;
  96. end;
  97. { check, if the first parameter is a pointer to a _class_ }
  98. classh:=tobjectdef(tpointerdef(p.resulttype.def).pointertype.def);
  99. if is_class(classh) then
  100. begin
  101. Message(parser_e_no_new_or_dispose_for_classes);
  102. new_dispose_statement:=factor(false);
  103. consume_all_until(_RKLAMMER);
  104. consume(_RKLAMMER);
  105. exit;
  106. end;
  107. { search cons-/destructor, also in parent classes }
  108. storepos:=akttokenpos;
  109. akttokenpos:=destructorpos;
  110. sym:=search_class_member(classh,destructorname);
  111. akttokenpos:=storepos;
  112. { the second parameter of new/dispose must be a call }
  113. { to a cons-/destructor }
  114. if (not assigned(sym)) or (sym.typ<>procsym) then
  115. begin
  116. if is_new then
  117. Message(parser_e_expr_have_to_be_constructor_call)
  118. else
  119. Message(parser_e_expr_have_to_be_destructor_call);
  120. p.free;
  121. new_dispose_statement:=cerrornode.create;
  122. end
  123. else
  124. begin
  125. if is_new then
  126. p2:=chnewnode.create(tpointerdef(p.resulttype.def).pointertype)
  127. else
  128. p2:=chdisposenode.create(p);
  129. do_resulttypepass(p2);
  130. if is_new then
  131. do_member_read(false,sym,p2,again)
  132. else
  133. begin
  134. if not(m_fpc in aktmodeswitches) then
  135. do_member_read(false,sym,p2,again)
  136. else
  137. begin
  138. p2:=ccallnode.create(nil,tprocsym(sym),sym.owner,p2);
  139. { support dispose(p,done()); }
  140. if try_to_consume(_LKLAMMER) then
  141. begin
  142. if not try_to_consume(_RKLAMMER) then
  143. begin
  144. Message(parser_e_no_paras_for_destructor);
  145. consume_all_until(_RKLAMMER);
  146. consume(_RKLAMMER);
  147. end;
  148. end;
  149. end;
  150. end;
  151. { we need the real called method }
  152. { rg.cleartempgen;}
  153. do_resulttypepass(p2);
  154. if not codegenerror then
  155. begin
  156. if is_new then
  157. begin
  158. if (tcallnode(p2).procdefinition.proctypeoption<>potype_constructor) then
  159. Message(parser_e_expr_have_to_be_constructor_call);
  160. p2.resulttype:=p.resulttype;
  161. p2:=cassignmentnode.create(p,p2);
  162. end
  163. else
  164. begin
  165. if (tcallnode(p2).procdefinition.proctypeoption<>potype_destructor) then
  166. Message(parser_e_expr_have_to_be_destructor_call);
  167. end;
  168. end;
  169. new_dispose_statement:=p2;
  170. end;
  171. end
  172. else
  173. begin
  174. if (p.resulttype.def.deftype<>pointerdef) then
  175. Begin
  176. Message1(type_e_pointer_type_expected,p.resulttype.def.typename);
  177. new_dispose_statement:=cerrornode.create;
  178. end
  179. else
  180. begin
  181. if (tpointerdef(p.resulttype.def).pointertype.def.deftype=objectdef) and
  182. (oo_has_vmt in tobjectdef(tpointerdef(p.resulttype.def).pointertype.def).objectoptions) then
  183. Message(parser_w_use_extended_syntax_for_objects);
  184. if (tpointerdef(p.resulttype.def).pointertype.def.deftype=orddef) and
  185. (torddef(tpointerdef(p.resulttype.def).pointertype.def).typ=uvoid) then
  186. begin
  187. if (m_tp7 in aktmodeswitches) or
  188. (m_delphi in aktmodeswitches) then
  189. Message(parser_w_no_new_dispose_on_void_pointers)
  190. else
  191. Message(parser_e_no_new_dispose_on_void_pointers);
  192. end;
  193. { create statements with call to getmem+initialize or
  194. finalize+freemem }
  195. new_dispose_statement:=internalstatements(newstatement);
  196. if is_new then
  197. begin
  198. { create temp for result }
  199. temp := ctempcreatenode.create(p.resulttype,p.resulttype.def.size,true);
  200. addstatement(newstatement,temp);
  201. { create call to fpc_getmem }
  202. para := ccallparanode.create(cordconstnode.create
  203. (tpointerdef(p.resulttype.def).pointertype.def.size,s32bittype),nil);
  204. addstatement(newstatement,cassignmentnode.create(
  205. ctemprefnode.create(temp),
  206. ccallnode.createintern('fpc_getmem',para)));
  207. { create call to fpc_initialize }
  208. if tpointerdef(p.resulttype.def).pointertype.def.needs_inittable then
  209. begin
  210. para := ccallparanode.create(caddrnode.create(crttinode.create(
  211. tstoreddef(tpointerdef(p.resulttype.def).pointertype.def),initrtti)),
  212. ccallparanode.create(ctemprefnode.create
  213. (temp),nil));
  214. addstatement(newstatement,ccallnode.createintern('fpc_initialize',para));
  215. end;
  216. { copy the temp to the destination }
  217. addstatement(newstatement,cassignmentnode.create(
  218. p,
  219. ctemprefnode.create(temp)));
  220. { release temp }
  221. addstatement(newstatement,ctempdeletenode.create(temp));
  222. end
  223. else
  224. begin
  225. { create call to fpc_finalize }
  226. if tpointerdef(p.resulttype.def).pointertype.def.needs_inittable then
  227. begin
  228. { we need to use a copy of p here }
  229. para := ccallparanode.create(caddrnode.create(crttinode.create
  230. (tstoreddef(tpointerdef(p.resulttype.def).pointertype.def),initrtti)),
  231. ccallparanode.create(p.getcopy,nil));
  232. addstatement(newstatement,ccallnode.createintern('fpc_finalize',para));
  233. end;
  234. { create call to fpc_freemem }
  235. para := ccallparanode.create(p,nil);
  236. addstatement(newstatement,ccallnode.createintern('fpc_freemem',para));
  237. end;
  238. end;
  239. end;
  240. consume(_RKLAMMER);
  241. end;
  242. function new_function : tnode;
  243. var
  244. newstatement : tstatementnode;
  245. newblock : tblocknode;
  246. temp : ttempcreatenode;
  247. para : tcallparanode;
  248. p1,p2 : tnode;
  249. classh : tobjectdef;
  250. sym : tsym;
  251. again : boolean; { dummy for do_proc_call }
  252. begin
  253. consume(_LKLAMMER);
  254. p1:=factor(false);
  255. if p1.nodetype<>typen then
  256. begin
  257. Message(type_e_type_id_expected);
  258. p1.destroy;
  259. p1:=cerrornode.create;
  260. do_resulttypepass(p1);
  261. end;
  262. if (p1.resulttype.def.deftype<>pointerdef) then
  263. Message1(type_e_pointer_type_expected,p1.resulttype.def.typename)
  264. else
  265. if token=_RKLAMMER then
  266. begin
  267. if (tpointerdef(p1.resulttype.def).pointertype.def.deftype=objectdef) and
  268. (oo_has_vmt in tobjectdef(tpointerdef(p1.resulttype.def).pointertype.def).objectoptions) then
  269. Message(parser_w_use_extended_syntax_for_objects);
  270. { create statements with call to getmem+initialize }
  271. newblock:=internalstatements(newstatement);
  272. { create temp for result }
  273. temp := ctempcreatenode.create(p1.resulttype,p1.resulttype.def.size,true);
  274. addstatement(newstatement,temp);
  275. { create call to fpc_getmem }
  276. para := ccallparanode.create(cordconstnode.create
  277. (tpointerdef(p1.resulttype.def).pointertype.def.size,s32bittype),nil);
  278. addstatement(newstatement,cassignmentnode.create(
  279. ctemprefnode.create(temp),
  280. ccallnode.createintern('fpc_getmem',para)));
  281. { create call to fpc_initialize }
  282. if tpointerdef(p1.resulttype.def).pointertype.def.needs_inittable then
  283. begin
  284. para := ccallparanode.create(caddrnode.create(crttinode.create
  285. (tstoreddef(tpointerdef(p1.resulttype.def).pointertype.def),initrtti)),
  286. ccallparanode.create(ctemprefnode.create
  287. (temp),nil));
  288. addstatement(newstatement,ccallnode.createintern('fpc_initialize',para));
  289. end;
  290. { the last statement should return the value as
  291. location and type, this is done be referencing the
  292. temp and converting it first from a persistent temp to
  293. normal temp }
  294. addstatement(newstatement,ctempdeletenode.create_normal_temp(temp));
  295. addstatement(newstatement,ctemprefnode.create(temp));
  296. p1.destroy;
  297. p1:=newblock;
  298. consume(_RKLAMMER);
  299. end
  300. else
  301. begin
  302. p2:=chnewnode.create(tpointerdef(p1.resulttype.def).pointertype);
  303. do_resulttypepass(p2);
  304. consume(_COMMA);
  305. afterassignment:=false;
  306. { determines the current object defintion }
  307. classh:=tobjectdef(p2.resulttype.def);
  308. if classh.deftype=objectdef then
  309. begin
  310. { check for an abstract class }
  311. if (oo_has_abstract in classh.objectoptions) then
  312. Message(sym_e_no_instance_of_abstract_object);
  313. { search the constructor also in the symbol tables of
  314. the parents }
  315. sym:=searchsym_in_class(classh,pattern);
  316. consume(_ID);
  317. do_member_read(false,sym,p2,again);
  318. { we need to know which procedure is called }
  319. do_resulttypepass(p2);
  320. if (p2.nodetype<>calln) or
  321. (assigned(tcallnode(p2).procdefinition) and
  322. (tcallnode(p2).procdefinition.proctypeoption<>potype_constructor)) then
  323. Message(parser_e_expr_have_to_be_constructor_call);
  324. end
  325. else
  326. Message(parser_e_pointer_to_class_expected);
  327. { constructors return boolean, update resulttype to return
  328. the pointer to the object }
  329. p2.resulttype:=p1.resulttype;
  330. p1.destroy;
  331. p1:=p2;
  332. consume(_RKLAMMER);
  333. end;
  334. new_function:=p1;
  335. end;
  336. function inline_setlength : tnode;
  337. var
  338. paras : tnode;
  339. npara,
  340. ppn : tcallparanode;
  341. counter : integer;
  342. isarray : boolean;
  343. def : tdef;
  344. destppn : tnode;
  345. newstatement : tstatementnode;
  346. temp : ttempcreatenode;
  347. newblock : tnode;
  348. begin
  349. { for easy exiting if something goes wrong }
  350. result := cerrornode.create;
  351. consume(_LKLAMMER);
  352. paras:=parse_paras(false,false);
  353. consume(_RKLAMMER);
  354. if not assigned(paras) then
  355. begin
  356. CGMessage(parser_e_wrong_parameter_size);
  357. exit;
  358. end;
  359. counter:=0;
  360. if assigned(paras) then
  361. begin
  362. { check type of lengths }
  363. ppn:=tcallparanode(paras);
  364. while assigned(ppn.right) do
  365. begin
  366. set_varstate(ppn.left,true);
  367. inserttypeconv(ppn.left,s32bittype);
  368. inc(counter);
  369. ppn:=tcallparanode(ppn.right);
  370. end;
  371. end;
  372. if counter=0 then
  373. begin
  374. CGMessage(parser_e_wrong_parameter_size);
  375. paras.free;
  376. exit;
  377. end;
  378. { last param must be var }
  379. destppn:=ppn.left;
  380. inc(parsing_para_level);
  381. valid_for_var(destppn);
  382. set_varstate(destppn,false);
  383. dec(parsing_para_level);
  384. { first param must be a string or dynamic array ...}
  385. isarray:=is_dynamic_array(destppn.resulttype.def);
  386. if not((destppn.resulttype.def.deftype=stringdef) or
  387. isarray) then
  388. begin
  389. CGMessage(type_e_mismatch);
  390. paras.free;
  391. exit;
  392. end;
  393. { only dynamic arrays accept more dimensions }
  394. if (counter>1) then
  395. begin
  396. if (not isarray) then
  397. CGMessage(type_e_mismatch)
  398. else
  399. begin
  400. { check if the amount of dimensions is valid }
  401. def := tarraydef(destppn.resulttype.def).elementtype.def;
  402. while counter > 1 do
  403. begin
  404. if not(is_dynamic_array(def)) then
  405. begin
  406. CGMessage(parser_e_wrong_parameter_size);
  407. break;
  408. end;
  409. dec(counter);
  410. def := tarraydef(def).elementtype.def;
  411. end;
  412. end;
  413. end;
  414. if isarray then
  415. begin
  416. { create statements with call initialize the arguments and
  417. call fpc_dynarr_setlength }
  418. newblock:=internalstatements(newstatement);
  419. { get temp for array of lengths }
  420. temp := ctempcreatenode.create(s32bittype,counter*s32bittype.def.size,true);
  421. addstatement(newstatement,temp);
  422. { load array of lengths }
  423. ppn:=tcallparanode(paras);
  424. counter:=0;
  425. while assigned(ppn.right) do
  426. begin
  427. addstatement(newstatement,cassignmentnode.create(
  428. ctemprefnode.create_offset(temp,counter*s32bittype.def.size),
  429. ppn.left));
  430. ppn.left:=nil;
  431. inc(counter);
  432. ppn:=tcallparanode(ppn.right);
  433. end;
  434. { destppn is also reused }
  435. ppn.left:=nil;
  436. { create call to fpc_dynarr_setlength }
  437. npara:=ccallparanode.create(caddrnode.create
  438. (ctemprefnode.create(temp)),
  439. ccallparanode.create(cordconstnode.create
  440. (counter,s32bittype),
  441. ccallparanode.create(caddrnode.create
  442. (crttinode.create(tstoreddef(destppn.resulttype.def),initrtti)),
  443. ccallparanode.create(ctypeconvnode.create_explicit(destppn,voidpointertype),nil))));
  444. addstatement(newstatement,ccallnode.createintern('fpc_dynarray_setlength',npara));
  445. addstatement(newstatement,ctempdeletenode.create(temp));
  446. { we don't need original the callparanodes tree }
  447. paras.free;
  448. end
  449. else
  450. begin
  451. { we can reuse the supplied parameters }
  452. newblock:=ccallnode.createintern(
  453. 'fpc_'+tstringdef(destppn.resulttype.def).stringtypname+'_setlength',paras);
  454. end;
  455. result.free;
  456. result:=newblock;
  457. end;
  458. function inline_finalize : tnode;
  459. var
  460. newblock,
  461. paras : tnode;
  462. npara,
  463. destppn,
  464. ppn : tcallparanode;
  465. begin
  466. { for easy exiting if something goes wrong }
  467. result := cerrornode.create;
  468. consume(_LKLAMMER);
  469. paras:=parse_paras(false,false);
  470. consume(_RKLAMMER);
  471. if not assigned(paras) then
  472. begin
  473. CGMessage(parser_e_wrong_parameter_size);
  474. exit;
  475. end;
  476. ppn:=tcallparanode(paras);
  477. { 2 arguments? }
  478. if assigned(ppn.right) then
  479. begin
  480. destppn:=tcallparanode(ppn.right);
  481. { 3 arguments is invalid }
  482. if assigned(destppn.right) then
  483. begin
  484. CGMessage(parser_e_wrong_parameter_size);
  485. paras.free;
  486. exit;
  487. end;
  488. { create call to fpc_finalize_array }
  489. npara:=ccallparanode.create(cordconstnode.create
  490. (destppn.left.resulttype.def.size,s32bittype),
  491. ccallparanode.create(ctypeconvnode.create
  492. (ppn.left,s32bittype),
  493. ccallparanode.create(caddrnode.create
  494. (crttinode.create(tstoreddef(destppn.left.resulttype.def),initrtti)),
  495. ccallparanode.create(caddrnode.create
  496. (destppn.left),nil))));
  497. newblock:=ccallnode.createintern('fpc_finalize_array',npara);
  498. destppn.left:=nil;
  499. ppn.left:=nil;
  500. end
  501. else
  502. begin
  503. { create call to fpc_finalize }
  504. npara:=ccallparanode.create(caddrnode.create
  505. (crttinode.create(tstoreddef(ppn.left.resulttype.def),initrtti)),
  506. ccallparanode.create(caddrnode.create
  507. (ppn.left),nil));
  508. newblock:=ccallnode.createintern('fpc_finalize',npara);
  509. ppn.left:=nil;
  510. end;
  511. paras.free;
  512. result.free;
  513. result:=newblock;
  514. end;
  515. end.
  516. {
  517. $Log$
  518. Revision 1.1 2002-04-23 19:16:35 peter
  519. * add pinline unit that inserts compiler supported functions using
  520. one or more statements
  521. * moved finalize and setlength from ninl to pinline
  522. }