20461ff8f9b381f3b1701c995e9b2aac7f32358c
[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 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 main_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 main_module.local_classes do classes.add(c)
174 classes.sort !cmp(x,y) = x.total_order_compare(y)
175
176 for c in classes do
177 # Associate a CompiledClass to the class
178 var cc = new CompiledClass(c)
179 compiled_classes[c.global] = cc
180
181 # Assign a unique class identifier
182 # (negative are for primitive classes)
183 var gc = c.global
184 var bm = gc.mmmodule
185 if c.primitive_info != null then
186 cc.id = pclassid
187 pclassid = pclassid - 4
188 else
189 cc.id = classid
190 classid = classid + 4
191 end
192
193 # Register is the class is a leaf
194 if c.cshe.direct_smallers.is_empty then
195 smallest_classes.add(c)
196 end
197
198 # Store the colortableelt in the class table pool
199 var bc = c.global.intro
200 assert bc isa MMConcreteClass
201 ctab.add(bc.class_color_pos)
202 end
203
204 # Compute core and crown classes for colorization
205 var crown_classes = new HashSet[MMLocalClass]
206 var core_classes = new HashSet[MMLocalClass]
207 for c in smallest_classes do
208 while c.cshe.direct_greaters.length == 1 do
209 c = c.cshe.direct_greaters.first
210 end
211 crown_classes.add(c)
212 core_classes.add_all(c.cshe.greaters_and_self)
213 end
214 #print("nbclasses: {classes.length} leaves: {smallest_classes.length} crown: {crown_classes.length} core: {core_classes.length}")
215
216 # Colorize core color for typechecks
217 colorize(ctab, crown_classes, 0)
218
219 # Compute tables for typechecks
220 var maxcolor = 0
221 for c in classes do
222 var cc = compiled_classes[c.global]
223 if core_classes.has(c) then
224 # For core classes, just build the table
225 build_tables_in(cc.class_table, c, ctab)
226 if maxcolor < cc.class_table.length then maxcolor = cc.class_table.length
227 else
228 # For other classes, it's easier: just append to the parent tables
229 var sc = c.cshe.direct_greaters.first
230 var scc = compiled_classes[sc.global]
231 assert cc.class_table.is_empty
232 cc.class_table.add_all(scc.class_table)
233 var bc = c.global.intro
234 assert bc isa MMConcreteClass
235 var colpos = bc.class_color_pos
236 var colposcolor = cc.class_table.length
237 table_information.color(colpos) = colposcolor
238 cc.class_table.add(colpos)
239 if maxcolor < colposcolor then maxcolor = colposcolor
240 end
241 end
242 table_information.max_class_table_length = maxcolor + 1
243
244 # Fill class table and instance tables pools
245 for c in classes do
246 var cc = compiled_classes[c.global]
247 var cte = cc.class_layout
248 var ite = cc.instance_layout
249 for sc in c.crhe.greaters_and_self do
250 if sc isa MMConcreteClass then
251 cte.add(sc, sc.class_layout)
252 ite.add(sc, sc.instance_layout)
253 end
254 end
255
256 if core_classes.has(c) then
257 if cte.length > 0 then
258 ctab.add(cte)
259 end
260 if ite.length > 0 then
261 itab.add(ite)
262 end
263 end
264 end
265
266 # Colorize all elements in pools tables
267 colorize(ctab, crown_classes, maxcolor+1)
268 colorize(itab, crown_classes, 0)
269
270 # Build class and instance tables now things are colored
271 table_information.max_class_table_length = 0
272 for c in classes do
273 var cc = compiled_classes[c.global]
274 if core_classes.has(c) then
275 # For core classes, just build the table
276 build_tables_in(cc.class_table, c, ctab)
277 build_tables_in(cc.instance_table, c, itab)
278 else
279 # For other classes, it's easier: just append to the parent tables
280 var sc = c.cshe.direct_greaters.first
281 var scc = compiled_classes[sc.global]
282 cc.class_table.clear
283 cc.class_table.add_all(scc.class_table)
284 var bc = c.global.intro
285 assert bc isa MMConcreteClass
286 var colpos = bc.class_color_pos
287 cc.class_table[table_information.color(colpos)] = colpos
288 while cc.class_table.length <= maxcolor do
289 cc.class_table.add(null)
290 end
291 append_to_table(cc.class_table, cc.class_layout)
292 assert cc.instance_table.is_empty
293 cc.instance_table.add_all(scc.instance_table)
294 append_to_table(cc.instance_table, cc.instance_layout)
295 end
296 end
297 end
298
299 # Perform coloring
300 fun colorize(elts: Array[TableElt], classes: Collection[MMLocalClass], startcolor: Int)
301 do
302 var colors = new HashMap[Int, Array[TableElt]]
303 var rel_classes = new Array[MMLocalClass]
304 for e in elts do
305 var color = -1
306 var len = e.length
307 if table_information.has_color(e) then
308 color = table_information.color(e)
309 else
310 rel_classes.clear
311 for c in classes do
312 if e.is_related_to(c) then
313 rel_classes.add(c)
314 end
315 end
316 var trycolor = startcolor
317 while trycolor != color do
318 color = trycolor
319 for c in rel_classes do
320 var idx = 0
321 while idx < len do
322 if colors.has_key(trycolor + idx) and not free_color(colors[trycolor + idx], c) then
323 trycolor = trycolor + idx + 1
324 idx = 0
325 else
326 idx = idx + 1
327 end
328 end
329 end
330 end
331 table_information.color(e) = color
332 end
333 for idx in [0..len[ do
334 if colors.has_key(color + idx) then
335 colors[color + idx].add(e)
336 else
337 colors[color + idx] = [e]
338 end
339 end
340 end
341 end
342
343 private fun free_color(es: Array[TableElt], c: MMLocalClass): Bool
344 do
345 for e2 in es do
346 if e2.is_related_to(c) then
347 return false
348 end
349 end
350 return true
351 end
352
353 private fun append_to_table(table: Array[nullable TableElt], cmp: TableEltComposite)
354 do
355 for j in [0..cmp.length[ do
356 var e = cmp.item(j)
357 table_information.color(e) = table.length
358 table.add(e)
359 end
360 end
361
362 private fun build_tables_in(table: Array[nullable TableElt], c: MMLocalClass, elts: Array[TableElt])
363 do
364 var tab = new HashMap[Int, TableElt]
365 var len = 0
366 for e in elts do
367 if e.is_related_to(c) then
368 var col = table_information.color(e)
369 var l = col + e.length
370 tab[col] = e
371 if len < l then
372 len = l
373 end
374 end
375 end
376 var i = 0
377 while i < len do
378 if tab.has_key(i) then
379 var e = tab[i]
380 for j in [0..e.length[ do
381 table[i] = e.item(j)
382 i = i + 1
383 end
384 else
385 table[i] = null
386 i = i + 1
387 end
388 end
389 end
390 end
391
392 redef class MMModule
393 # The local table of the module (refers things introduced in the module)
394 readable var _local_table: Array[ModuleTableElt] = new Array[ModuleTableElt]
395
396 # Builds the local tables and local classes layouts
397 private fun local_analysis
398 do
399 for c in local_classes do
400 if c isa MMConcreteClass then
401 c.build_layout_in(_local_table)
402 end
403 end
404 end
405 end
406
407 ###############################################################################
408
409 # An element of a class, an instance or a module table
410 abstract class AbsTableElt
411 end
412
413 # An element of a class or an instance table
414 # Such an elements represent method function pointers, attribute values, etc.
415 abstract class TableElt
416 super AbsTableElt
417 # Is the element conflict to class `c' (used for coloring)
418 fun is_related_to(c: MMLocalClass): Bool is abstract
419
420 # Number of sub-elements. 1 if none
421 fun length: Int do return 1
422
423 # Access the ith subelement.
424 fun item(i: Int): TableElt do return self
425 end
426
427 # An element of a module table
428 # Such an elements represent colors or identifiers
429 abstract class ModuleTableElt
430 super AbsTableElt
431 end
432
433 # An element of a module table that represents a group of TableElt defined in the same local class
434 class ModuleTableEltGroup
435 super ModuleTableElt
436 readable var _elements: Array[TableElt] = new Array[TableElt]
437 end
438
439 # An element that represents a class property
440 abstract class TableEltProp
441 super TableElt
442 readable var _property: MMLocalProperty
443
444 init(p: MMLocalProperty)
445 do
446 _property = p
447 end
448 end
449
450 # An element that represents a function pointer to a global method
451 class TableEltMeth
452 super TableEltProp
453 end
454
455 # An element that represents a function pointer to the super method of a local method
456 class TableEltSuper
457 super TableEltProp
458 end
459
460 # An element that represents the value stored for a global attribute
461 class TableEltAttr
462 super TableEltProp
463 end
464
465 # An element representing a class information
466 class AbsTableEltClass
467 super AbsTableElt
468 # The local class where the information comes from
469 readable var _local_class: MMLocalClass
470
471 init(c: MMLocalClass)
472 do
473 _local_class = c
474 end
475 end
476
477 # An element of a class table representing a class information
478 class TableEltClass
479 super TableElt
480 super AbsTableEltClass
481 redef fun is_related_to(c)
482 do
483 var bc = c.mmmodule[_local_class.global]
484 return c.cshe <= bc
485 end
486 end
487
488 # An element representing the id of a class in a module table
489 class TableEltClassId
490 super ModuleTableElt
491 super AbsTableEltClass
492 end
493
494 # An element representing the constructor marker position in a class table
495 class TableEltClassInitTable
496 super TableEltClass
497 end
498
499 # An element used for a cast
500 # Note: this element is both a TableElt and a ModuleTableElt.
501 # At the TableElt offset, there is the id of the super-class
502 # At the ModuleTableElt offset, there is the TableElt offset (ie. the color of the super-class).
503 class TableEltClassColor
504 super TableEltClass
505 super ModuleTableElt
506 end
507
508 # A Group of elements introduced in the same global-class that are colored together
509 class TableEltComposite
510 super TableElt
511 var _table: Array[TableElt]
512 var _cc: CompiledClass
513 var _offsets: HashMap[MMLocalClass, Int]
514 redef fun length do return _table.length
515 redef fun is_related_to(c) do return c.cshe <= _cc.local_class
516
517 fun add(c: MMLocalClass, tab: Array[TableElt])
518 do
519 _offsets[c] = _table.length
520 _table.append(tab)
521 end
522
523 redef fun item(i) do return _table[i]
524
525 init(cc: CompiledClass)
526 do
527 _cc = cc
528 _table = new Array[TableElt]
529 _offsets = new HashMap[MMLocalClass, Int]
530 end
531 end
532
533 # The element that represent the class id
534 class TableEltClassSelfId
535 super TableElt
536 redef fun is_related_to(c) do return true
537 end
538
539 # The element that represent the Object Size
540 class TableEltClassObjectSize
541 super TableElt
542 redef fun is_related_to(c) do return true
543 end
544
545 # The element that represent the object id
546 class TableEltObjectId
547 super TableElt
548 redef fun is_related_to(c) do return true
549 end
550
551 # The element that
552 class TableEltVftPointer
553 super TableElt
554 redef fun is_related_to(c) do return true
555 end