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