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