/compiler/wpobase.pas

https://github.com/slibre/freepascal · Pascal · 829 lines · 499 code · 146 blank · 184 comment · 41 complexity · 950e3e2213b78b1a0115dd4522fb2fc1 MD5 · raw file

  1. {
  2. Copyright (c) 2008 by Jonas Maebe
  3. Whole program optimisation information collection base class
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit wpobase;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,
  22. cclasses,
  23. symtype;
  24. type
  25. { the types of available whole program optimization }
  26. twpotype = (wpo_devirtualization_context_insensitive,wpo_live_symbol_information);
  27. const
  28. wpo2str: array[twpotype] of string[16] = ('devirtualization','symbol liveness');
  29. type
  30. { ************************************************************************* }
  31. { ******************** General base classes/interfaces ******************** }
  32. { ************************************************************************* }
  33. { interface to reading a section from a file with wpo info }
  34. twposectionreaderintf = interface
  35. ['{51BE3F89-C9C5-4965-9C83-AE7490C92E3E}']
  36. function sectiongetnextline(out s: string): boolean;
  37. end;
  38. { interface to writing sections to a file with wpoinfo }
  39. twposectionwriterintf = interface
  40. ['{C056F0DD-62B1-4612-86C7-2D39944C4437}']
  41. procedure startsection(const name: string);
  42. procedure sectionputline(const s: string);
  43. end;
  44. { base class for wpo information stores }
  45. { twpocomponentbase }
  46. twpocomponentbase = class
  47. public
  48. constructor create; reintroduce; virtual;
  49. { type of whole program optimization information collected/provided by
  50. this class
  51. }
  52. class function getwpotype: twpotype; virtual; abstract;
  53. { whole program optimizations for which this class generates information }
  54. class function generatesinfoforwposwitches: twpoptimizerswitches; virtual; abstract;
  55. { whole program optimizations performed by this class }
  56. class function performswpoforswitches: twpoptimizerswitches; virtual; abstract;
  57. { returns the name of the section parsed by this class }
  58. class function sectionname: shortstring; virtual; abstract;
  59. { checks whether the compiler options are compatible with this
  60. optimization (default: don't check anything)
  61. }
  62. class procedure checkoptions; virtual;
  63. { loads the information pertinent to this whole program optimization from
  64. the current section being processed by reader
  65. }
  66. procedure loadfromwpofilesection(reader: twposectionreaderintf); virtual; abstract;
  67. { stores the information of this component to a file in a format that can
  68. be loaded again using loadfromwpofilesection()
  69. }
  70. procedure storewpofilesection(writer: twposectionwriterintf); virtual; abstract;
  71. { extracts the information pertinent to this whole program optimization
  72. from the current compiler state (loaded units, ...)
  73. }
  74. procedure constructfromcompilerstate; virtual; abstract;
  75. end;
  76. twpocomponentbaseclass = class of twpocomponentbase;
  77. { forward declaration of overall wpo info manager class }
  78. twpoinfomanagerbase = class;
  79. { ************************************************************************* }
  80. { ** Information created per unit for use during subsequent compilation *** }
  81. { ************************************************************************* }
  82. { information about called vmt entries for a class }
  83. tcalledvmtentries = class
  84. protected
  85. { the class }
  86. fobjdef: tdef;
  87. fobjdefderef: tderef;
  88. { the vmt entries }
  89. fcalledentries: tbitset;
  90. public
  91. constructor create(_objdef: tdef; nentries: longint);
  92. constructor ppuload(ppufile: tcompilerppufile);
  93. destructor destroy; override;
  94. procedure ppuwrite(ppufile: tcompilerppufile);
  95. procedure buildderef;
  96. procedure buildderefimpl;
  97. procedure deref;
  98. procedure derefimpl;
  99. property objdef: tdef read fobjdef write fobjdef;
  100. property objdefderef: tderef read fobjdefderef write fobjdefderef;
  101. property calledentries: tbitset read fcalledentries write fcalledentries;
  102. end;
  103. { base class of information collected per unit. Still needs to be
  104. generalised for different kinds of wpo information, currently specific
  105. to devirtualization.
  106. }
  107. tunitwpoinfobase = class
  108. protected
  109. { created object types }
  110. fcreatedobjtypes: tfpobjectlist;
  111. { objectdefs pointed to by created classrefdefs }
  112. fcreatedclassrefobjtypes: tfpobjectlist;
  113. { objtypes potentially instantiated by fcreatedclassrefobjtypes
  114. (objdectdefs pointed to by classrefdefs that are
  115. passed as a regular parameter, loaded in a variable, ...
  116. so they can end up in a classrefdef var and be instantiated)
  117. }
  118. fmaybecreatedbyclassrefdeftypes: tfpobjectlist;
  119. { called virtual methods for all classes (hashed by mangled classname,
  120. entries bitmaps indicating which vmt entries per class are called --
  121. tcalledvmtentries)
  122. }
  123. fcalledvmtentries: tfphashlist;
  124. public
  125. constructor create; reintroduce; virtual;
  126. destructor destroy; override;
  127. property createdobjtypes: tfpobjectlist read fcreatedobjtypes;
  128. property createdclassrefobjtypes: tfpobjectlist read fcreatedclassrefobjtypes;
  129. property maybecreatedbyclassrefdeftypes: tfpobjectlist read fmaybecreatedbyclassrefdeftypes;
  130. property calledvmtentries: tfphashlist read fcalledvmtentries;
  131. procedure addcreatedobjtype(def: tdef);
  132. procedure addcreatedobjtypeforclassref(def: tdef);
  133. procedure addmaybecreatedbyclassref(def: tdef);
  134. procedure addcalledvmtentry(def: tdef; index: longint);
  135. { resets the "I've been registered with wpo" flags for all defs in the
  136. above lists }
  137. procedure resetdefs;
  138. end;
  139. { ************************************************************************* }
  140. { **** Total information created for use during subsequent compilation **** }
  141. { ************************************************************************* }
  142. { class to create a file with wpo information }
  143. { tavailablewpofilewriter }
  144. twpofilewriter = class(tobject,twposectionwriterintf)
  145. private
  146. { array of class *instances* that wish to be written out to the
  147. whole program optimization feedback file
  148. }
  149. fsectioncontents: tfpobjectlist;
  150. ffilename: tcmdstr;
  151. foutputfile: text;
  152. public
  153. constructor create(const fn: tcmdstr);
  154. destructor destroy; override;
  155. procedure writefile;
  156. { starts a new section with name "name" }
  157. procedure startsection(const name: string);
  158. { writes s to the wpo file }
  159. procedure sectionputline(const s: string);
  160. { register a component instance that needs to be written
  161. to the wpo feedback file
  162. }
  163. procedure registerwpocomponent(component: twpocomponentbase);
  164. end;
  165. { ************************************************************************* }
  166. { ************ Information for use during current compilation ************* }
  167. { ************************************************************************* }
  168. { class to read a file with wpo information }
  169. twpofilereader = class(tobject,twposectionreaderintf)
  170. private
  171. ffilename: tcmdstr;
  172. flinenr: longint;
  173. finputfile: text;
  174. fcurline: string;
  175. fusecurline: boolean;
  176. { destination for the read information }
  177. fdest: twpoinfomanagerbase;
  178. function getnextnoncommentline(out s: string): boolean;
  179. public
  180. constructor create(const fn: tcmdstr; dest: twpoinfomanagerbase);
  181. destructor destroy; override;
  182. { processes the wpo info in the file }
  183. procedure processfile;
  184. { returns next line of the current section in s, and false if no more
  185. lines in the current section
  186. }
  187. function sectiongetnextline(out s: string): boolean;
  188. end;
  189. { ************************************************************************* }
  190. { ******* Specific kinds of whole program optimization components ********* }
  191. { ************************************************************************* }
  192. { method devirtualisation }
  193. twpodevirtualisationhandler = class(twpocomponentbase)
  194. { checks whether procdef (a procdef for a virtual method) can be replaced with
  195. a static call when it's called as objdef.procdef, and if so returns the
  196. mangled name in staticname.
  197. }
  198. function staticnameforcallingvirtualmethod(objdef, procdef: tdef; out staticname: string): boolean; virtual; abstract;
  199. { checks whether procdef (a procdef for a virtual method) can be replaced with
  200. a different procname in the vmt of objdef, and if so returns the new
  201. mangledname in staticname
  202. }
  203. function staticnameforvmtentry(objdef, procdef: tdef; out staticname: string): boolean; virtual; abstract;
  204. end;
  205. twpodeadcodehandler = class(twpocomponentbase)
  206. { checks whether a mangledname was removed as dead code from the final
  207. binary (WARNING: must *not* be called for functions marked as inline,
  208. since if all call sites are inlined, it won't appear in the final
  209. binary but nevertheless is still necessary!)
  210. }
  211. function symbolinfinalbinary(const s: shortstring): boolean; virtual; abstract;
  212. end;
  213. { ************************************************************************* }
  214. { ************ Collection of all instances of wpo components ************** }
  215. { ************************************************************************* }
  216. { class doing all the bookkeeping for everything }
  217. twpoinfomanagerbase = class
  218. private
  219. { array of classrefs of handler classes for the various kinds of whole
  220. program optimizations that we support
  221. }
  222. fwpocomponents: tfphashlist;
  223. freader: twpofilereader;
  224. fwriter: twpofilewriter;
  225. public
  226. { instances of the various optimizers/information collectors (for
  227. information used during this compilation)
  228. }
  229. wpoinfouse: array[twpotype] of twpocomponentbase;
  230. { register a whole program optimization class type }
  231. procedure registerwpocomponentclass(wpocomponent: twpocomponentbaseclass);
  232. { get the program optimization class type that can parse the contents
  233. of the section with name "secname" in the wpo feedback file
  234. }
  235. function gethandlerforsection(const secname: string): twpocomponentbaseclass;
  236. { tell all instantiated wpo component classes to collect the information
  237. from the global compiler state that they need (done at the very end of
  238. the compilation process)
  239. }
  240. procedure extractwpoinfofromprogram;
  241. { set the name of the feedback file from which all whole-program information
  242. to be used during the current compilation will be read
  243. }
  244. procedure setwpoinputfile(const fn: tcmdstr);
  245. { set the name of the feedback file to which all whole-program information
  246. collected during the current compilation will be written
  247. }
  248. procedure setwpooutputfile(const fn: tcmdstr);
  249. { check whether the specified wpo options (-FW/-Fw/-OW/-Ow) are complete
  250. and sensical, and parse the wpo feedback file specified with
  251. setwpoinputfile
  252. }
  253. procedure parseandcheckwpoinfo;
  254. { routines accessing the optimizer information }
  255. { 1) devirtualization at the symbol name level }
  256. function can_be_devirtualized(objdef, procdef: tdef; out name: shortstring): boolean; virtual; abstract;
  257. { 2) optimal replacement method name in vmt }
  258. function optimized_name_for_vmt(objdef, procdef: tdef; out name: shortstring): boolean; virtual; abstract;
  259. { 3) does a symbol appear in the final binary (i.e., not removed by dead code stripping/smart linking).
  260. WARNING: do *not* call for inline functions/procedures/methods/...
  261. }
  262. function symbol_live(const name: shortstring): boolean; virtual; abstract;
  263. constructor create; reintroduce;
  264. destructor destroy; override;
  265. end;
  266. var
  267. wpoinfomanager: twpoinfomanagerbase;
  268. implementation
  269. uses
  270. globals,
  271. cutils,
  272. sysutils,
  273. symdef,
  274. verbose;
  275. { tcreatedwpoinfobase }
  276. constructor tunitwpoinfobase.create;
  277. begin
  278. fcreatedobjtypes:=tfpobjectlist.create(false);
  279. fcreatedclassrefobjtypes:=tfpobjectlist.create(false);
  280. fmaybecreatedbyclassrefdeftypes:=tfpobjectlist.create(false);
  281. fcalledvmtentries:=tfphashlist.create;
  282. end;
  283. destructor tunitwpoinfobase.destroy;
  284. var
  285. i: longint;
  286. begin
  287. { don't call resetdefs here, because the defs may have been freed
  288. already }
  289. fcreatedobjtypes.free;
  290. fcreatedobjtypes:=nil;
  291. fcreatedclassrefobjtypes.free;
  292. fcreatedclassrefobjtypes:=nil;
  293. fmaybecreatedbyclassrefdeftypes.free;
  294. fmaybecreatedbyclassrefdeftypes:=nil;
  295. { may not be assigned in case the info was loaded from a ppu and we
  296. are not generating a wpo feedback file (see tunitwpoinfo.ppuload)
  297. }
  298. if assigned(fcalledvmtentries) then
  299. begin
  300. for i:=0 to fcalledvmtentries.count-1 do
  301. tcalledvmtentries(fcalledvmtentries[i]).free;
  302. fcalledvmtentries.free;
  303. fcalledvmtentries:=nil;
  304. end;
  305. inherited destroy;
  306. end;
  307. procedure tunitwpoinfobase.resetdefs;
  308. var
  309. i: ptrint;
  310. begin
  311. if assigned(fcreatedobjtypes) then
  312. for i:=0 to fcreatedobjtypes.count-1 do
  313. tobjectdef(fcreatedobjtypes[i]).created_in_current_module:=false;
  314. if assigned(fcreatedclassrefobjtypes) then
  315. for i:=0 to fcreatedclassrefobjtypes.count-1 do
  316. tobjectdef(fcreatedclassrefobjtypes[i]).classref_created_in_current_module:=false;
  317. if assigned(fmaybecreatedbyclassrefdeftypes) then
  318. for i:=0 to fmaybecreatedbyclassrefdeftypes.count-1 do
  319. tobjectdef(fmaybecreatedbyclassrefdeftypes[i]).maybe_created_in_current_module:=false;
  320. end;
  321. procedure tunitwpoinfobase.addcreatedobjtype(def: tdef);
  322. begin
  323. fcreatedobjtypes.add(def);
  324. end;
  325. procedure tunitwpoinfobase.addcreatedobjtypeforclassref(def: tdef);
  326. begin
  327. fcreatedclassrefobjtypes.add(def);
  328. end;
  329. procedure tunitwpoinfobase.addmaybecreatedbyclassref(def: tdef);
  330. begin
  331. fmaybecreatedbyclassrefdeftypes.add(def);
  332. end;
  333. procedure tunitwpoinfobase.addcalledvmtentry(def: tdef; index: longint);
  334. var
  335. entries: tcalledvmtentries;
  336. key: shortstring;
  337. begin
  338. key:=tobjectdef(def).vmt_mangledname;
  339. entries:=tcalledvmtentries(fcalledvmtentries.find(key));
  340. if not assigned(entries) then
  341. begin
  342. entries:=tcalledvmtentries.create(def,tobjectdef(def).vmtentries.count);
  343. fcalledvmtentries.add(key,entries);
  344. end;
  345. entries.calledentries.include(index);
  346. end;
  347. { twpofilereader }
  348. function twpofilereader.getnextnoncommentline(out s: string):
  349. boolean;
  350. begin
  351. if (fusecurline) then
  352. begin
  353. s:=fcurline;
  354. fusecurline:=false;
  355. result:=true;
  356. exit;
  357. end;
  358. repeat
  359. readln(finputfile,s);
  360. if (s='') and
  361. eof(finputfile) then
  362. begin
  363. result:=false;
  364. exit;
  365. end;
  366. inc(flinenr);
  367. until (s='') or
  368. (s[1]<>'#');
  369. result:=true;
  370. end;
  371. constructor twpofilereader.create(const fn: tcmdstr; dest: twpoinfomanagerbase);
  372. begin
  373. if not FileExists(fn) or
  374. { FileExists also returns true for directories }
  375. DirectoryExists(fn) then
  376. begin
  377. cgmessage1(wpo_cant_find_file,fn);
  378. exit;
  379. end;
  380. assign(finputfile,fn);
  381. ffilename:=fn;
  382. fdest:=dest;
  383. end;
  384. destructor twpofilereader.destroy;
  385. begin
  386. inherited destroy;
  387. end;
  388. procedure twpofilereader.processfile;
  389. var
  390. sectionhandler: twpocomponentbaseclass;
  391. i: longint;
  392. wpotype: twpotype;
  393. s,
  394. sectionname: string;
  395. begin
  396. cgmessage1(wpo_begin_processing,ffilename);
  397. reset(finputfile);
  398. flinenr:=0;
  399. while getnextnoncommentline(s) do
  400. begin
  401. if (s='') then
  402. continue;
  403. { format: "% sectionname" }
  404. if (s[1]<>'%') then
  405. begin
  406. cgmessage2(wpo_expected_section,tostr(flinenr),s);
  407. break;
  408. end;
  409. for i:=2 to length(s) do
  410. if (s[i]<>' ') then
  411. break;
  412. sectionname:=copy(s,i,255);
  413. { find handler for section and process }
  414. sectionhandler:=fdest.gethandlerforsection(sectionname);
  415. if assigned(sectionhandler) then
  416. begin
  417. wpotype:=sectionhandler.getwpotype;
  418. cgmessage2(wpo_found_section,sectionname,wpo2str[wpotype]);
  419. { do we need this information? }
  420. if ((sectionhandler.performswpoforswitches * init_settings.dowpoptimizerswitches) <> []) then
  421. begin
  422. { did some other section already generate this type of information? }
  423. if assigned(fdest.wpoinfouse[wpotype]) then
  424. begin
  425. cgmessage2(wpo_duplicate_wpotype,wpo2str[wpotype],sectionname);
  426. fdest.wpoinfouse[wpotype].free;
  427. end;
  428. { process the section }
  429. fdest.wpoinfouse[wpotype]:=sectionhandler.create;
  430. twpocomponentbase(fdest.wpoinfouse[wpotype]).loadfromwpofilesection(self);
  431. end
  432. else
  433. begin
  434. cgmessage1(wpo_skipping_unnecessary_section,sectionname);
  435. { skip the current section }
  436. while sectiongetnextline(s) do
  437. ;
  438. end;
  439. end
  440. else
  441. begin
  442. cgmessage1(wpo_no_section_handler,sectionname);
  443. { skip the current section }
  444. while sectiongetnextline(s) do
  445. ;
  446. end;
  447. end;
  448. close(finputfile);
  449. cgmessage1(wpo_end_processing,ffilename);
  450. end;
  451. function twpofilereader.sectiongetnextline(out s: string): boolean;
  452. begin
  453. result:=getnextnoncommentline(s);
  454. if not result then
  455. exit;
  456. { start of new section? }
  457. if (s<>'') and
  458. (s[1]='%') then
  459. begin
  460. { keep read line for next call to getnextnoncommentline() }
  461. fcurline:=s;
  462. fusecurline:=true;
  463. result:=false;
  464. end;
  465. end;
  466. { twpocomponentbase }
  467. constructor twpocomponentbase.create;
  468. begin
  469. { do nothing }
  470. end;
  471. class procedure twpocomponentbase.checkoptions;
  472. begin
  473. { do nothing }
  474. end;
  475. { twpofilewriter }
  476. constructor twpofilewriter.create(const fn: tcmdstr);
  477. begin
  478. assign(foutputfile,fn);
  479. ffilename:=fn;
  480. fsectioncontents:=tfpobjectlist.create(true);
  481. end;
  482. destructor twpofilewriter.destroy;
  483. begin
  484. fsectioncontents.free;
  485. inherited destroy;
  486. end;
  487. procedure twpofilewriter.writefile;
  488. var
  489. i: longint;
  490. begin
  491. {$push}{$i-}
  492. rewrite(foutputfile);
  493. {$pop}
  494. if (ioresult <> 0) then
  495. begin
  496. cgmessage1(wpo_cant_create_feedback_file,ffilename);
  497. exit;
  498. end;
  499. for i:=0 to fsectioncontents.count-1 do
  500. twpocomponentbase(fsectioncontents[i]).storewpofilesection(self);
  501. close(foutputfile);
  502. end;
  503. procedure twpofilewriter.startsection(const name: string);
  504. begin
  505. writeln(foutputfile,'% ',name);
  506. end;
  507. procedure twpofilewriter.sectionputline(const s: string);
  508. begin
  509. writeln(foutputfile,s);
  510. end;
  511. procedure twpofilewriter.registerwpocomponent(
  512. component: twpocomponentbase);
  513. begin
  514. fsectioncontents.add(component);
  515. end;
  516. { twpoinfomanagerbase }
  517. procedure twpoinfomanagerbase.registerwpocomponentclass(wpocomponent: twpocomponentbaseclass);
  518. begin
  519. fwpocomponents.add(wpocomponent.sectionname,wpocomponent);
  520. end;
  521. function twpoinfomanagerbase.gethandlerforsection(const secname: string
  522. ): twpocomponentbaseclass;
  523. begin
  524. result:=twpocomponentbaseclass(fwpocomponents.find(secname));
  525. end;
  526. procedure twpoinfomanagerbase.setwpoinputfile(const fn: tcmdstr);
  527. begin
  528. freader:=twpofilereader.create(fn,self);
  529. end;
  530. procedure twpoinfomanagerbase.setwpooutputfile(const fn: tcmdstr);
  531. begin
  532. fwriter:=twpofilewriter.create(fn);
  533. end;
  534. procedure twpoinfomanagerbase.parseandcheckwpoinfo;
  535. var
  536. i: longint;
  537. begin
  538. { error if we don't have to optimize yet have an input feedback file }
  539. if (init_settings.dowpoptimizerswitches=[]) and
  540. assigned(freader) then
  541. begin
  542. cgmessage(wpo_input_without_info_use);
  543. exit;
  544. end;
  545. { error if we have to optimize yet don't have an input feedback file }
  546. if (init_settings.dowpoptimizerswitches<>[]) and
  547. not assigned(freader) then
  548. begin
  549. cgmessage(wpo_no_input_specified);
  550. exit;
  551. end;
  552. { if we have to generate wpo information, check that a file has been
  553. specified and that we have something to write to it
  554. }
  555. if (init_settings.genwpoptimizerswitches<>[]) and
  556. not assigned(fwriter) then
  557. begin
  558. cgmessage(wpo_no_output_specified);
  559. exit;
  560. end;
  561. if (init_settings.genwpoptimizerswitches=[]) and
  562. assigned(fwriter) then
  563. begin
  564. cgmessage(wpo_output_without_info_gen);
  565. exit;
  566. end;
  567. { now read the input feedback file }
  568. if assigned(freader) then
  569. begin
  570. freader.processfile;
  571. freader.free;
  572. freader:=nil;
  573. end;
  574. { and for each specified optimization check whether the input feedback
  575. file contained the necessary information
  576. }
  577. if (([cs_wpo_devirtualize_calls,cs_wpo_optimize_vmts] * init_settings.dowpoptimizerswitches) <> []) and
  578. not assigned(wpoinfouse[wpo_devirtualization_context_insensitive]) then
  579. begin
  580. cgmessage1(wpo_not_enough_info,wpo2str[wpo_devirtualization_context_insensitive]);
  581. exit;
  582. end;
  583. if (cs_wpo_symbol_liveness in init_settings.dowpoptimizerswitches) and
  584. not assigned(wpoinfouse[wpo_live_symbol_information]) then
  585. begin
  586. cgmessage1(wpo_not_enough_info,wpo2str[wpo_live_symbol_information]);
  587. exit;
  588. end;
  589. { perform pre-checking to ensure there are no known incompatibilities between
  590. the selected optimizations and other switches
  591. }
  592. for i:=0 to fwpocomponents.count-1 do
  593. if (twpocomponentbaseclass(fwpocomponents[i]).generatesinfoforwposwitches*init_settings.genwpoptimizerswitches)<>[] then
  594. twpocomponentbaseclass(fwpocomponents[i]).checkoptions
  595. end;
  596. procedure twpoinfomanagerbase.extractwpoinfofromprogram;
  597. var
  598. i: longint;
  599. info: twpocomponentbase;
  600. begin
  601. { if don't have to write anything, fwriter has not been created }
  602. if not assigned(fwriter) then
  603. exit;
  604. { let all wpo components gather the necessary info from the compiler state }
  605. for i:=0 to fwpocomponents.count-1 do
  606. if (twpocomponentbaseclass(fwpocomponents[i]).generatesinfoforwposwitches*current_settings.genwpoptimizerswitches)<>[] then
  607. begin
  608. info:=twpocomponentbaseclass(fwpocomponents[i]).create;
  609. info.constructfromcompilerstate;
  610. fwriter.registerwpocomponent(info);
  611. end;
  612. { and write their info to disk }
  613. fwriter.writefile;
  614. fwriter.free;
  615. fwriter:=nil;
  616. end;
  617. constructor twpoinfomanagerbase.create;
  618. begin
  619. inherited create;
  620. fwpocomponents:=tfphashlist.create;
  621. end;
  622. destructor twpoinfomanagerbase.destroy;
  623. var
  624. i: twpotype;
  625. begin
  626. freader.free;
  627. freader:=nil;
  628. fwriter.free;
  629. fwriter:=nil;
  630. fwpocomponents.free;
  631. fwpocomponents:=nil;
  632. for i:=low(wpoinfouse) to high(wpoinfouse) do
  633. if assigned(wpoinfouse[i]) then
  634. wpoinfouse[i].free;
  635. inherited destroy;
  636. end;
  637. { tcalledvmtentries }
  638. constructor tcalledvmtentries.create(_objdef: tdef; nentries: longint);
  639. begin
  640. objdef:=_objdef;
  641. calledentries:=tbitset.create(nentries);
  642. end;
  643. constructor tcalledvmtentries.ppuload(ppufile: tcompilerppufile);
  644. var
  645. len: longint;
  646. begin
  647. ppufile.getderef(fobjdefderef);
  648. len:=ppufile.getlongint;
  649. calledentries:=tbitset.create_bytesize(len);
  650. if (len <> calledentries.datasize) then
  651. internalerror(2009060301);
  652. ppufile.readdata(calledentries.data^,len);
  653. end;
  654. destructor tcalledvmtentries.destroy;
  655. begin
  656. fcalledentries.free;
  657. inherited destroy;
  658. end;
  659. procedure tcalledvmtentries.ppuwrite(ppufile: tcompilerppufile);
  660. begin
  661. ppufile.putderef(objdefderef);
  662. ppufile.putlongint(calledentries.datasize);
  663. ppufile.putdata(calledentries.data^,calledentries.datasize);
  664. end;
  665. procedure tcalledvmtentries.buildderef;
  666. begin
  667. objdefderef.build(objdef);
  668. end;
  669. procedure tcalledvmtentries.buildderefimpl;
  670. begin
  671. end;
  672. procedure tcalledvmtentries.deref;
  673. begin
  674. objdef:=tdef(objdefderef.resolve);
  675. end;
  676. procedure tcalledvmtentries.derefimpl;
  677. begin
  678. end;
  679. end.