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