Merge branch 'pu/class_name' into wip
[nit.git] / src / compiling / table_computation.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2008 Jean Privat <jean@pryen.org>
4 # Copyright 2009 Jean-Sebastien Gelinas <calestar@gmail.com>
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17
18 # Compute tables for classes and modules.
19 package table_computation
20
21 import mmloader
22 import primitive_info
23 import program
24
25 # Something that store color of table elements
26 class ColorContext
27 var _colors: HashMap[TableElt, Int] = new HashMap[TableElt, Int]
28
29 # The color of a table element.
30 fun color(e: TableElt): Int
31 do
32 return _colors[e]
33 end
34
35 # Is a table element already colored?
36 fun has_color(e: TableElt): Bool
37 do
38 return _colors.has_key(e)
39 end
40
41 # Assign a color to a table element.
42 fun color=(e: TableElt, c: Int)
43 do
44 _colors[e] = c
45 var idx = c
46 for i in [0..e.length[ do
47 _colors[e.item(i)] = idx
48 idx = idx + 1
49 end
50 end
51 end
52
53 # All information and results of the global analysis.
54 class TableInformation
55 super ColorContext
56 # FIXME: do something better.
57 readable writable var _max_class_table_length: Int = 0
58 end
59
60 # A compiled class is a class in a program
61 class CompiledClass
62 super ColorContext
63 # The corresponding local class in the main module of the prgram
64 readable var _local_class: MMLocalClass
65
66 # The identifier of the class
67 readable writable var _id: Int = 0
68
69 # The full class table of the class
70 readable var _class_table: Array[nullable TableElt] = new Array[nullable TableElt]
71
72 # The full instance table of the class
73 readable var _instance_table: Array[nullable TableElt] = new Array[nullable TableElt]
74
75 # The proper class table part (no superclasses but all refinements)
76 readable writable var _class_layout: TableEltComposite = new TableEltComposite(self)
77
78 # The proper instance table part (no superclasses but all refinements)
79 readable writable var _instance_layout: TableEltComposite = new TableEltComposite(self)
80
81 init(c: MMLocalClass) do _local_class = c
82 end
83
84 redef class MMConcreteClass
85 # The table element of the subtype check
86 fun class_color_pos: TableEltClassColor do return _class_color_pos.as(not null)
87 var _class_color_pos: nullable TableEltClassColor
88
89 # The proper local class table part (nor superclasses nor refinments)
90 readable var _class_layout: Array[TableElt] = new Array[TableElt]
91
92 # The proper local instance table part (nor superclasses nor refinments)
93 readable var _instance_layout: Array[TableElt] = new Array[TableElt]
94
95 # Build the local layout of the class and feed the module table
96 private fun build_layout_in(module_table: Array[ModuleTableElt])
97 do
98 var clt = _class_layout
99 var ilt = _instance_layout
100
101 if global.intro == self then
102 module_table.add(new TableEltClassId(self))
103 var cpp = new TableEltClassColor(self)
104 _class_color_pos = cpp
105 module_table.add(cpp)
106 clt.add(new TableEltClassInitTable(self))
107 end
108 for p in local_local_properties do
109 var pg = p.global
110 if pg.intro == p then
111 if p isa MMAttribute then
112 ilt.add(new TableEltAttr(p))
113 else if p isa MMMethod then
114 clt.add(new TableEltMeth(p))
115 end
116 end
117 if p isa MMMethod and p.need_super then
118 clt.add(new TableEltSuper(p))
119 end
120 end
121
122 if not ilt.is_empty then
123 var teg = new ModuleTableEltGroup
124 teg.elements.append(ilt)
125 module_table.add(teg)
126 end
127
128 if not clt.is_empty then
129 var teg = new ModuleTableEltGroup
130 teg.elements.append(clt)
131 module_table.add(teg)
132 end
133 end
134 end
135
136 redef class Program
137 # Information about the class tables
138 readable var _table_information: TableInformation = new TableInformation
139
140 # Associate global classes to compiled classes
141 readable var _compiled_classes: HashMap[MMGlobalClass, CompiledClass] = new HashMap[MMGlobalClass, CompiledClass]
142
143 fun do_table_computation
144 do
145 tc.info("Building tables",1)
146 for m in main_module.mhe.greaters_and_self do
147 tc.info("Building tables for module: {m.name}",2)
148 m.local_analysis
149 end
150
151 tc.info("Merging all tables",2)
152 do_global_table_analysis
153 end
154
155 # Do the complete global analysis
156 private fun do_global_table_analysis
157 do
158 var smallest_classes = new Array[MMLocalClass]
159 var global_properties = new HashSet[MMGlobalProperty]
160 var ctab = new Array[TableElt]
161 var itab = new Array[TableElt]
162
163 ctab.add(new TableEltClassSelfId)
164 ctab.add(new TableEltClassObjectSize)
165 ctab.add(new TableEltClassSelfName)
166 itab.add(new TableEltVftPointer)
167 itab.add(new TableEltObjectId)
168
169 var pclassid = -1
170 var classid = 3
171
172 # We have to work on ALL the classes of the module
173 var classes = new Array[MMLocalClass]
174 for c in main_module.local_classes do classes.add(c)
175 classes.sort !cmp(x,y) = x.total_order_compare(y)
176
177 for c in classes do
178 # Associate a CompiledClass to the class
179 var cc = new CompiledClass(c)
180 compiled_classes[c.global] = cc
181
182 # Assign a unique class identifier
183 # (negative are for primitive classes)
184 var gc = c.global
185 var bm = gc.mmmodule
186 if c.primitive_info != null then
187 cc.id = pclassid
188 pclassid = pclassid - 4
189 else
190 cc.id = classid
191 classid = classid + 4
192 end
193
194 # Register is the class is a leaf
195 if c.cshe.direct_smallers.is_empty then
196 smallest_classes.add(c)
197 end
198
199 # Store the colortableelt in the class table pool
200 var bc = c.global.intro
201 assert bc isa MMConcreteClass
202 ctab.add(bc.class_color_pos)
203 end
204
205 # Compute core and crown classes for colorization
206 var crown_classes = new HashSet[MMLocalClass]
207 var core_classes = new HashSet[MMLocalClass]
208 for c in smallest_classes do
209 while c.cshe.direct_greaters.length == 1 do
210 c = c.cshe.direct_greaters.first
211 end
212 crown_classes.add(c)
213 core_classes.add_all(c.cshe.greaters_and_self)
214 end
215 #print("nbclasses: {classes.length} leaves: {smallest_classes.length} crown: {crown_classes.length} core: {core_classes.length}")
216
217 # Colorize core color for typechecks
218 colorize(ctab, crown_classes, 0)
219
220 # Compute tables for typechecks
221 var maxcolor = 0
222 for c in classes do
223 var cc = compiled_classes[c.global]
224 if core_classes.has(c) then
225 # For core classes, just build the table
226 build_tables_in(cc.class_table, c, ctab)
227 if maxcolor < cc.class_table.length then maxcolor = cc.class_table.length
228 else
229 # For other classes, it's easier: just append to the parent tables
230 var sc = c.cshe.direct_greaters.first
231 var scc = compiled_classes[sc.global]
232 assert cc.class_table.is_empty
233 cc.class_table.add_all(scc.class_table)
234 var bc = c.global.intro
235 assert bc isa MMConcreteClass
236 var colpos = bc.class_color_pos
237 var colposcolor = cc.class_table.length
238 table_information.color(colpos) = colposcolor
239 cc.class_table.add(colpos)
240 if maxcolor < colposcolor then maxcolor = colposcolor
241 end
242 end
243 table_information.max_class_table_length = maxcolor + 1
244
245 # Fill class table and instance tables pools
246 for c in classes do
247 var cc = compiled_classes[c.global]
248 var cte = cc.class_layout
249 var ite = cc.instance_layout
250 for sc in c.crhe.greaters_and_self do
251 if sc isa MMConcreteClass then
252 cte.add(sc, sc.class_layout)
253 ite.add(sc, sc.instance_layout)
254 end
255 end
256
257 if core_classes.has(c) then
258 if cte.length > 0 then
259 ctab.add(cte)
260 end
261 if ite.length > 0 then
262 itab.add(ite)
263 end
264 end
265 end
266
267 # Colorize all elements in pools tables
268 colorize(ctab, crown_classes, maxcolor+1)
269 colorize(itab, crown_classes, 0)
270
271 # Build class and instance tables now things are colored
272 table_information.max_class_table_length = 0
273 for c in classes do
274 var cc = compiled_classes[c.global]
275 if core_classes.has(c) then
276 # For core classes, just build the table
277 build_tables_in(cc.class_table, c, ctab)
278 build_tables_in(cc.instance_table, c, itab)
279 else
280 # For other classes, it's easier: just append to the parent tables
281 var sc = c.cshe.direct_greaters.first
282 var scc = compiled_classes[sc.global]
283 cc.class_table.clear
284 cc.class_table.add_all(scc.class_table)
285 var bc = c.global.intro
286 assert bc isa MMConcreteClass
287 var colpos = bc.class_color_pos
288 cc.class_table[table_information.color(colpos)] = colpos
289 while cc.class_table.length <= maxcolor do
290 cc.class_table.add(null)
291 end
292 append_to_table(cc.class_table, cc.class_layout)
293 assert cc.instance_table.is_empty
294 cc.instance_table.add_all(scc.instance_table)
295 append_to_table(cc.instance_table, cc.instance_layout)
296 end
297 end
298 end
299
300 # Perform coloring
301 fun colorize(elts: Array[TableElt], classes: Collection[MMLocalClass], startcolor: Int)
302 do
303 var colors = new HashMap[Int, Array[TableElt]]
304 var rel_classes = new Array[MMLocalClass]
305 for e in elts do
306 var color = -1
307 var len = e.length
308 if table_information.has_color(e) then
309 color = table_information.color(e)
310 else
311 rel_classes.clear
312 for c in classes do
313 if e.is_related_to(c) then
314 rel_classes.add(c)
315 end
316 end
317 var trycolor = startcolor
318 while trycolor != color do
319 color = trycolor
320 for c in rel_classes do
321 var idx = 0
322 while idx < len do
323 if colors.has_key(trycolor + idx) and not free_color(colors[trycolor + idx], c) then
324 trycolor = trycolor + idx + 1
325 idx = 0
326 else
327 idx = idx + 1
328 end
329 end
330 end
331 end
332 table_information.color(e) = color
333 end
334 for idx in [0..len[ do
335 if colors.has_key(color + idx) then
336 colors[color + idx].add(e)
337 else
338 colors[color + idx] = [e]
339 end
340 end
341 end
342 end
343
344 private fun free_color(es: Array[TableElt], c: MMLocalClass): Bool
345 do
346 for e2 in es do
347 if e2.is_related_to(c) then
348 return false
349 end
350 end
351 return true
352 end
353
354 private fun append_to_table(table: Array[nullable TableElt], cmp: TableEltComposite)
355 do
356 for j in [0..cmp.length[ do
357 var e = cmp.item(j)
358 table_information.color(e) = table.length
359 table.add(e)
360 end
361 end
362
363 private fun build_tables_in(table: Array[nullable TableElt], c: MMLocalClass, elts: Array[TableElt])
364 do
365 var tab = new HashMap[Int, TableElt]
366 var len = 0
367 for e in elts do
368 if e.is_related_to(c) then
369 var col = table_information.color(e)
370 var l = col + e.length
371 tab[col] = e
372 if len < l then
373 len = l
374 end
375 end
376 end
377 var i = 0
378 while i < len do
379 if tab.has_key(i) then
380 var e = tab[i]
381 for j in [0..e.length[ do
382 table[i] = e.item(j)
383 i = i + 1
384 end
385 else
386 table[i] = null
387 i = i + 1
388 end
389 end
390 end
391 end
392
393 redef class MMModule
394 # The local table of the module (refers things introduced in the module)
395 readable var _local_table: Array[ModuleTableElt] = new Array[ModuleTableElt]
396
397 # Builds the local tables and local classes layouts
398 private fun local_analysis
399 do
400 for c in local_classes do
401 if c isa MMConcreteClass then
402 c.build_layout_in(_local_table)
403 end
404 end
405 end
406 end
407
408 ###############################################################################
409
410 # An element of a class, an instance or a module table
411 abstract class AbsTableElt
412 end
413
414 # An element of a class or an instance table
415 # Such an elements represent method function pointers, attribute values, etc.
416 abstract class TableElt
417 super AbsTableElt
418 # Is the element conflict to class `c' (used for coloring)
419 fun is_related_to(c: MMLocalClass): Bool is abstract
420
421 # Number of sub-elements. 1 if none
422 fun length: Int do return 1
423
424 # Access the ith subelement.
425 fun item(i: Int): TableElt do return self
426 end
427
428 # An element of a module table
429 # Such an elements represent colors or identifiers
430 abstract class ModuleTableElt
431 super AbsTableElt
432 end
433
434 # An element of a module table that represents a group of TableElt defined in the same local class
435 class ModuleTableEltGroup
436 super ModuleTableElt
437 readable var _elements: Array[TableElt] = new Array[TableElt]
438 end
439
440 # An element that represents a class property
441 abstract class TableEltProp
442 super TableElt
443 readable var _property: MMLocalProperty
444
445 init(p: MMLocalProperty)
446 do
447 _property = p
448 end
449 end
450
451 # An element that represents a function pointer to a global method
452 class TableEltMeth
453 super TableEltProp
454 end
455
456 # An element that represents a function pointer to the super method of a local method
457 class TableEltSuper
458 super TableEltProp
459 end
460
461 # An element that represents the value stored for a global attribute
462 class TableEltAttr
463 super TableEltProp
464 end
465
466 # An element representing a class information
467 class AbsTableEltClass
468 super AbsTableElt
469 # The local class where the information comes from
470 readable var _local_class: MMLocalClass
471
472 init(c: MMLocalClass)
473 do
474 _local_class = c
475 end
476 end
477
478 # An element of a class table representing a class information
479 class TableEltClass
480 super TableElt
481 super AbsTableEltClass
482 redef fun is_related_to(c)
483 do
484 var bc = c.mmmodule[_local_class.global]
485 return c.cshe <= bc
486 end
487 end
488
489 # An element representing the id of a class in a module table
490 class TableEltClassId
491 super ModuleTableElt
492 super AbsTableEltClass
493 end
494
495 # An element representing the constructor marker position in a class table
496 class TableEltClassInitTable
497 super TableEltClass
498 end
499
500 # An element used for a cast
501 # Note: this element is both a TableElt and a ModuleTableElt.
502 # At the TableElt offset, there is the id of the super-class
503 # At the ModuleTableElt offset, there is the TableElt offset (ie. the color of the super-class).
504 class TableEltClassColor
505 super TableEltClass
506 super ModuleTableElt
507 end
508
509 # A Group of elements introduced in the same global-class that are colored together
510 class TableEltComposite
511 super TableElt
512 var _table: Array[TableElt]
513 var _cc: CompiledClass
514 var _offsets: HashMap[MMLocalClass, Int]
515 redef fun length do return _table.length
516 redef fun is_related_to(c) do return c.cshe <= _cc.local_class
517
518 fun add(c: MMLocalClass, tab: Array[TableElt])
519 do
520 _offsets[c] = _table.length
521 _table.append(tab)
522 end
523
524 redef fun item(i) do return _table[i]
525
526 init(cc: CompiledClass)
527 do
528 _cc = cc
529 _table = new Array[TableElt]
530 _offsets = new HashMap[MMLocalClass, Int]
531 end
532 end
533
534 # The element that represent the class id
535 class TableEltClassSelfId
536 super TableElt
537 redef fun is_related_to(c) do return true
538 end
539
540 # The element that represent the class name
541 class TableEltClassSelfName
542 super TableElt
543 redef fun is_related_to(c) do return true
544 end
545
546 # The element that represent the Object Size
547 class TableEltClassObjectSize
548 super TableElt
549 redef fun is_related_to(c) do return true
550 end
551
552 # The element that represent the object id
553 class TableEltObjectId
554 super TableElt
555 redef fun is_related_to(c) do return true
556 end
557
558 # The element that
559 class TableEltVftPointer
560 super TableElt
561 redef fun is_related_to(c) do return true
562 end