8a323eb2fb86b497ccec8541390c1a97fb559d80
[nit.git] / src / layout_builders.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 # Table layout builders
16 module layout_builders
17
18 import abstract_compiler
19
20 # Layouts
21
22 class Layout[E: Object]
23 # Ids or each element
24 var ids: Map[E, Int] = new HashMap[E, Int]
25 # Fixed positions of each element in all tables
26 var pos: Map[E, Int] = new HashMap[E, Int]
27 end
28
29 class PHLayout[HOLDER: Object, E: Object]
30 super Layout[E]
31 # Masks used by hash function
32 var masks: Map[HOLDER, Int] = new HashMap[HOLDER, Int]
33 # Positions of each element for each tables
34 var hashes: Map[HOLDER, Map[E, Int]] = new HashMap[HOLDER, Map[E, Int]]
35 end
36
37 class PropertyLayout[E: Object]
38 # Fixed positions of each element in all tables
39 var pos: Map[E, Int] = new HashMap[E, Int]
40 end
41
42 # Builders
43
44 interface TypingLayoutBuilder[E: Object]
45 # Build typing table layout
46 fun build_layout(elements: Set[E]): Layout[E] is abstract
47 end
48
49 interface PropertyLayoutBuilder[E: MProperty]
50 # Build table layout for attributes, methods and virtual types
51 fun build_layout(elements: Set[MClass]): Layout[E] is abstract
52 end
53
54 interface ResolutionLayoutBuilder
55 # Build resolution table layout
56 fun build_layout(elements: Map[MClassType, Set[MType]]): Layout[MType] is abstract
57 end
58
59 # Matrice computers
60
61 abstract class TypingBMizer[E: Object]
62 super TypingLayoutBuilder[E]
63
64 var mmodule: MModule
65
66 init(mmodule: MModule) do
67 self.mmodule = mmodule
68 end
69
70 # Compute mtypes ids and position using BM
71 redef fun build_layout(elements: Set[E]): Layout[E] do
72 var result = new Layout[E]
73 var ids = new HashMap[E, Int]
74 var lin = self.reverse_linearize(elements)
75 for element in lin do
76 ids[element] = ids.length
77 end
78 result.ids = ids
79 result.pos = ids
80 return result
81 end
82
83 private fun reverse_linearize(elements: Set[E]): Array[E] is abstract
84 end
85
86 class MTypeBMizer
87 super TypingBMizer[MType]
88
89 init(mmodule: MModule) do super(mmodule)
90
91 redef fun reverse_linearize(elements) do
92 return self.mmodule.reverse_linearize_mtypes(elements)
93 end
94 end
95
96 class MClassBMizer
97 super TypingBMizer[MClass]
98
99 init(mmodule: MModule) do super(mmodule)
100
101 redef fun reverse_linearize(elements) do
102 return self.mmodule.reverse_linearize_mclasses(elements)
103 end
104 end
105
106 # Layout builder for resolution tables using Binary Matrix (BM)
107 class ResolutionBMizer
108 super ResolutionLayoutBuilder
109
110 init do end
111
112 redef fun build_layout(elements) do
113 var result = new Layout[MType]
114 var ids = new HashMap[MType, Int]
115 var color = 0
116 for mclasstype, mclasstypes in elements do
117 for element in mclasstypes do
118 if ids.has_key(element) then continue
119 ids[element] = color
120 color += 1
121 end
122 end
123 result.ids = ids
124 result.pos = ids
125 return result
126 end
127 end
128
129 # Abstract BMizing for MProperties
130 class MPropertyBMizer[E: MProperty]
131 super PropertyLayoutBuilder[E]
132
133 type MPROP: MProperty
134
135 var mmodule: MModule
136
137 init(mmodule: MModule) do self.mmodule = mmodule
138
139 redef fun build_layout(elements) do
140 var result = new Layout[E]
141 var ids = new HashMap[E, Int]
142 for mclass in elements do
143 for mproperty in properties(mclass) do
144 if ids.has_key(mproperty) then continue
145 ids[mproperty] = ids.length
146 end
147 end
148 result.pos = ids
149 return result
150 end
151
152 private fun properties(mclass: MClass): Set[E] do
153 var properties = new HashSet[E]
154 for mprop in self.mmodule.properties(mclass) do
155 if mprop isa MPROP then properties.add(mprop)
156 end
157 return properties
158 end
159 end
160
161 # BMizing for MMethods
162 class MMethodBMizer
163 super MPropertyBMizer[MMethod]
164
165 redef type MPROP: MMethod
166 init(mmodule: MModule) do super(mmodule)
167 end
168
169 # BMizing for MMAttributes
170 class MAttributeBMizer
171 super MPropertyBMizer[MAttribute]
172
173 redef type MPROP: MAttribute
174 init(mmodule: MModule) do super(mmodule)
175 end
176
177 # BMizing for MVirtualTypeProps
178 class MVirtualTypePropBMizer
179 super MPropertyBMizer[MVirtualTypeProp]
180
181 redef type MPROP: MVirtualTypeProp
182 init(mmodule: MModule) do super(mmodule)
183 end
184
185 # Colorers
186
187 abstract class TypingColorer[E: Object]
188 super TypingLayoutBuilder[E]
189
190 private var core: Set[E] = new HashSet[E]
191 private var crown: Set[E] = new HashSet[E]
192 private var border: Set[E] = new HashSet[E]
193
194 private var coloration_result: Map[E, Int] = new HashMap[E, Int]
195
196 init do end
197
198 # Compute the layout with coloring
199 redef fun build_layout(elements: Set[E]): Layout[E] do
200 var result = new Layout[E]
201 result.ids = compute_ids(elements)
202 result.pos = colorize(elements)
203 return result
204 end
205
206 private fun compute_ids(elements: Set[E]): Map[E, Int] do
207 var ids = new HashMap[E, Int]
208 var lin = reverse_linearize(elements)
209 for element in lin do
210 ids[element] = ids.length
211 end
212 return ids
213 end
214
215 private fun colorize(elements: Set[E]): Map[E, Int] do
216 tag_elements(elements)
217 build_conflicts_graph(elements)
218 colorize_elements(core)
219 colorize_elements(border)
220 colorize_elements(crown)
221 return coloration_result
222 end
223
224 # Colorize a collection of elements
225 private fun colorize_elements(elements: Set[E]) do
226 var min_color = 0
227
228 var lin = reverse_linearize(elements)
229 for element in lin do
230 var color = min_color
231 while not self.is_color_free(element, elements, color) do
232 color += 1
233 end
234 coloration_result[element] = color
235 color = min_color
236 end
237 end
238
239 # Check if a related element to the element already use the color
240 private fun is_color_free(element: E, elements: Set[E], color: Int): Bool do
241 if conflicts_graph.has_key(element) then
242 for st in conflicts_graph[element] do
243 if coloration_result.has_key(st) and coloration_result[st] == color then return false
244 end
245 end
246 for st in self.super_elements(element, elements) do
247 if coloration_result.has_key(st) and coloration_result[st] == color then return false
248 end
249 return true
250 end
251
252 # Tag elements as core, crown or border
253 private fun tag_elements(elements: Set[E]) do
254 for element in elements do
255 # Check if sub elements are all in single inheritance
256 var all_subelements_si = true
257 for subelem in self.sub_elements(element, elements) do
258 if self.is_element_mi(subelem, elements) then
259 all_subelements_si = false
260 break
261 end
262 end
263
264 # Tag as core, crown or border
265 if self.is_element_mi(element, elements) then
266 core.add_all(self.super_elements(element, elements))
267 core.add(element)
268 if all_subelements_si then
269 border.add(element)
270 end
271 else if not all_subelements_si then
272 core.add_all(self.super_elements(element, elements))
273 core.add(element)
274 else
275 crown.add(element)
276 end
277 end
278 end
279
280 # Conflicts graph of elements hierarchy (two types are in conflict if they have common subelements)
281 private fun build_conflicts_graph(elements: Set[E]) do
282 self.conflicts_graph = new HashMap[E, HashSet[E]]
283 var core = reverse_linearize(self.core)
284 for t in core do
285 for i in self.linear_extension(t, elements) do
286 if t == i then continue
287
288 var lin_i = self.linear_extension(i, elements)
289
290 for j in self.linear_extension(t, elements) do
291 if i == j or j == t then continue
292 var lin_j = self.linear_extension(j, elements)
293
294 var d_ij = lin_i - lin_j
295 var d_ji = lin_j - lin_i
296
297 for ed1 in d_ij do
298 if not conflicts_graph.has_key(ed1) then conflicts_graph[ed1] = new HashSet[E]
299 # add ed1 x ed2 to conflicts graph
300 for ed2 in d_ji do conflicts_graph[ed1].add(ed2)
301 end
302 for ed1 in d_ij do
303 if not conflicts_graph.has_key(ed1) then conflicts_graph[ed1] = new HashSet[E]
304 # add ed1 x ed2 to conflicts graph
305 for ed2 in d_ji do conflicts_graph[ed1].add(ed2)
306 end
307 end
308 end
309 end
310 end
311
312 private var conflicts_graph: nullable HashMap[E, Set[E]]
313
314 # cache for linear_extensions
315 private var linear_extensions_cache: Map[E, Array[E]] = new HashMap[E, Array[E]]
316
317 # Return a linear_extension of super_elements of the element
318 private fun linear_extension(element: E, elements: Set[E]): Array[E] do
319 if not self.linear_extensions_cache.has_key(element) then
320 var supers = new HashSet[E]
321 supers.add(element)
322 supers.add_all(self.super_elements(element, elements))
323 self.linear_extensions_cache[element] = self.linearize(supers)
324 end
325 return self.linear_extensions_cache[element]
326 end
327
328 private fun super_elements(element: E, elements: Set[E]): Set[E] is abstract
329 private fun sub_elements(element: E, elements: Set[E]): Set[E] is abstract
330 private fun is_element_mi(element: E, elements: Set[E]): Bool is abstract
331 private fun linearize(elements: Set[E]): Array[E] is abstract
332 private fun reverse_linearize(elements: Set[E]): Array[E] is abstract
333 end
334
335 # MType coloring
336 class MTypeColorer
337 super TypingColorer[MType]
338
339 var mmodule: MModule
340
341 init(mmodule: MModule) do self.mmodule = mmodule
342
343 redef fun super_elements(element, elements) do return self.mmodule.super_mtypes(element, elements)
344 redef fun is_element_mi(element, elements) do return self.super_elements(element, elements).length > 1
345 redef fun sub_elements(element, elements) do do return self.mmodule.sub_mtypes(element, elements)
346 redef fun linearize(elements) do return self.mmodule.linearize_mtypes(elements)
347 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mtypes(elements)
348 end
349
350 # MClass coloring
351 class MClassColorer
352 super TypingColorer[MClass]
353
354 private var mmodule: MModule
355
356 init(mmodule: MModule) do self.mmodule = mmodule
357
358 redef fun super_elements(element, elements) do return self.mmodule.super_mclasses(element)
359 fun parent_elements(element: MClass): Set[MClass] do return self.mmodule.parent_mclasses(element)
360 redef fun is_element_mi(element, elements) do return self.parent_elements(element).length > 1
361 redef fun sub_elements(element, elements) do do return self.mmodule.sub_mclasses(element)
362 redef fun linearize(elements) do return self.mmodule.linearize_mclasses(elements)
363 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mclasses(elements)
364 end
365
366 # MProperty coloring
367 abstract class MPropertyColorer[E: MProperty]
368 super PropertyLayoutBuilder[E]
369
370 private var mmodule: MModule
371 private var class_colorer: MClassColorer
372 private var coloration_result: Map[E, Int] = new HashMap[E, Int]
373
374 init(mmodule: MModule) do
375 self.mmodule = mmodule
376 self.class_colorer = new MClassColorer(mmodule)
377 end
378
379 # Compute mclasses ids and position using BM
380 redef fun build_layout(mclasses: Set[MClass]): Layout[E] do
381 var result = new Layout[E]
382 result.pos = self.colorize(mclasses)
383 return result
384 end
385
386 private fun colorize(mclasses: Set[MClass]): Map[E, Int] do
387 self.class_colorer.tag_elements(mclasses)
388 self.class_colorer.build_conflicts_graph(mclasses)
389 self.colorize_core(self.class_colorer.core)
390 self.colorize_crown(self.class_colorer.crown)
391 return self.coloration_result
392 end
393
394 # Colorize properties of the core hierarchy
395 private fun colorize_core(mclasses: Set[MClass]) do
396 var min_color = 0
397 for mclass in mclasses do
398 var color = min_color
399
400 # if the class is root, get the minimal color
401 if self.mmodule.parent_mclasses(mclass).length == 0 then
402 colorize_elements(self.properties(mclass), color)
403 else
404 # check last color used by parents
405 color = max_color(color, self.mmodule.parent_mclasses(mclass))
406 # check max color used in conflicts
407 if self.class_colorer.conflicts_graph.has_key(mclass) then
408 color = max_color(color, self.class_colorer.conflicts_graph[mclass])
409 end
410 colorize_elements(self.properties(mclass), color)
411 end
412 end
413 end
414
415 # Colorize properties of the crown hierarchy
416 private fun colorize_crown(mclasses: Set[MClass]) do
417 for mclass in mclasses do
418 colorize_elements(self.properties(mclass), max_color(0, self.mmodule.parent_mclasses(mclass)))
419 end
420 end
421
422 # Colorize a collection of mproperties given a starting color
423 private fun colorize_elements(elements: Collection[E], start_color: Int) do
424 for element in elements do
425 if self.coloration_result.has_key(element) then continue
426 self.coloration_result[element] = start_color
427 start_color += 1
428 end
429 end
430
431 private fun max_color(min_color: Int, mclasses: Collection[MClass]): Int do
432 var max_color = min_color
433
434 for mclass in mclasses do
435 for mproperty in self.properties(mclass) do
436 var color = min_color
437 if self.coloration_result.has_key(mproperty) then
438 color = self.coloration_result[mproperty]
439 if color >= max_color then max_color = color + 1
440 end
441 end
442 end
443 return max_color
444 end
445
446 # Filter properties
447 private fun properties(mclass: MClass): Set[E] is abstract
448 end
449
450 # Coloring for MMethods
451 class MMethodColorer
452 super MPropertyColorer[MMethod]
453
454 init(mmodule: MModule) do super
455
456 redef fun properties(mclass) do
457 var properties = new HashSet[MMethod]
458 for mprop in self.mmodule.properties(mclass) do
459 if mprop isa MMethod then properties.add(mprop)
460 end
461 return properties
462 end
463 end
464
465 # Coloring for MMAttributes
466 class MAttributeColorer
467 super MPropertyColorer[MAttribute]
468
469 init(mmodule: MModule) do super
470
471 redef fun properties(mclass) do
472 var properties = new HashSet[MAttribute]
473 for mprop in self.mmodule.properties(mclass) do
474 if mprop isa MAttribute then properties.add(mprop)
475 end
476 return properties
477 end
478 end
479
480 # Coloring for MVirtualTypeProps
481 class MVirtualTypePropColorer
482 super MPropertyColorer[MVirtualTypeProp]
483
484 init(mmodule: MModule) do super
485
486 redef fun properties(mclass) do
487 var properties = new HashSet[MVirtualTypeProp]
488 for mprop in self.mmodule.properties(mclass) do
489 if mprop isa MVirtualTypeProp then properties.add(mprop)
490 end
491 return properties
492 end
493 end
494
495 # Colorer for type resolution table
496 class ResolutionColorer
497 super ResolutionLayoutBuilder
498
499 private var coloration_result: Map[MType, Int] = new HashMap[MType, Int]
500
501 init do end
502
503 # Compute resolved types colors
504 redef fun build_layout(elements) do
505 self.build_conflicts_graph(elements)
506 var result = new Layout[MType]
507 result.ids = self.compute_ids(elements)
508 result.pos = self.colorize_elements(elements)
509 return result
510 end
511
512 private fun compute_ids(elements: Map[MClassType, Set[MType]]): Map[MType, Int] do
513 var ids = new HashMap[MType, Int]
514 var color = 0
515 for mclasstype, mclasstypes in elements do
516 for element in mclasstypes do
517 if ids.has_key(element) then continue
518 ids[element] = color
519 color += 1
520 end
521 end
522 return ids
523 end
524
525 # Colorize a collection of elements
526 private fun colorize_elements(elements: Map[MClassType, Set[MType]]): Map[MType, Int] do
527 var min_color = 0
528 for mclasstype, mclasstypes in elements do
529 for element in mclasstypes do
530 if self.coloration_result.has_key(element) then continue
531 var color = min_color
532 while not self.is_color_free(element, color) do
533 color += 1
534 end
535 coloration_result[element] = color
536 color = min_color
537 end
538 end
539 return self.coloration_result
540 end
541
542 # Check if a related element to the element already use the color
543 private fun is_color_free(element: MType, color: Int): Bool do
544 if conflicts_graph.has_key(element) then
545 for st in conflicts_graph[element] do
546 if coloration_result.has_key(st) and coloration_result[st] == color then return false
547 end
548 end
549 return true
550 end
551
552 # look for unanchored types generated by the same type
553 private fun build_conflicts_graph(elements: Map[MClassType, Set[MType]]) do
554 for mclasstype, mtypes in elements do
555 for mtype in mtypes do
556 for otype in mtypes do
557 if otype == mtype then continue
558 self.add_conflict(mtype, otype)
559 end
560 end
561 end
562 end
563
564 private var conflicts_graph: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]]
565
566 private fun add_conflict(mtype: MType, otype: MType) do
567 if mtype == otype then return
568 if not self.conflicts_graph.has_key(mtype) then self.conflicts_graph[mtype] = new HashSet[MType]
569 self.conflicts_graph[mtype].add(otype)
570 if not self.conflicts_graph.has_key(otype) then self.conflicts_graph[otype] = new HashSet[MType]
571 self.conflicts_graph[otype].add(mtype)
572 end
573 end
574
575 # Perfect Hashing (PH)
576 # T = type of holder
577 # U = type of elements to hash
578 private class PerfectHasher[T: Object, U: Object]
579
580 var operator: PHOperator
581
582 init(operator: PHOperator) do self.operator = operator
583
584 fun compute_masks(conflicts: Map[T, Set[U]], ids: Map[U, Int]): Map[T, Int] do
585 var masks = new HashMap[T, Int]
586 for mclasstype, mtypes in conflicts do
587 masks[mclasstype] = compute_mask(mtypes, ids)
588 end
589 return masks
590 end
591
592 private fun compute_mask(mtypes: Set[U], ids: Map[U, Int]): Int do
593 var mask = 0
594 loop
595 var used = new List[Int]
596 for mtype in mtypes do
597 var res = operator.op(mask, ids[mtype])
598 if used.has(res) then
599 break
600 else
601 used.add(res)
602 end
603 end
604 if used.length == mtypes.length then break
605 mask += 1
606 end
607 return mask
608 end
609
610 fun compute_hashes(elements: Map[T, Set[U]], ids: Map[U, Int], masks: Map[T, Int]): Map[T, Map[U, Int]] do
611 var hashes = new HashMap[T, Map[U, Int]]
612 for mclasstype, mtypes in elements do
613 var mask = masks[mclasstype]
614 var inhashes = new HashMap[U, Int]
615 for mtype in mtypes do
616 inhashes[mtype] = operator.op(mask, ids[mtype])
617 end
618 hashes[mclasstype] = inhashes
619 end
620 return hashes
621 end
622 end
623
624 # Abstract operator used for perfect hashing
625 abstract class PHOperator
626 fun op(mask: Int, id:Int): Int is abstract
627 end
628
629 # Hashing using modulo (MOD) operator
630 # slower but compact
631 class PHModOperator
632 super PHOperator
633 init do end
634 redef fun op(mask, id) do return mask % id
635 end
636
637 # Hashing using binary and (AND) operator
638 # faster but sparse
639 class PHAndOperator
640 super PHOperator
641 init do end
642 redef fun op(mask, id) do return mask.bin_and(id)
643 end
644
645 class TypingHasher[E: Object]
646 super PerfectHasher[E, E]
647 super TypingLayoutBuilder[E]
648
649 var mmodule: MModule
650
651 init(operator: PHOperator, mmodule: MModule) do
652 super(operator)
653 self.mmodule = mmodule
654 end
655
656 redef fun build_layout(elements: Set[E]): PHLayout[E, E] do
657 var result = new PHLayout[E, E]
658 var conflicts = self.build_conflicts(elements)
659 result.ids = self.compute_ids(elements)
660 result.masks = self.compute_masks(conflicts, result.ids)
661 result.hashes = self.compute_hashes(conflicts, result.ids, result.masks)
662 return result
663 end
664
665 # Ids start from 1 instead of 0
666 private fun compute_ids(elements: Set[E]): Map[E, Int] do
667 var ids = new HashMap[E, Int]
668 var lin = self.reverse_linearize(elements)
669 for e in lin do
670 ids[e] = ids.length + 1
671 end
672 return ids
673 end
674
675 private fun build_conflicts(elements: Set[E]): Map[E, Set[E]] do
676 var conflicts = new HashMap[E, Set[E]]
677 for e in elements do
678 var supers = self.super_elements(e, elements)
679 supers.add(e)
680 conflicts[e] = supers
681 end
682 return conflicts
683 end
684
685 private fun super_elements(element: E, elements: Set[E]): Set[E] is abstract
686 private fun reverse_linearize(elements: Set[E]): Array[E] is abstract
687 end
688
689 class MTypeHasher
690 super TypingHasher[MType]
691
692 init(operator: PHOperator, mmodule: MModule) do super(operator, mmodule)
693
694 redef fun super_elements(element, elements) do
695 return self.mmodule.super_mtypes(element, elements)
696 end
697
698 redef fun reverse_linearize(elements) do
699 return self.mmodule.reverse_linearize_mtypes(elements)
700 end
701 end
702
703 class MClassHasher
704 super TypingHasher[MClass]
705
706 init(operator: PHOperator, mmodule: MModule) do super(operator, mmodule)
707
708 redef fun super_elements(element, elements) do
709 return self.mmodule.super_mclasses(element)
710 end
711
712 redef fun reverse_linearize(elements) do
713 return self.mmodule.reverse_linearize_mclasses(elements)
714 end
715 end
716
717 # Layout builder for MProperty using Perfect Hashing (PH)
718 # TODO implement this class without sublcassing CL builder
719 class MPropertyHasher[E: MProperty]
720 super MPropertyColorer[E]
721 end
722
723 class ResolutionHasher
724 super PerfectHasher[MClassType, MType]
725 super ResolutionLayoutBuilder
726
727 init(operator: PHOperator) do super(operator)
728
729 # Compute resolved types masks and hashes
730 redef fun build_layout(elements) do
731 var result = new PHLayout[MClassType, MType]
732 var ids = new HashMap[MType, Int]
733 var color = 1
734 for mclasstype, mclasstypes in elements do
735 for element in mclasstypes do
736 if ids.has_key(element) then continue
737 ids[element] = color
738 color += 1
739 end
740 end
741 result.ids = ids
742 result.pos = ids
743 result.masks = self.compute_masks(elements, ids)
744 result.hashes = self.compute_hashes(elements, ids, result.masks)
745 return result
746 end
747 end