adcc42038755f37db41ebf7fbe78d53b8cfdd6de
[nit.git] / src / coloring.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Graph coloring tools
16 module coloring
17
18 import typing
19
20 abstract class AbstractColoring[E: Object]
21
22 private var core: Set[E] = new HashSet[E]
23 private var crown: Set[E] = new HashSet[E]
24 private var border: Set[E] = new HashSet[E]
25
26 private var coloration_result: Map[E, Int] = new HashMap[E, Int]
27
28 init do end
29
30 fun colorize(elements: Set[E]): Map[E, Int] do
31 tag_elements(elements)
32 build_conflicts_graph(elements)
33 colorize_elements(core)
34 colorize_elements(border)
35 colorize_elements(crown)
36 return coloration_result
37 end
38
39 # Colorize a collection of elements
40 private fun colorize_elements(elements: Set[E]) do
41 var min_color = 0
42
43 var lin = reverse_linearize(elements)
44 for element in lin do
45 var color = min_color
46 while not self.is_color_free(element, elements, color) do
47 color += 1
48 end
49 coloration_result[element] = color
50 color = min_color
51 end
52 end
53
54 # Check if a related element to the element already use the color
55 private fun is_color_free(element: E, elements: Set[E], color: Int): Bool do
56 if conflicts_graph.has_key(element) then
57 for st in conflicts_graph[element] do
58 if coloration_result.has_key(st) and coloration_result[st] == color then return false
59 end
60 end
61 for st in self.super_elements(element, elements) do
62 if coloration_result.has_key(st) and coloration_result[st] == color then return false
63 end
64 return true
65 end
66
67 # Tag elements as core, crown or border
68 private fun tag_elements(elements: Set[E]) do
69 for element in elements do
70 # Check if sub elements are all in single inheritance
71 var all_subelements_si = true
72 for subelem in self.sub_elements(element, elements) do
73 if self.is_element_mi(subelem, elements) then
74 all_subelements_si = false
75 break
76 end
77 end
78
79 # Tag as core, crown or border
80 if self.is_element_mi(element, elements) then
81 core.add_all(self.super_elements(element, elements))
82 core.add(element)
83 if all_subelements_si then
84 border.add(element)
85 end
86 else if not all_subelements_si then
87 core.add_all(self.super_elements(element, elements))
88 core.add(element)
89 else
90 crown.add(element)
91 end
92 end
93 end
94
95 # Conflicts graph of elements hierarchy (two types are in conflict if they have common subelements)
96 private fun build_conflicts_graph(elements: Set[E]) do
97 self.conflicts_graph = new HashMap[E, HashSet[E]]
98 var core = reverse_linearize(self.core)
99 for t in core do
100 for i in self.linear_extension(t, elements) do
101 if t == i then continue
102
103 var lin_i = self.linear_extension(i, elements)
104
105 for j in self.linear_extension(t, elements) do
106 if i == j or j == t then continue
107 var lin_j = self.linear_extension(j, elements)
108
109 var d_ij = lin_i - lin_j
110 var d_ji = lin_j - lin_i
111
112 for ed1 in d_ij do
113 if not conflicts_graph.has_key(ed1) then conflicts_graph[ed1] = new HashSet[E]
114 # add ed1 x ed2 to conflicts graph
115 for ed2 in d_ji do conflicts_graph[ed1].add(ed2)
116 end
117 for ed1 in d_ij do
118 if not conflicts_graph.has_key(ed1) then conflicts_graph[ed1] = new HashSet[E]
119 # add ed1 x ed2 to conflicts graph
120 for ed2 in d_ji do conflicts_graph[ed1].add(ed2)
121 end
122 end
123 end
124 end
125 end
126
127 private var conflicts_graph: nullable HashMap[E, Set[E]]
128
129 # cache for linear_extensions
130 private var linear_extensions_cache: Map[E, Array[E]] = new HashMap[E, Array[E]]
131
132 # Return a linear_extension of super_elements of the element
133 private fun linear_extension(element: E, elements: Set[E]): Array[E] do
134 if not self.linear_extensions_cache.has_key(element) then
135 var supers = new HashSet[E]
136 supers.add(element)
137 supers.add_all(self.super_elements(element, elements))
138 self.linear_extensions_cache[element] = self.linearize(supers)
139 end
140 return self.linear_extensions_cache[element]
141 end
142
143 private fun super_elements(element: E, elements: Set[E]): Set[E] is abstract
144 private fun sub_elements(element: E, elements: Set[E]): Set[E] is abstract
145 private fun is_element_mi(element: E, elements: Set[E]): Bool is abstract
146 private fun linearize(elements: Set[E]): Array[E] is abstract
147 private fun reverse_linearize(elements: Set[E]): Array[E] is abstract
148 end
149
150 # MClassType coloring
151 class TypeColoring
152 super AbstractColoring[MType]
153
154 type T: MType
155
156 private var mmodule: MModule
157
158 init(mainmodule: MModule) do self.mmodule = mainmodule
159
160 redef fun super_elements(element, elements) do return self.mmodule.super_mtypes(element, elements)
161 redef fun is_element_mi(element, elements) do return self.super_elements(element, elements).length > 1
162 redef fun sub_elements(element, elements) do do return self.mmodule.sub_mtypes(element, elements)
163 redef fun linearize(elements) do return self.mmodule.linearize_mtypes(elements)
164 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mtypes(elements)
165 end
166
167 class NaiveTypeColoring
168 super TypeColoring
169
170 init(mainmodule: MModule) do super
171
172 # naive coloring that use incremental coloring
173 redef fun colorize_elements(elements) do
174 for e in elements do
175 self.coloration_result[e] = self.coloration_result.length
176 end
177 end
178 end
179
180 abstract class TypePerfectHashing
181 super TypeColoring
182
183 init(mainmodule: MModule) do super
184
185 fun compute_masks(elements: Set[T], ids: Map[T, Int]): Map[T, Int] do
186 for e in elements do
187 # Create super type list
188 var supers = new HashSet[T]
189 supers.add_all(self.super_elements(e, elements))
190 supers.add(e)
191 # Compute the hashing 'mask'
192 self.coloration_result[e] = compute_mask(supers, ids)
193 end
194 return self.coloration_result
195 end
196
197 private fun compute_mask(mtypes: Set[T], ids: Map[T, Int]): Int do
198 var mask = 0
199 loop
200 var used = new List[Int]
201 for sup in mtypes do
202 var res = op(mask, ids[sup])
203 if used.has(res) then
204 break
205 else
206 used.add(res)
207 end
208 end
209 if used.length == mtypes.length then break
210 mask += 1
211 end
212 return mask
213 end
214
215 private fun op(mask: Int, id:Int): Int is abstract
216 private fun phash(id: Int, mask: Int): Int do return op(mask, id)
217 end
218
219 class TypeModPerfectHashing
220 super TypePerfectHashing
221 init(mainmodule: MModule) do super
222 redef fun op(mask, id) do return mask % id
223 end
224
225 class TypeAndPerfectHashing
226 super TypePerfectHashing
227 init(mainmodule: MModule) do super
228 redef fun op(mask, id) do return mask.bin_and(id)
229 end
230
231 # MClass coloring
232 class ClassColoring
233 super AbstractColoring[MClass]
234
235 type T: MClass
236
237 private var mmodule: MModule
238
239 # caches
240 private var super_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
241 private var parent_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
242 private var sub_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
243
244 init(mainmodule: MModule) do self.mmodule = mainmodule
245
246 # Build type tables
247 fun build_type_tables(mclasses: Set[T], colors: Map[T, Int]): Map[T, Array[nullable T]] do
248 var tables = new HashMap[T, Array[nullable T]]
249
250 for mclasse in mclasses do
251 var table = new Array[nullable T]
252 var supers = new HashSet[T]
253 supers.add_all(self.super_elements(mclasse, mclasses))
254 supers.add(mclasse)
255 for sup in supers do
256 var color = colors[sup]
257 if table.length <= color then
258 for i in [table.length .. color[ do
259 table[i] = null
260 end
261 end
262 table[color] = sup
263 end
264 tables[mclasse] = table
265 end
266 return tables
267 end
268
269 redef fun super_elements(element, elements) do return self.mmodule.super_mclasses(element)
270 fun parent_elements(element: MClass): Set[MClass] do return self.mmodule.parent_mclasses(element)
271 redef fun is_element_mi(element, elements) do return self.parent_elements(element).length > 1
272 redef fun sub_elements(element, elements) do do return self.mmodule.sub_mclasses(element)
273 redef fun linearize(elements) do return self.mmodule.linearize_mclasses(elements)
274 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mclasses(elements)
275 end
276
277 # incremental coloring (very naive)
278 class NaiveClassColoring
279 super ClassColoring
280
281 init(mainmodule: MModule) do
282 super(mainmodule)
283 end
284
285 # naive coloring that use incremental coloring
286 redef fun colorize_elements(elements) do
287 for e in elements do
288 self.coloration_result[e] = self.coloration_result.length
289 end
290 end
291 end
292
293 abstract class ClassPerfectHashing
294 super ClassColoring
295
296 init(mainmodule: MModule) do
297 super(mainmodule)
298 end
299
300 fun compute_masks(elements: Set[T], ids: Map[T, Int]): Map[T, Int] do
301 for e in elements do
302 # Create super type list
303 var supers = new HashSet[T]
304 supers.add_all(self.super_elements(e, elements))
305 supers.add(e)
306 # Compute the hashing 'mask'
307 self.coloration_result[e] = compute_mask(supers, ids)
308 end
309 return self.coloration_result
310 end
311
312 # Build type tables
313 fun hash_type_tables(mtypes: Set[T], ids: Map[T, Int], masks: Map[T, Int]): Map[T, Array[nullable T]] do
314 var tables = new HashMap[T, Array[nullable T]]
315
316 for mtype in mtypes do
317 var table = new Array[nullable T]
318 var supers = new HashSet[T]
319 supers.add_all(self.super_elements(mtype, mtypes))
320 supers.add(mtype)
321
322 for sup in supers do
323 var color = phash(ids[sup], masks[mtype])
324 if table.length <= color then
325 for i in [table.length .. color[ do
326 table[i] = null
327 end
328 end
329 table[color] = sup
330 end
331 tables[mtype] = table
332 end
333 return tables
334 end
335
336 private fun compute_mask(mtypes: Set[T], ids: Map[T, Int]): Int do
337 var mask = 0
338 loop
339 var used = new List[Int]
340 for sup in mtypes do
341 var res = op(mask, ids[sup])
342 if used.has(res) then
343 break
344 else
345 used.add(res)
346 end
347 end
348 if used.length == mtypes.length then break
349 mask += 1
350 end
351 return mask
352 end
353
354 private fun op(mask: Int, id:Int): Int is abstract
355 private fun phash(id: Int, mask: Int): Int do return op(mask, id)
356 end
357
358 class ClassModPerfectHashing
359 super ClassPerfectHashing
360 init(mainmodule: MModule) do
361 super(mainmodule)
362 end
363 redef fun op(mask, id) do return mask % id
364 end
365
366 class ClassAndPerfectHashing
367 super ClassPerfectHashing
368 init(mainmodule: MModule) do
369 super(mainmodule)
370 end
371 redef fun op(mask, id) do return mask.bin_and(id)
372 end
373
374 # MProperty coloring
375 class PropertyColoring
376
377 type MPROP: MProperty
378 type MPROPDEF: MPropDef
379
380 private var class_coloring: ClassColoring
381 private var coloration_result: Map[MPROP, Int] = new HashMap[MPROP, Int]
382
383 init(class_coloring: ClassColoring) do
384 self.class_coloring = class_coloring
385 end
386
387 fun colorize: Map[MPROP, Int] do
388 colorize_core_properties
389 colorize_crown_properties
390 return self.coloration_result
391 end
392
393 fun build_property_tables: Map[MClass, Array[nullable MPROPDEF]] do
394 var tables = new HashMap[MClass, Array[nullable MPROPDEF]]
395 var mclasses = self.class_coloring.coloration_result.keys
396 for mclass in mclasses do
397 var table = new Array[nullable MPROPDEF]
398 # first, fill table from parents by reverse linearization order
399 var parents = self.class_coloring.mmodule.super_mclasses(mclass)
400 var lin = self.class_coloring.reverse_linearize(parents)
401 for parent in lin do
402 for mproperty in self.properties(parent) do
403 var color = self.coloration_result[mproperty]
404 if table.length <= color then
405 for i in [table.length .. color[ do
406 table[i] = null
407 end
408 end
409 for mpropdef in mproperty.mpropdefs do
410 if mpropdef.mclassdef.mclass == parent then
411 table[color] = mpropdef
412 end
413 end
414 end
415 end
416
417 # then override with local properties
418 for mproperty in self.properties(mclass) do
419 var color = self.coloration_result[mproperty]
420 if table.length <= color then
421 for i in [table.length .. color[ do
422 table[i] = null
423 end
424 end
425 for mpropdef in mproperty.mpropdefs do
426 if mpropdef.mclassdef.mclass == mclass then
427 table[color] = mpropdef
428 end
429 end
430 end
431 tables[mclass] = table
432 end
433 return tables
434 end
435
436 # Colorize properties of the core hierarchy
437 private fun colorize_core_properties do
438 var mclasses = self.class_coloring.core
439 var min_color = 0
440
441 for mclass in mclasses do
442 var color = min_color
443
444 # if the class is root, get the minimal color
445 if self.class_coloring.parent_elements(mclass).length == 0 then
446 colorize_elements(self.properties(mclass), color)
447 else
448 # check last color used by parents
449 color = max_color(color, self.class_coloring.parent_elements(mclass))
450 # check max color used in conflicts
451 if self.class_coloring.conflicts_graph.has_key(mclass) then
452 color = max_color(color, self.class_coloring.conflicts_graph[mclass])
453 end
454
455 # colorize
456 colorize_elements(self.properties(mclass), color)
457 end
458 end
459 end
460
461 # Colorize properties of the crown hierarchy
462 private fun colorize_crown_properties do
463 for mclass in self.class_coloring.crown do
464 colorize_elements(self.properties(mclass), max_color(0, self.class_coloring.parent_elements(mclass)))
465 end
466 end
467
468 # Colorize a collection of properties given a starting color
469 private fun colorize_elements(elements: Collection[MPROP], start_color: Int) do
470 for element in elements do
471 if self.coloration_result.has_key(element) then continue
472 self.coloration_result[element] = start_color
473 start_color += 1
474 end
475 end
476
477 private fun max_color(min_color: Int, mclasses: Collection[MClass]): Int do
478 var max_color = min_color
479
480 for mclass in mclasses do
481 for mproperty in self.properties(mclass) do
482 var color = min_color
483 if self.coloration_result.has_key(mproperty) then
484 color = self.coloration_result[mproperty]
485 if color >= max_color then max_color = color + 1
486 end
487 end
488 end
489 return max_color
490 end
491
492 # properties cache
493 private var properties_cache: Map[MClass, Set[MPROP]] = new HashMap[MClass, Set[MPROP]]
494
495 # All 'mproperties' associated to all 'mclassdefs' of the class
496 private fun properties(mclass: MClass): Set[MPROP] do
497 if not self.properties_cache.has_key(mclass) then
498 var properties = new HashSet[MPROP]
499 var parents = self.class_coloring.mmodule.super_mclasses(mclass)
500 for parent in parents do
501 properties.add_all(self.properties(parent))
502 end
503
504 for mclassdef in mclass.mclassdefs do
505 for mpropdef in mclassdef.mpropdefs do
506 var mproperty = mpropdef.mproperty
507 if mproperty isa MPROP then
508 properties.add(mproperty)
509 end
510 end
511 end
512 self.properties_cache[mclass] = properties
513 end
514 return properties_cache[mclass]
515 end
516 end
517
518 # MMethod coloring
519 class MethodColoring
520 super PropertyColoring
521
522 redef type MPROP: MMethod
523 redef type MPROPDEF: MMethodDef
524 init(class_coloring: ClassColoring) do end
525 end
526
527 # MAttribute coloring
528 class AttributeColoring
529 super PropertyColoring
530
531 redef type MPROP: MAttribute
532 redef type MPROPDEF: MAttributeDef
533 init(class_coloring: ClassColoring) do end
534 end
535
536 # MVirtualTypeProp coloring
537 class VTColoring
538 super PropertyColoring
539
540 redef type MPROP: MVirtualTypeProp
541 redef type MPROPDEF: MVirtualTypeDef
542 init(class_coloring: ClassColoring) do end
543 end
544
545 class NaiveVTColoring
546 super VTColoring
547
548 init(class_coloring: ClassColoring) do end
549
550 redef fun colorize: Map[MPROP, Int] do
551 var mclasses = new HashSet[MClass]
552 mclasses.add_all(self.class_coloring.core)
553 mclasses.add_all(self.class_coloring.crown)
554 var min_color = 0
555
556 for mclass in mclasses do
557 min_color = max_color(min_color, mclasses)
558 colorize_elements(self.properties(mclass), min_color)
559 end
560 return self.coloration_result
561 end
562 end
563
564 abstract class VTPerfectHashing
565 super VTColoring
566
567 private var masks: Map[MClass, Int] = new HashMap[MClass, Int]
568
569 init(class_coloring: ClassColoring) do end
570
571 redef fun colorize: Map[MPROP, Int] do
572 var mclasses = new HashSet[MClass]
573 mclasses.add_all(self.class_coloring.core)
574 mclasses.add_all(self.class_coloring.crown)
575 for mclass in mclasses do
576 var vts = self.properties(mclass)
577 for vt in vts do
578 if coloration_result.has_key(vt) then continue
579 coloration_result[vt] = coloration_result.length + 1
580 end
581 end
582 return self.coloration_result
583 end
584
585 fun compute_masks: Map[MClass, Int] do
586 var mclasses = new HashSet[MClass]
587 mclasses.add_all(self.class_coloring.core)
588 mclasses.add_all(self.class_coloring.crown)
589 for mclass in mclasses do
590 self.masks[mclass] = compute_mask(self.properties(mclass))
591 end
592 return self.masks
593 end
594
595 private fun compute_mask(vts: Set[MPROP]): Int do
596 var mask = 0
597 loop
598 var used = new List[Int]
599 for vt in vts do
600 var res = op(mask, self.coloration_result[vt])
601 if used.has(res) then
602 break
603 else
604 used.add(res)
605 end
606 end
607 if used.length == vts.length then break
608 mask += 1
609 end
610 return mask
611 end
612
613 redef fun build_property_tables do
614 var tables = new HashMap[MClass, Array[nullable MPROPDEF]]
615
616 for mclass in self.class_coloring.coloration_result.keys do
617 var table = new Array[nullable MPROPDEF]
618 # first, fill table from parents by reverse linearization order
619 var parents = self.class_coloring.mmodule.super_mclasses(mclass)
620 var lin = self.class_coloring.reverse_linearize(parents)
621 for parent in lin do
622 for mproperty in self.properties(parent) do
623 var color = phash(self.coloration_result[mproperty], masks[mclass])
624 if table.length <= color then
625 for i in [table.length .. color[ do
626 table[i] = null
627 end
628 end
629 for mpropdef in mproperty.mpropdefs do
630 if mpropdef.mclassdef.mclass == parent then
631 table[color] = mpropdef
632 end
633 end
634 end
635 end
636
637 # then override with local properties
638 for mproperty in self.properties(mclass) do
639 var color = phash(self.coloration_result[mproperty], masks[mclass])
640 if table.length <= color then
641 for i in [table.length .. color[ do
642 table[i] = null
643 end
644 end
645 for mpropdef in mproperty.mpropdefs do
646 if mpropdef.mclassdef.mclass == mclass then
647 table[color] = mpropdef
648 end
649 end
650 end
651 tables[mclass] = table
652 end
653 return tables
654 end
655
656 private fun op(mask: Int, id:Int): Int is abstract
657 private fun phash(id: Int, mask: Int): Int do return op(mask, id)
658
659 end
660
661 class VTModPerfectHashing
662 super VTPerfectHashing
663 init(class_coloring: ClassColoring) do end
664 redef fun op(mask, id) do return mask % id
665 end
666
667 class VTAndPerfectHashing
668 super VTPerfectHashing
669 init(class_coloring: ClassColoring) do end
670 redef fun op(mask, id) do return mask.bin_and(id)
671 end
672
673 # MParameterType coloring
674 class FTColoring
675 private var class_coloring: ClassColoring
676 private var coloration_result: Map[MParameterType, Int] = new HashMap[MParameterType, Int]
677
678 init(class_coloring: ClassColoring) do
679 self.class_coloring = class_coloring
680 end
681
682 fun colorize: Map[MParameterType, Int] do
683 colorize_core_properties
684 colorize_crown_properties
685 return self.coloration_result
686 end
687
688 # Colorize properties of the core hierarchy
689 private fun colorize_core_properties do
690 var mclasses = self.class_coloring.core
691 var min_color = 0
692
693 for mclass in mclasses do
694 var color = min_color
695
696 # if the class is root, get the minimal color
697 if self.class_coloring.parent_elements(mclass).length == 0 then
698 colorize_elements(self.fts(mclass), color)
699 else
700 # check last color used by parents
701 color = max_color(color, self.class_coloring.parent_elements(mclass))
702 # check max color used in conflicts
703 if self.class_coloring.conflicts_graph.has_key(mclass) then
704 color = max_color(color, self.class_coloring.conflicts_graph[mclass])
705 end
706 # colorize
707 colorize_elements(self.fts(mclass), color)
708 end
709 end
710 end
711
712 # Colorize properties of the crown hierarchy
713 private fun colorize_crown_properties do
714 for mclass in self.class_coloring.crown do
715 colorize_elements(self.fts(mclass), max_color(0, self.class_coloring.parent_elements(mclass)))
716 end
717 end
718
719 # Colorize a collection of properties given a starting color
720 private fun colorize_elements(elements: Collection[MParameterType], start_color: Int) do
721 for element in elements do
722 if self.coloration_result.has_key(element) then continue
723 self.coloration_result[element] = start_color
724 start_color += 1
725 end
726 end
727
728 private fun max_color(min_color: Int, mclasses: Collection[MClass]): Int do
729 var max_color = min_color
730
731 for mclass in mclasses do
732 for ft in self.fts(mclass) do
733 var color = min_color
734 if self.coloration_result.has_key(ft) then
735 color = self.coloration_result[ft]
736 if color >= max_color then max_color = color + 1
737 end
738 end
739 end
740 return max_color
741 end
742
743 # fts cache
744 private var fts_cache: Map[MClass, Set[MParameterType]] = new HashMap[MClass, Set[MParameterType]]
745
746 private fun fts(mclass: MClass): Set[MParameterType] do
747 if not self.fts_cache.has_key(mclass) then
748 var fts = new HashSet[MParameterType]
749 var mclass_type = mclass.mclass_type
750 if mclass_type isa MGenericType then
751 for ft in mclass_type.arguments do
752 fts.add(ft.as(MParameterType))
753 end
754 end
755 self.fts_cache[mclass] = fts
756 end
757 return fts_cache[mclass]
758 end
759
760 fun build_ft_tables: Map[MClass, Array[nullable MParameterType]] do
761 var tables = new HashMap[MClass, Array[nullable MParameterType]]
762
763 for mclass in self.class_coloring.coloration_result.keys do
764 var table = new Array[nullable MParameterType]
765
766 # first, fill table from parents
767 var parents = self.class_coloring.mmodule.super_mclasses(mclass)
768 for parent in parents do
769 for ft in self.fts(parent) do
770 var color = self.coloration_result[ft]
771 if table.length <= color then
772 for i in [table.length .. color[ do
773 table[i] = null
774 end
775 end
776 table[color] = ft
777 end
778 end
779
780 # then override with local properties
781 for ft in self.fts(mclass) do
782 var color = self.coloration_result[ft]
783 if table.length <= color then
784 for i in [table.length .. color[ do
785 table[i] = null
786 end
787 end
788 table[color] = ft
789 end
790 tables[mclass] = table
791 end
792 return tables
793 end
794 end
795
796 class NaiveFTColoring
797 super FTColoring
798
799 init(class_coloring: ClassColoring) do end
800
801 redef fun colorize: Map[MParameterType, Int] do
802 var mclasses = new HashSet[MClass]
803 mclasses.add_all(self.class_coloring.core)
804 mclasses.add_all(self.class_coloring.crown)
805 var min_color = 0
806
807 for mclass in mclasses do
808 min_color = max_color(min_color, mclasses)
809 colorize_elements(self.fts(mclass), min_color)
810 end
811 return self.coloration_result
812 end
813 end
814
815 abstract class FTPerfectHashing
816 super FTColoring
817
818 private var masks: Map[MClass, Int] = new HashMap[MClass, Int]
819
820 init(class_coloring: ClassColoring) do end
821
822 redef fun colorize: Map[MParameterType, Int] do
823 var mclasses = new HashSet[MClass]
824 mclasses.add_all(self.class_coloring.core)
825 mclasses.add_all(self.class_coloring.crown)
826 for mclass in mclasses do
827 for ft in self.fts(mclass) do
828 if coloration_result.has_key(ft) then continue
829 coloration_result[ft] = coloration_result.length + 1
830 end
831 end
832 return self.coloration_result
833 end
834
835 fun compute_masks: Map[MClass, Int] do
836 var mclasses = new HashSet[MClass]
837 mclasses.add_all(self.class_coloring.core)
838 mclasses.add_all(self.class_coloring.crown)
839 for mclass in mclasses do
840 var fts = new HashSet[MParameterType]
841 var parents = self.class_coloring.mmodule.super_mclasses(mclass)
842 for parent in parents do
843 fts.add_all(self.fts(parent))
844 end
845 fts.add_all(self.fts(mclass))
846 self.masks[mclass] = compute_mask(fts)
847 end
848 return self.masks
849 end
850
851 private fun compute_mask(fts: Set[MParameterType]): Int do
852 var mask = 0
853 loop
854 var used = new List[Int]
855 for ft in fts do
856 var res = op(mask, self.coloration_result[ft])
857 if used.has(res) then
858 break
859 else
860 used.add(res)
861 end
862 end
863 if used.length == fts.length then break
864 mask += 1
865 end
866 return mask
867 end
868
869 redef fun build_ft_tables do
870 var tables = new HashMap[MClass, Array[nullable MParameterType]]
871
872 for mclass in self.class_coloring.coloration_result.keys do
873 var table = new Array[nullable MParameterType]
874
875 # first, fill table from parents
876 var parents = self.class_coloring.mmodule.super_mclasses(mclass)
877 for parent in parents do
878 for ft in self.fts(parent) do
879 var color = phash(self.coloration_result[ft], masks[mclass])
880 if table.length <= color then
881 for i in [table.length .. color[ do
882 table[i] = null
883 end
884 end
885 table[color] = ft
886 end
887 end
888
889 # then override with local properties
890 for ft in self.fts(mclass) do
891 var color = phash(self.coloration_result[ft], masks[mclass])
892 if table.length <= color then
893 for i in [table.length .. color[ do
894 table[i] = null
895 end
896 end
897 table[color] = ft
898 end
899 tables[mclass] = table
900 end
901 return tables
902 end
903
904 private fun op(mask: Int, id:Int): Int is abstract
905 private fun phash(id: Int, mask: Int): Int do return op(mask, id)
906 end
907
908 class FTModPerfectHashing
909 super FTPerfectHashing
910 init(class_coloring: ClassColoring) do end
911 redef fun op(mask, id) do return mask % id
912 end
913
914 class FTAndPerfectHashing
915 super FTPerfectHashing
916 init(class_coloring: ClassColoring) do end
917 redef fun op(mask, id) do return mask.bin_and(id)
918 end
919
920 # Live Entries coloring
921 class LiveEntryColoring
922
923 private var coloration_result: Map[MType, Int] = new HashMap[MType, Int]
924 private var conflicts_graph_cache: nullable HashMap[MType, Set[MType]]
925 var livetypes_tables_sizes: nullable Map[MClass, Array[Int]]
926
927 init do end
928
929 fun colorize(elements: Collection[MType]): Map[MType, Int] do
930 # compute conflicts
931 build_conflicts_graph(elements)
932
933 # colorize graph
934 colorize_elements(elements)
935
936 return coloration_result
937 end
938
939 # Build type tables
940 fun build_livetype_tables(mtypes: Set[MType]): Map[MClass, Array[nullable Object]] do
941 var livetypes_tables = new HashMap[MClass, Array[nullable Object]]
942 self.livetypes_tables_sizes = new HashMap[MClass, Array[Int]]
943
944 for mtype in mtypes do
945 if mtype isa MGenericType then
946 var table: Array[nullable Object]
947 var sizes: Array[Int]
948 if livetypes_tables.has_key(mtype.mclass) then
949 table = livetypes_tables[mtype.mclass]
950 else
951 table = new Array[nullable Object]
952 livetypes_tables[mtype.mclass] = table
953 end
954 if livetypes_tables_sizes.has_key(mtype.mclass) then
955 sizes = livetypes_tables_sizes[mtype.mclass]
956 else
957 sizes = new Array[Int]
958 livetypes_tables_sizes[mtype.mclass] = sizes
959 end
960 build_livetype_table(mtype, 0, table, sizes)
961 end
962 end
963
964 return livetypes_tables
965 end
966
967 # Build live gentype table recursively
968 private fun build_livetype_table(mtype: MGenericType, current_rank: Int, table: Array[nullable Object], sizes: Array[Int]) do
969 var ft = mtype.arguments[current_rank]
970 if not self.coloration_result.has_key(ft) then return
971 var color = self.coloration_result[ft]
972
973 if current_rank >= sizes.length then
974 sizes[current_rank] = color + 1
975 else if color >= sizes[current_rank] then
976 sizes[current_rank] = color + 1
977 end
978
979 if color > table.length then
980 for i in [table.length .. color[ do table[i] = null
981 end
982
983 if current_rank == mtype.arguments.length - 1 then
984 table[color] = mtype
985 else
986 var ft_table: Array[nullable Object]
987 if color < table.length and table[color] != null then
988 ft_table = table[color].as(Array[nullable Object])
989 else
990 ft_table = new Array[nullable Object]
991 end
992 table[color] = ft_table
993 build_livetype_table(mtype, current_rank + 1, ft_table, sizes)
994 end
995 end
996
997 # Colorize a collection of elements
998 fun colorize_elements(elements: Collection[MType]) do
999 var min_color = 0
1000
1001 for element in elements do
1002 var color = min_color
1003 while not self.is_color_free(element, color) do
1004 color += 1
1005 end
1006 coloration_result[element] = color
1007 color = min_color
1008 end
1009 end
1010
1011 # Check if a related element to the element already use the color
1012 private fun is_color_free(element: MType, color: Int): Bool do
1013 if conflicts_graph.has_key(element) then
1014 for st in conflicts_graph[element] do
1015 if coloration_result.has_key(st) and coloration_result[st] == color then return false
1016 end
1017 end
1018 return true
1019 end
1020
1021 # look for types in the same generic signatures
1022 private fun build_conflicts_graph(elements: Collection[MType]) do
1023 # regroup types by classes
1024 var genclasses = new HashMap[MClass, Set[MType]]
1025 for e in elements do
1026 if e isa MGenericType then
1027 if not genclasses.has_key(e.mclass) then
1028 genclasses[e.mclass] = new HashSet[MType]
1029 end
1030 genclasses[e.mclass].add(e)
1031 end
1032 end
1033
1034 # for each class
1035 self.conflicts_graph_cache = new HashMap[MType, Set[MType]]
1036 for mclass, mtypes in genclasses do
1037 # for each rank
1038 for rank in [0..mclass.arity[ do
1039 # for each live type
1040 for mtype in mtypes do
1041 var mclasstype: MClassType
1042 if mtype isa MNullableType then
1043 mclasstype = mtype.mtype.as(MClassType)
1044 else
1045 mclasstype = mtype.as(MClassType)
1046 end
1047 var ft = mclasstype.arguments[rank]
1048 for otype in mtypes do
1049 if mtype == otype then continue
1050 var oclasstype: MClassType
1051 if otype isa MNullableType then
1052 oclasstype = otype.mtype.as(MClassType)
1053 else
1054 oclasstype = otype.as(MClassType)
1055 end
1056 var oft = oclasstype.arguments[rank]
1057 self.add_conflict(ft, oft)
1058 end
1059 end
1060 end
1061 end
1062 end
1063
1064 private fun add_conflict(mtype: MType, otype: MType) do
1065 if mtype == otype then return
1066 if not self.conflicts_graph_cache.has_key(mtype) then self.conflicts_graph_cache[mtype] = new HashSet[MType]
1067 self.conflicts_graph_cache[mtype].add(otype)
1068 if not self.conflicts_graph_cache.has_key(otype) then self.conflicts_graph_cache[otype] = new HashSet[MType]
1069 self.conflicts_graph_cache[otype].add(mtype)
1070 end
1071 private fun conflicts_graph: Map[MType, Set[MType]] do return conflicts_graph_cache.as(not null)
1072 end
1073
1074 class NaiveLiveEntryColoring
1075 super LiveEntryColoring
1076
1077 init do end
1078
1079 redef fun colorize_elements(elements: Collection[MType]) do
1080 var color = 0
1081 for element in elements do
1082 coloration_result[element] = color
1083 color += 1
1084 end
1085 end
1086 end
1087
1088 # live unanchored coloring
1089 class UnanchoredTypeColoring
1090
1091 private var coloration_result: Map[MType, Int] = new HashMap[MType, Int]
1092 private var conflicts_graph: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]]
1093
1094 init do end
1095
1096 fun colorize(elements: Map[MClassType, Set[MType]]): Map[MType, Int] do
1097 build_conflicts_graph(elements)
1098 colorize_elements(elements)
1099 return coloration_result
1100 end
1101
1102 fun build_tables(elements: Map[MClassType, Set[MType]]): Map[MClassType, Array[nullable MType]] do
1103 var tables = new HashMap[MClassType, Array[nullable MType]]
1104
1105 for mclasstype, mtypes in elements do
1106 var table = new Array[nullable MType]
1107 for mtype in mtypes do
1108 var color = self.coloration_result[mtype]
1109 if table.length <= color then
1110 for i in [table.length .. color[ do
1111 table[i] = null
1112 end
1113 end
1114 table[color] = mtype
1115 end
1116 tables[mclasstype] = table
1117 end
1118 return tables
1119 end
1120
1121 # Colorize a collection of elements
1122 fun colorize_elements(elements: Map[MClassType, Set[MType]]) do
1123 var min_color = 0
1124 for mclasstype, mclasstypes in elements do
1125 for element in mclasstypes do
1126 if self.coloration_result.has_key(element) then continue
1127 var color = min_color
1128 while not self.is_color_free(element, color) do
1129 color += 1
1130 end
1131 coloration_result[element] = color
1132 color = min_color
1133 end
1134 end
1135 end
1136
1137 # Check if a related element to the element already use the color
1138 private fun is_color_free(element: MType, color: Int): Bool do
1139 if conflicts_graph.has_key(element) then
1140 for st in conflicts_graph[element] do
1141 if coloration_result.has_key(st) and coloration_result[st] == color then return false
1142 end
1143 end
1144 return true
1145 end
1146
1147 # look for unanchored types generated by the same type
1148 private fun build_conflicts_graph(elements: Map[MClassType, Set[MType]]) do
1149 for mclasstype, mtypes in elements do
1150 for mtype in mtypes do
1151 for otype in mtypes do
1152 if otype == mtype then continue
1153 self.add_conflict(mtype, otype)
1154 end
1155 end
1156 end
1157 end
1158
1159 private fun add_conflict(mtype: MType, otype: MType) do
1160 if mtype == otype then return
1161 if not self.conflicts_graph.has_key(mtype) then self.conflicts_graph[mtype] = new HashSet[MType]
1162 self.conflicts_graph[mtype].add(otype)
1163 if not self.conflicts_graph.has_key(otype) then self.conflicts_graph[otype] = new HashSet[MType]
1164 self.conflicts_graph[otype].add(mtype)
1165 end
1166 end
1167
1168 class NaiveUnanchoredTypeColoring
1169 super UnanchoredTypeColoring
1170
1171 init do end
1172
1173 redef fun colorize_elements(elements: Map[MClassType, Set[MType]]) do
1174 var color = 0
1175 for mclasstype, mclasstypes in elements do
1176 for element in mclasstypes do
1177 coloration_result[element] = color
1178 color += 1
1179 end
1180 end
1181 end
1182 end
1183
1184 abstract class UnanchoredTypePerfectHashing
1185 super NaiveUnanchoredTypeColoring
1186
1187 private var masks: Map[MClassType, Int] = new HashMap[MClassType, Int]
1188
1189 init do end
1190
1191 redef fun colorize_elements(elements: Map[MClassType, Set[MType]]) do
1192 var color = 1
1193 for mclasstype, mclasstypes in elements do
1194 for element in mclasstypes do
1195 coloration_result[element] = color
1196 color += 1
1197 end
1198 end
1199 end
1200
1201 fun compute_masks(elements: Map[MClassType, Set[MType]]): Map[MClassType, Int] do
1202 for mclasstype, mtypes in elements do
1203 self.masks[mclasstype] = compute_mask(mtypes)
1204 end
1205 return self.masks
1206 end
1207
1208 private fun compute_mask(mtypes: Set[MType]): Int do
1209 var mask = 0
1210 loop
1211 var used = new List[Int]
1212 for mtype in mtypes do
1213 var res = op(mask, self.coloration_result[mtype])
1214 if used.has(res) then
1215 break
1216 else
1217 used.add(res)
1218 end
1219 end
1220 if used.length == mtypes.length then break
1221 mask += 1
1222 end
1223 return mask
1224 end
1225
1226 redef fun build_tables(elements: Map[MClassType, Set[MType]]): Map[MClassType, Array[nullable MType]] do
1227 var tables = new HashMap[MClassType, Array[nullable MType]]
1228
1229 for mclasstype, mtypes in elements do
1230 var table = new Array[nullable MType]
1231 for mtype in mtypes do
1232 var color = phash(self.coloration_result[mtype], masks[mclasstype])
1233 if table.length <= color then
1234 for i in [table.length .. color[ do
1235 table[i] = null
1236 end
1237 end
1238 table[color] = mtype
1239 end
1240 tables[mclasstype] = table
1241 end
1242 return tables
1243 end
1244
1245 private fun op(mask: Int, id:Int): Int is abstract
1246 private fun phash(id: Int, mask: Int): Int do return op(mask, id)
1247 end
1248
1249 class UnanchoredTypeModPerfectHashing
1250 super UnanchoredTypePerfectHashing
1251 init do end
1252 redef fun op(mask, id) do return mask % id
1253 end
1254
1255 class UnanchoredTypeAndPerfectHashing
1256 super UnanchoredTypePerfectHashing
1257 init do end
1258 redef fun op(mask, id) do return mask.bin_and(id)
1259 end
1260
1261
1262 # Utils
1263
1264 redef class HashSet[E]
1265 init from(elements: Collection[E]) do
1266 init
1267 self.add_all(elements)
1268 end
1269 end
1270
1271 redef class Array[E]
1272 init from(elements: Collection[E]) do
1273 init
1274 self.add_all(elements)
1275 end
1276
1277 # Return a new Array with the elements only contened in 'self' and not in 'o'
1278 fun -(o: Array[E]): Array[E] do
1279 var res = new Array[E]
1280 for e in self do if not o.has(e) then res.add(e)
1281 return res
1282 end
1283 end
1284
1285 redef class MModule
1286
1287 # Return a linearization of a set of mtypes
1288 private fun linearize_mtypes(mtypes: Set[MType]): Array[MType] do
1289 var lin = new Array[MType].from(mtypes)
1290 var sorter = new TypeSorter(self)
1291 sorter.sort(lin)
1292 return lin
1293 end
1294
1295 # Return a reverse linearization of a set of mtypes
1296 private fun reverse_linearize_mtypes(mtypes: Set[MType]): Array[MType] do
1297 var lin = new Array[MType].from(mtypes)
1298 var sorter = new ReverseTypeSorter(self)
1299 sorter.sort(lin)
1300 return lin
1301 end
1302
1303 # Return super types of a `mtype` in `self`
1304 private fun super_mtypes(mtype: MType, mtypes: Set[MType]): Set[MType] do
1305 if not self.super_mtypes_cache.has_key(mtype) then
1306 var supers = new HashSet[MType]
1307 for otype in mtypes do
1308 if otype == mtype then continue
1309 if mtype.is_subtype(self, null, otype) then
1310 supers.add(otype)
1311 end
1312 end
1313 self.super_mtypes_cache[mtype] = supers
1314 end
1315 return self.super_mtypes_cache[mtype]
1316 end
1317
1318 private var super_mtypes_cache: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]]
1319
1320 # Return all sub mtypes (directs and indirects) of a `mtype` in `self`
1321 private fun sub_mtypes(mtype: MType, mtypes: Set[MType]): Set[MType] do
1322 if not self.sub_mtypes_cache.has_key(mtype) then
1323 var subs = new HashSet[MType]
1324 for otype in mtypes do
1325 if otype == mtype then continue
1326 if otype.is_subtype(self, null, mtype) then
1327 subs.add(otype)
1328 end
1329 end
1330 self.sub_mtypes_cache[mtype] = subs
1331 end
1332 return self.sub_mtypes_cache[mtype]
1333 end
1334
1335 private var sub_mtypes_cache: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]]
1336
1337 # Return a linearization of a set of mclasses
1338 private fun linearize_mclasses(mclasses: Set[MClass]): Array[MClass] do
1339 var lin = new Array[MClass].from(mclasses)
1340 var sorter = new ClassSorter(self)
1341 sorter.sort(lin)
1342 return lin
1343 end
1344
1345 # Return a reverse linearization of a set of mtypes
1346 private fun reverse_linearize_mclasses(mclasses: Set[MClass]): Array[MClass] do
1347 var lin = new Array[MClass].from(mclasses)
1348 var sorter = new ReverseClassSorter(self)
1349 sorter.sort(lin)
1350 return lin
1351 end
1352
1353 # Return all super mclasses (directs and indirects) of a `mclass` in `self`
1354 private fun super_mclasses(mclass: MClass): Set[MClass] do
1355 if not self.super_mclasses_cache.has_key(mclass) then
1356 var supers = new HashSet[MClass]
1357 if self.flatten_mclass_hierarchy.has(mclass) then
1358 for sup in self.flatten_mclass_hierarchy[mclass].greaters do
1359 if sup == mclass then continue
1360 supers.add(sup)
1361 end
1362 end
1363 self.super_mclasses_cache[mclass] = supers
1364 end
1365 return self.super_mclasses_cache[mclass]
1366 end
1367
1368 private var super_mclasses_cache: Map[MClass, Set[MClass]] = new HashMap[MClass, Set[MClass]]
1369
1370 # Return all parents of a `mclass` in `self`
1371 private fun parent_mclasses(mclass: MClass): Set[MClass] do
1372 if not self.parent_mclasses_cache.has_key(mclass) then
1373 var parents = new HashSet[MClass]
1374 if self.flatten_mclass_hierarchy.has(mclass) then
1375 for sup in self.flatten_mclass_hierarchy[mclass].direct_greaters do
1376 if sup == mclass then continue
1377 parents.add(sup)
1378 end
1379 end
1380 self.parent_mclasses_cache[mclass] = parents
1381 end
1382 return self.parent_mclasses_cache[mclass]
1383 end
1384
1385 private var parent_mclasses_cache: Map[MClass, Set[MClass]] = new HashMap[MClass, Set[MClass]]
1386
1387 # Return all sub mclasses (directs and indirects) of a `mclass` in `self`
1388 private fun sub_mclasses(mclass: MClass): Set[MClass] do
1389 if not self.sub_mclasses_cache.has_key(mclass) then
1390 var subs = new HashSet[MClass]
1391 if self.flatten_mclass_hierarchy.has(mclass) then
1392 for sub in self.flatten_mclass_hierarchy[mclass].smallers do
1393 if sub == mclass then continue
1394 subs.add(sub)
1395 end
1396 end
1397 self.sub_mclasses_cache[mclass] = subs
1398 end
1399 return self.sub_mclasses_cache[mclass]
1400 end
1401
1402 private var sub_mclasses_cache: Map[MClass, Set[MClass]] = new HashMap[MClass, Set[MClass]]
1403
1404 # All 'mproperties' associated to all 'mclassdefs' of `mclass`
1405 private fun properties(mclass: MClass): Set[MProperty] do
1406 if not self.properties_cache.has_key(mclass) then
1407 var properties = new HashSet[MProperty]
1408 var parents = self.super_mclasses(mclass)
1409 for parent in parents do
1410 properties.add_all(self.properties(parent))
1411 end
1412
1413 for mclassdef in mclass.mclassdefs do
1414 for mpropdef in mclassdef.mpropdefs do
1415 properties.add(mpropdef.mproperty)
1416 end
1417 end
1418 self.properties_cache[mclass] = properties
1419 end
1420 return properties_cache[mclass]
1421 end
1422
1423 private var properties_cache: Map[MClass, Set[MProperty]] = new HashMap[MClass, Set[MProperty]]
1424 end
1425
1426 # A sorter for linearize list of types
1427 class TypeSorter
1428 super AbstractSorter[MType]
1429
1430 private var mmodule: MModule
1431
1432 init(mmodule: MModule) do self.mmodule = mmodule
1433
1434 redef fun compare(a, b) do
1435 if a == b then
1436 return 0
1437 else if a.is_subtype(self.mmodule, null, b) then
1438 return -1
1439 end
1440 return 1
1441 end
1442 end
1443
1444 # A sorter for reverse linearization
1445 class ReverseTypeSorter
1446 super TypeSorter
1447
1448 init(mmodule: MModule) do end
1449
1450 redef fun compare(a, b) do
1451 if a == b then
1452 return 0
1453 else if a.is_subtype(self.mmodule, null, b) then
1454 return 1
1455 end
1456 return -1
1457 end
1458 end
1459
1460 # A sorter for linearize list of classes
1461 private class ClassSorter
1462 super AbstractSorter[MClass]
1463
1464 var mmodule: MModule
1465
1466 redef fun compare(a, b) do
1467 if a == b then
1468 return 0
1469 else if self.mmodule.flatten_mclass_hierarchy.has(a) and self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
1470 return -1
1471 end
1472 return 1
1473 end
1474 end
1475
1476 # A sorter for reverse linearization
1477 private class ReverseClassSorter
1478 super AbstractSorter[MClass]
1479
1480 var mmodule: MModule
1481
1482 redef fun compare(a, b) do
1483 if a == b then
1484 return 0
1485 else if self.mmodule.flatten_mclass_hierarchy.has(a) and self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
1486 return 1
1487 end
1488 return -1
1489 end
1490 end