1 {
2     Copyright (c) 2008 by Jonas Maebe
3 
4     Whole program optimisation information collection
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  ****************************************************************************
20 }
21 
22 unit wpoinfo;
23 
24 {$i fpcdefs.inc}
25 
26 interface
27 
28 uses
29   globtype,cclasses,
30   symtype,
31   wpobase;
32 
33 type
34   pderefarray = ^tderefarray;
35   tderefarray = array[0..1024*1024-1] of tderef;
36 
37   tunitwpoinfo = class(tunitwpoinfobase)
38    { devirtualisation information -- begin }
39    private
40     fcreatedobjtypesderefs: pderefarray;
41     fcreatedclassrefobjtypesderefs: pderefarray;
42     fmaybecreatedbyclassrefdeftypesderefs: pderefarray;
43     fcalledvmtentriestemplist: tfpobjectlist;
44    { devirtualisation information -- end }
45 
46     procedure clearderefinfo;
47    public
48 
49     destructor destroy; override;
50 
51     procedure ppuwrite(ppufile:tcompilerppufile);
52     constructor ppuload(ppufile:tcompilerppufile);
53 
54     procedure deref;
55     procedure derefimpl;
56     procedure buildderef;
57     procedure buildderefimpl;
58   end;
59 
60 
61   { twpoinfomanager }
62 
63   twpoinfomanager = class(twpoinfomanagerbase)
can_be_devirtualizednull64     function can_be_devirtualized(objdef, procdef: tdef; out name: TSymStr): boolean; override;
optimized_name_for_vmtnull65     function optimized_name_for_vmt(objdef, procdef: tdef; out name: TSymStr): boolean; override;
symbol_livenull66     function symbol_live(const name: shortstring): boolean; override;
67   end;
68 
69 
70 implementation
71 
72   uses
73     globals,
74     symdef,
75     verbose,
76     entfile;
77 
78   procedure tunitwpoinfo.clearderefinfo;
79     begin
80       if assigned(fcreatedobjtypesderefs) then
81         begin
82           freemem(fcreatedobjtypesderefs);
83           fcreatedobjtypesderefs:=nil;
84         end;
85       if assigned(fcreatedclassrefobjtypesderefs) then
86         begin
87           freemem(fcreatedclassrefobjtypesderefs);
88           fcreatedclassrefobjtypesderefs:=nil;
89         end;
90       if assigned(fmaybecreatedbyclassrefdeftypesderefs) then
91         begin
92           freemem(fmaybecreatedbyclassrefdeftypesderefs);
93           fmaybecreatedbyclassrefdeftypesderefs:=nil;
94         end;
95 
96       if assigned(fcalledvmtentriestemplist) then
97         begin
98           fcalledvmtentriestemplist.free;
99           fcalledvmtentriestemplist:=nil;
100         end;
101     end;
102 
103   destructor tunitwpoinfo.destroy;
104     begin
105       clearderefinfo;
106       inherited destroy;
107     end;
108 
109 
110   procedure tunitwpoinfo.ppuwrite(ppufile:tcompilerppufile);
111     var
112       i: longint;
113     begin
114       { write the number of instantiated object types in this module,
115         followed by the derefs of those types
116       }
117       ppufile.putlongint(fcreatedobjtypes.count);
118       for i:=0 to fcreatedobjtypes.count-1 do
119         ppufile.putderef(fcreatedobjtypesderefs^[i]);
120       ppufile.putlongint(fcreatedclassrefobjtypes.count);
121       for i:=0 to fcreatedclassrefobjtypes.count-1 do
122         ppufile.putderef(fcreatedclassrefobjtypesderefs^[i]);
123       ppufile.putlongint(fmaybecreatedbyclassrefdeftypes.count);
124       for i:=0 to fmaybecreatedbyclassrefdeftypes.count-1 do
125         ppufile.putderef(fmaybecreatedbyclassrefdeftypesderefs^[i]);
126 
127       ppufile.putlongint(fcalledvmtentriestemplist.count);
128       for i:=0 to fcalledvmtentriestemplist.count-1 do
129         tcalledvmtentries(fcalledvmtentriestemplist[i]).ppuwrite(ppufile);
130 
131       ppufile.writeentry(ibcreatedobjtypes);
132 
133       { don't free deref arrays immediately after use, as the types may need
134         re-resolving in case a unit needs to be reloaded
135       }
136     end;
137 
138 
139   constructor tunitwpoinfo.ppuload(ppufile:tcompilerppufile);
140     var
141       i, len: longint;
142     begin
143       { load start of definition section, which holds the amount of defs }
144       if ppufile.readentry<>ibcreatedobjtypes then
145         message(unit_f_ppu_read_error);
146 
147       { don't load the wpo info from the units if we are not generating
148         a wpo feedback file (that would just take time and memory)
149       }
150       if (init_settings.genwpoptimizerswitches=[]) then
151         ppufile.skipdata(ppufile.entrysize)
152       else
153         begin
154           len:=ppufile.getlongint;
155           fcreatedobjtypes:=tfpobjectlist.create(false);
156           fcreatedobjtypes.count:=len;
157           getmem(fcreatedobjtypesderefs,len*sizeof(tderef));
158           for i:=0 to len-1 do
159             ppufile.getderef(fcreatedobjtypesderefs^[i]);
160 
161           len:=ppufile.getlongint;
162           fcreatedclassrefobjtypes:=tfpobjectlist.create(false);
163           fcreatedclassrefobjtypes.count:=len;
164           getmem(fcreatedclassrefobjtypesderefs,len*sizeof(tderef));
165           for i:=0 to len-1 do
166             ppufile.getderef(fcreatedclassrefobjtypesderefs^[i]);
167 
168           len:=ppufile.getlongint;
169           fmaybecreatedbyclassrefdeftypes:=tfpobjectlist.create(false);
170           fmaybecreatedbyclassrefdeftypes.count:=len;
171           getmem(fmaybecreatedbyclassrefdeftypesderefs,len*sizeof(tderef));
172           for i:=0 to len-1 do
173             ppufile.getderef(fmaybecreatedbyclassrefdeftypesderefs^[i]);
174 
175           len:=ppufile.getlongint;
176           fcalledvmtentriestemplist:=tfpobjectlist.create(false);
177           fcalledvmtentriestemplist.count:=len;
178           fcalledvmtentries:=tfphashlist.create;
179           for i:=0 to len-1 do
180             fcalledvmtentriestemplist[i]:=tcalledvmtentries.ppuload(ppufile);
181         end;
182     end;
183 
184 
185   procedure tunitwpoinfo.buildderef;
186     var
187       i: longint;
188     begin
189       { ppuload may have already been called before -> deref info structures
190         may already have been allocated }
191       clearderefinfo;
192 
193       getmem(fcreatedobjtypesderefs,fcreatedobjtypes.count*sizeof(tderef));
194       for i:=0 to fcreatedobjtypes.count-1 do
195         fcreatedobjtypesderefs^[i].build(fcreatedobjtypes[i]);
196 
197       getmem(fcreatedclassrefobjtypesderefs,fcreatedclassrefobjtypes.count*sizeof(tderef));
198       for i:=0 to fcreatedclassrefobjtypes.count-1 do
199         fcreatedclassrefobjtypesderefs^[i].build(fcreatedclassrefobjtypes[i]);
200 
201       getmem(fmaybecreatedbyclassrefdeftypesderefs,fmaybecreatedbyclassrefdeftypes.count*sizeof(tderef));
202       for i:=0 to fmaybecreatedbyclassrefdeftypes.count-1 do
203         fmaybecreatedbyclassrefdeftypesderefs^[i].build(fmaybecreatedbyclassrefdeftypes[i]);
204 
205       fcalledvmtentriestemplist:=tfpobjectlist.create(false);
206       fcalledvmtentriestemplist.count:=fcalledvmtentries.count;
207       for i:=0 to fcalledvmtentries.count-1 do
208         begin
209           tcalledvmtentries(fcalledvmtentries[i]).buildderef;
210           { necessary in case we have unit1 loads unit2, unit2 is recompiled,
211             then unit1 derefs unit2 -> in this case we have buildderef for unit2
212             -> ppuwrite for unit2 -> deref for unit2 (without a load) -> ensure
213             that the fcalledvmtentriestemplist, normally constructed by ppuload,
214             is created here as well since deref needs it }
215           fcalledvmtentriestemplist[i]:=tobject(fcalledvmtentries[i]);
216         end;
217     end;
218 
219 
220   procedure tunitwpoinfo.buildderefimpl;
221     var
222       i: longint;
223     begin
224       for i:=0 to fcalledvmtentriestemplist.count-1 do
225         begin
226           tcalledvmtentries(fcalledvmtentriestemplist[i]).buildderefimpl;
227         end;
228     end;
229 
230 
231   procedure tunitwpoinfo.deref;
232     var
233       i: longint;
234 
235     begin
236       if (init_settings.genwpoptimizerswitches=[]) or
237          not assigned(fcalledvmtentriestemplist) then
238         exit;
239 
240       { don't free deref arrays immediately after use, as the types may need
241         re-resolving in case a unit needs to be reloaded
242       }
243       for i:=0 to fcreatedobjtypes.count-1 do
244         fcreatedobjtypes[i]:=fcreatedobjtypesderefs^[i].resolve;
245 
246       for i:=0 to fcreatedclassrefobjtypes.count-1 do
247         fcreatedclassrefobjtypes[i]:=fcreatedclassrefobjtypesderefs^[i].resolve;
248 
249       for i:=0 to fmaybecreatedbyclassrefdeftypes.count-1 do
250         fmaybecreatedbyclassrefdeftypes[i]:=fmaybecreatedbyclassrefdeftypesderefs^[i].resolve;
251 
252       { in case we are re-resolving, free previous batch }
253       if (fcalledvmtentries.count<>0) then
254         fcalledvmtentries.clear;
255       { allocate enough internal memory in one go }
256       fcalledvmtentries.capacity:=fcalledvmtentriestemplist.count;
257       { now resolve all items in the list and add them to the hash table }
258       for i:=0 to fcalledvmtentriestemplist.count-1 do
259         begin
260           with tcalledvmtentries(fcalledvmtentriestemplist[i]) do
261             begin
262               deref;
263               fcalledvmtentries.add(tobjectdef(objdef).vmt_mangledname,
264                 fcalledvmtentriestemplist[i]);
265             end;
266         end;
267     end;
268 
269 
270   procedure tunitwpoinfo.derefimpl;
271     var
272       i: longint;
273     begin
274       if (init_settings.genwpoptimizerswitches=[]) or
275          not assigned(fcalledvmtentriestemplist) then
276         exit;
277 
278       for i:=0 to fcalledvmtentriestemplist.count-1 do
279         begin
280           tcalledvmtentries(fcalledvmtentriestemplist[i]).derefimpl;
281         end;
282     end;
283 
284 
285   { twpoinfomanager }
286 
287   { devirtualisation }
288 
twpoinfomanager.can_be_devirtualizednull289   function twpoinfomanager.can_be_devirtualized(objdef, procdef: tdef; out name: TSymStr): boolean;
290     begin
291       if not assigned(wpoinfouse[wpo_devirtualization_context_insensitive]) or
292          not(cs_wpo_devirtualize_calls in current_settings.dowpoptimizerswitches) then
293         begin
294           result:=false;
295           exit;
296         end;
297       result:=twpodevirtualisationhandler(wpoinfouse[wpo_devirtualization_context_insensitive]).staticnameforcallingvirtualmethod(objdef,procdef,name);
298     end;
299 
300 
twpoinfomanager.optimized_name_for_vmtnull301   function twpoinfomanager.optimized_name_for_vmt(objdef, procdef: tdef; out name: TSymStr): boolean;
302     begin
303       if not assigned(wpoinfouse[wpo_devirtualization_context_insensitive]) or
304          not(cs_wpo_optimize_vmts in current_settings.dowpoptimizerswitches) then
305         begin
306           result:=false;
307           exit;
308         end;
309       result:=twpodevirtualisationhandler(wpoinfouse[wpo_devirtualization_context_insensitive]).staticnameforvmtentry(objdef,procdef,name);
310     end;
311 
312 
313   { symbol liveness }
314 
twpoinfomanager.symbol_livenull315   function twpoinfomanager.symbol_live(const name: shortstring): boolean;
316     begin
317       if not assigned(wpoinfouse[wpo_live_symbol_information]) or
318          not(cs_wpo_symbol_liveness in current_settings.dowpoptimizerswitches) then
319         begin
320           { if we don't know, say that the symbol is live }
321           result:=true;
322           exit;
323         end;
324       result:=twpodeadcodehandler(wpoinfouse[wpo_live_symbol_information]).symbolinfinalbinary(name);
325     end;
326 
327 
328 end.
329