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