compile: give NativeArray its own C structure
[nit.git] / src / compiling / compiling_global.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2008 Jean Privat <jean@pryen.org>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Compute and generate tables for classes and modules.
18 package compiling_global
19
20 private import compiling_icode
21
22 # Something that store color of table elements
23 class ColorContext
24 var _colors: HashMap[TableElt, Int] = new HashMap[TableElt, Int]
25
26 # The color of a table element.
27 fun color(e: TableElt): Int
28 do
29 return _colors[e]
30 end
31
32 # Is a table element already colored?
33 fun has_color(e: TableElt): Bool
34 do
35 return _colors.has_key(e)
36 end
37
38 # Assign a color to a table element.
39 fun color=(e: TableElt, c: Int)
40 do
41 _colors[e] = c
42 var idx = c
43 for i in [0..e.length[ do
44 _colors[e.item(i)] = idx
45 idx = idx + 1
46 end
47 end
48 end
49
50 # All information and results of the global analysis.
51 class GlobalAnalysis
52 special ColorContext
53 # Associate global classes to compiled classes
54 readable var _compiled_classes: HashMap[MMGlobalClass, CompiledClass] = new HashMap[MMGlobalClass, CompiledClass]
55
56 # The main module of the program globally analysed
57 readable var _module: MMModule
58
59 # FIXME: do something better.
60 readable writable var _max_class_table_length: Int = 0
61
62 init(module: MMModule)
63 do
64 _module = module
65 end
66 end
67
68 class GlobalCompilerVisitor
69 special CompilerVisitor
70 # The global analysis result
71 readable var _global_analysis: GlobalAnalysis
72 init(m: MMModule, tc: ToolContext, ga: GlobalAnalysis)
73 do
74 super(m, tc)
75 _global_analysis = ga
76 end
77 end
78
79 # A compiled class is a class in a program
80 class CompiledClass
81 special ColorContext
82 # The corresponding local class in the main module of the prgram
83 readable var _local_class: MMLocalClass
84
85 # The identifier of the class
86 readable writable var _id: Int = 0
87
88 # The full class table of the class
89 readable var _class_table: Array[nullable TableElt] = new Array[nullable TableElt]
90
91 # The full instance table of the class
92 readable var _instance_table: Array[nullable TableElt] = new Array[nullable TableElt]
93
94 # The proper class table part (no superclasses but all refinements)
95 readable writable var _class_layout: TableEltComposite = new TableEltComposite(self)
96
97 # The proper instance table part (no superclasses but all refinements)
98 readable writable var _instance_layout: TableEltComposite = new TableEltComposite(self)
99
100 init(c: MMLocalClass) do _local_class = c
101 end
102
103 redef class MMConcreteClass
104 # The table element of the subtype check
105 fun class_color_pos: TableEltClassColor do return _class_color_pos.as(not null)
106 var _class_color_pos: nullable TableEltClassColor
107
108 # The proper local class table part (nor superclasses nor refinments)
109 readable var _class_layout: Array[TableElt] = new Array[TableElt]
110
111 # The proper local instance table part (nor superclasses nor refinments)
112 readable var _instance_layout: Array[TableElt] = new Array[TableElt]
113
114 # Build the local layout of the class and feed the module table
115 fun build_layout_in(tc: ToolContext, module_table: Array[ModuleTableElt])
116 do
117 var clt = _class_layout
118 var ilt = _instance_layout
119
120 if global.intro == self then
121 module_table.add(new TableEltClassId(self))
122 var cpp = new TableEltClassColor(self)
123 _class_color_pos = cpp
124 module_table.add(cpp)
125 clt.add(new TableEltClassInitTable(self))
126 end
127 for p in local_local_properties do
128 var pg = p.global
129 if pg.intro == p then
130 if p isa MMAttribute then
131 ilt.add(new TableEltAttr(p))
132 else if p isa MMMethod then
133 clt.add(new TableEltMeth(p))
134 end
135 end
136 if p isa MMMethod and p.need_super then
137 clt.add(new TableEltSuper(p))
138 end
139 end
140
141 if not ilt.is_empty then
142 var teg = new ModuleTableEltGroup
143 teg.elements.append(ilt)
144 module_table.add(teg)
145 end
146
147 if not clt.is_empty then
148 var teg = new ModuleTableEltGroup
149 teg.elements.append(clt)
150 module_table.add(teg)
151 end
152 end
153 end
154
155 redef class MMModule
156 # The local table of the module (refers things introduced in the module)
157 var _local_table: Array[ModuleTableElt] = new Array[ModuleTableElt]
158
159 # Builds the local tables and local classes layouts
160 fun local_analysis(tc: ToolContext)
161 do
162 for c in local_classes do
163 if c isa MMConcreteClass then
164 c.build_layout_in(tc, _local_table)
165 end
166 end
167 end
168
169 # Do the complete global analysis
170 fun global_analysis(cctx: ToolContext): GlobalAnalysis
171 do
172 #print "Do the complete global analysis"
173 var ga = new GlobalAnalysis(self)
174 var smallest_classes = new Array[MMLocalClass]
175 var global_properties = new HashSet[MMGlobalProperty]
176 var ctab = new Array[TableElt]
177 var itab = new Array[TableElt]
178
179 ctab.add(new TableEltClassSelfId)
180 itab.add(new TableEltVftPointer)
181 itab.add(new TableEltObjectId)
182
183 var pclassid = -1
184 var classid = 3
185
186 # We have to work on ALL the classes of the module
187 var classes = new Array[MMLocalClass]
188 for c in local_classes do
189 c.compute_super_classes
190 classes.add(c)
191 end
192 (new ClassSorter).sort(classes)
193
194 for c in classes do
195 # Finish processing the class (if invisible)
196 c.compute_ancestors
197 c.inherit_global_properties
198
199 # Associate a CompiledClass to the class
200 var cc = new CompiledClass(c)
201 ga.compiled_classes[c.global] = cc
202
203 # Assign a unique class identifier
204 # (negative are for primitive classes)
205 var gc = c.global
206 var bm = gc.module
207 if c.primitive_info != null then
208 cc.id = pclassid
209 pclassid = pclassid - 4
210 else
211 cc.id = classid
212 classid = classid + 4
213 end
214
215 # Register is the class is a leaf
216 if c.cshe.direct_smallers.is_empty then
217 smallest_classes.add(c)
218 end
219
220 # Store the colortableelt in the class table pool
221 var bc = c.global.intro
222 assert bc isa MMConcreteClass
223 ctab.add(bc.class_color_pos)
224 end
225
226 # Compute core and crown classes for colorization
227 var crown_classes = new HashSet[MMLocalClass]
228 var core_classes = new HashSet[MMLocalClass]
229 for c in smallest_classes do
230 while c.cshe.direct_greaters.length == 1 do
231 c = c.cshe.direct_greaters.first
232 end
233 crown_classes.add(c)
234 core_classes.add_all(c.cshe.greaters_and_self)
235 end
236 #print("nbclasses: {classes.length} leaves: {smallest_classes.length} crown: {crown_classes.length} core: {core_classes.length}")
237
238 # Colorize core color for typechecks
239 colorize(ga, ctab, crown_classes, 0)
240
241 # Compute tables for typechecks
242 var maxcolor = 0
243 for c in classes do
244 var cc = ga.compiled_classes[c.global]
245 if core_classes.has(c) then
246 # For core classes, just build the table
247 build_tables_in(cc.class_table, ga, c, ctab)
248 if maxcolor < cc.class_table.length then maxcolor = cc.class_table.length
249 else
250 # For other classes, it's easier: just append to the parent tables
251 var sc = c.cshe.direct_greaters.first
252 var scc = ga.compiled_classes[sc.global]
253 assert cc.class_table.is_empty
254 cc.class_table.add_all(scc.class_table)
255 var bc = c.global.intro
256 assert bc isa MMConcreteClass
257 var colpos = bc.class_color_pos
258 var colposcolor = cc.class_table.length
259 ga.color(colpos) = colposcolor
260 cc.class_table.add(colpos)
261 if maxcolor < colposcolor then maxcolor = colposcolor
262 end
263 end
264 ga.max_class_table_length = maxcolor + 1
265
266 # Fill class table and instance tables pools
267 for c in classes do
268 var cc = ga.compiled_classes[c.global]
269 var cte = cc.class_layout
270 var ite = cc.instance_layout
271 for sc in c.crhe.greaters_and_self do
272 if sc isa MMConcreteClass then
273 cte.add(sc, sc.class_layout)
274 ite.add(sc, sc.instance_layout)
275 end
276 end
277
278 if core_classes.has(c) then
279 if cte.length > 0 then
280 ctab.add(cte)
281 end
282 if ite.length > 0 then
283 itab.add(ite)
284 end
285 end
286 end
287
288 # Colorize all elements in pools tables
289 colorize(ga, ctab, crown_classes, maxcolor+1)
290 colorize(ga, itab, crown_classes, 0)
291
292 # Build class and instance tables now things are colored
293 ga.max_class_table_length = 0
294 for c in classes do
295 var cc = ga.compiled_classes[c.global]
296 if core_classes.has(c) then
297 # For core classes, just build the table
298 build_tables_in(cc.class_table, ga, c, ctab)
299 build_tables_in(cc.instance_table, ga, c, itab)
300 else
301 # For other classes, it's easier: just append to the parent tables
302 var sc = c.cshe.direct_greaters.first
303 var scc = ga.compiled_classes[sc.global]
304 cc.class_table.clear
305 cc.class_table.add_all(scc.class_table)
306 var bc = c.global.intro
307 assert bc isa MMConcreteClass
308 var colpos = bc.class_color_pos
309 cc.class_table[ga.color(colpos)] = colpos
310 while cc.class_table.length <= maxcolor do
311 cc.class_table.add(null)
312 end
313 append_to_table(ga, cc.class_table, cc.class_layout)
314 assert cc.instance_table.is_empty
315 cc.instance_table.add_all(scc.instance_table)
316 append_to_table(ga, cc.instance_table, cc.instance_layout)
317 end
318 end
319
320 return ga
321 end
322
323 private fun append_to_table(cc: ColorContext, table: Array[nullable TableElt], cmp: TableEltComposite)
324 do
325 for j in [0..cmp.length[ do
326 var e = cmp.item(j)
327 cc.color(e) = table.length
328 table.add(e)
329 end
330 end
331
332 private fun build_tables_in(table: Array[nullable TableElt], ga: GlobalAnalysis, c: MMLocalClass, elts: Array[TableElt])
333 do
334 var tab = new HashMap[Int, TableElt]
335 var len = 0
336 for e in elts do
337 if e.is_related_to(c) then
338 var col = ga.color(e)
339 var l = col + e.length
340 tab[col] = e
341 if len < l then
342 len = l
343 end
344 end
345 end
346 var i = 0
347 while i < len do
348 if tab.has_key(i) then
349 var e = tab[i]
350 for j in [0..e.length[ do
351 table[i] = e.item(j)
352 i = i + 1
353 end
354 else
355 table[i] = null
356 i = i + 1
357 end
358 end
359 end
360
361 # Perform coloring
362 fun colorize(ga: GlobalAnalysis, elts: Array[TableElt], classes: Collection[MMLocalClass], startcolor: Int)
363 do
364 var colors = new HashMap[Int, Array[TableElt]]
365 var rel_classes = new Array[MMLocalClass]
366 for e in elts do
367 var color = -1
368 var len = e.length
369 if ga.has_color(e) then
370 color = ga.color(e)
371 else
372 rel_classes.clear
373 for c in classes do
374 if e.is_related_to(c) then
375 rel_classes.add(c)
376 end
377 end
378 var trycolor = startcolor
379 while trycolor != color do
380 color = trycolor
381 for c in rel_classes do
382 var idx = 0
383 while idx < len do
384 if colors.has_key(trycolor + idx) and not free_color(colors[trycolor + idx], c) then
385 trycolor = trycolor + idx + 1
386 idx = 0
387 else
388 idx = idx + 1
389 end
390 end
391 end
392 end
393 ga.color(e) = color
394 end
395 for idx in [0..len[ do
396 if colors.has_key(color + idx) then
397 colors[color + idx].add(e)
398 else
399 colors[color + idx] = [e]
400 end
401 end
402 end
403 end
404
405 private fun free_color(es: Array[TableElt], c: MMLocalClass): Bool
406 do
407 for e2 in es do
408 if e2.is_related_to(c) then
409 return false
410 end
411 end
412 return true
413 end
414
415 # Compile module and class tables
416 fun compile_tables_to_c(v: GlobalCompilerVisitor)
417 do
418 for m in mhe.greaters_and_self do
419 m.compile_local_table_to_c(v)
420 end
421
422 for c in local_classes do
423 c.compile_tables_to_c(v)
424 end
425 var s = new Buffer.from("classtable_t TAG2VFT[4] = \{NULL")
426 for t in ["Int","Char","Bool"] do
427 if has_global_class_named(t.to_symbol) then
428 s.append(", (const classtable_t)VFT_{t}")
429 else
430 s.append(", NULL")
431 end
432 end
433 s.append("};")
434 v.add_instr(s.to_s)
435 end
436
437 # Declare class table (for _sep.h)
438 fun declare_class_tables_to_c(v: GlobalCompilerVisitor)
439 do
440 for c in local_classes do
441 if c.global.module == self then
442 c.declare_tables_to_c(v)
443 end
444 end
445 end
446
447 # Compile main part (for _table.c)
448 fun compile_main_part(v: GlobalCompilerVisitor)
449 do
450 v.add_instr("int main(int argc, char **argv) \{")
451 v.indent
452 v.add_instr("prepare_signals();")
453 v.add_instr("glob_argc = argc; glob_argv = argv;")
454 var sysname = once "Sys".to_symbol
455 if not has_global_class_named(sysname) then
456 print("No main")
457 else
458 var sys = class_by_name(sysname)
459 var name = once "main".to_symbol
460 if not sys.has_global_property_by_name(name) then
461 print("No main")
462 else
463 var mainm = sys.select_method(name)
464 v.add_instr("G_sys = NEW_Sys();")
465 v.add_instr("{mainm.cname}(G_sys);")
466 end
467 end
468 v.add_instr("return 0;")
469 v.unindent
470 v.add_instr("}")
471 end
472
473 # Compile sep files
474 fun compile_mod_to_c(v: GlobalCompilerVisitor)
475 do
476 v.add_decl("extern const char *LOCATE_{name};")
477 if not v.tc.global then
478 v.add_decl("extern const int SFT_{name}[];")
479 end
480 var i = 0
481 for e in _local_table do
482 var value: String
483 if v.tc.global then
484 value = "{e.value(v.global_analysis)}"
485 else
486 value = "SFT_{name}[{i}]"
487 i = i + 1
488 end
489 e.compile_macros(v, value)
490 end
491 for c in local_classes do
492 if not c isa MMConcreteClass then continue
493 for pg in c.global_properties do
494 var p = c[pg]
495 if p.local_class == c and p isa MMMethod then
496 p.compile_property_to_c(v)
497 end
498 if pg.is_init_for(c) then
499 # Declare constructors
500 var params = new Array[String]
501 for j in [0..p.signature.arity[ do
502 params.add("val_t p{j}")
503 end
504 v.add_decl("val_t NEW_{c}_{p.global.intro.cname}({params.join(", ")});")
505 end
506 end
507 end
508 end
509
510 # Compile module file for the current module
511 fun compile_local_table_to_c(v: GlobalCompilerVisitor)
512 do
513 v.add_instr("const char *LOCATE_{name} = \"{location.file}\";")
514
515 if v.tc.global or _local_table.is_empty then
516 return
517 end
518
519 v.add_instr("const int SFT_{name}[{_local_table.length}] = \{")
520 v.indent
521 for e in _local_table do
522 v.add_instr(e.value(v.global_analysis) + ",")
523 end
524 v.unindent
525 v.add_instr("\};")
526 end
527 end
528
529 ###############################################################################
530
531 # An element of a class, an instance or a module table
532 abstract class AbsTableElt
533 # Compile the macro needed to use the element and other related elements
534 fun compile_macros(v: GlobalCompilerVisitor, value: String) is abstract
535 end
536
537 # An element of a class or an instance table
538 # Such an elements represent method function pointers, attribute values, etc.
539 abstract class TableElt
540 special AbsTableElt
541 # Is the element conflict to class `c' (used for coloring)
542 fun is_related_to(c: MMLocalClass): Bool is abstract
543
544 # Number of sub-elements. 1 if none
545 fun length: Int do return 1
546
547 # Access the ith subelement.
548 fun item(i: Int): TableElt do return self
549
550 # Return the value of the element for a given class
551 fun compile_to_c(v: GlobalCompilerVisitor, c: MMLocalClass): String is abstract
552 end
553
554 # An element of a module table
555 # Such an elements represent colors or identifiers
556 abstract class ModuleTableElt
557 special AbsTableElt
558 # Return the value of the element once the global analisys is performed
559 fun value(ga: GlobalAnalysis): String is abstract
560 end
561
562 # An element of a module table that represents a group of TableElt defined in the same local class
563 class ModuleTableEltGroup
564 special ModuleTableElt
565 readable var _elements: Array[TableElt] = new Array[TableElt]
566
567 redef fun value(ga) do return "{ga.color(_elements.first)} /* Group of ? */"
568 redef fun compile_macros(v, value)
569 do
570 var i = 0
571 for e in _elements do
572 e.compile_macros(v, "{value} + {i}")
573 i += 1
574 end
575 end
576 end
577
578 # An element that represents a class property
579 abstract class TableEltProp
580 special TableElt
581 var _property: MMLocalProperty
582
583 init(p: MMLocalProperty)
584 do
585 _property = p
586 end
587 end
588
589 # An element that represents a function pointer to a global method
590 class TableEltMeth
591 special TableEltProp
592 redef fun compile_macros(v, value)
593 do
594 var pg = _property.global
595 v.add_decl("#define {pg.meth_call}(recv) (({pg.intro.cname}_t)CALL((recv), ({value})))")
596 end
597
598 redef fun compile_to_c(v, c)
599 do
600 var p = c[_property.global]
601 return p.cname
602 end
603 end
604
605 # An element that represents a function pointer to the super method of a local method
606 class TableEltSuper
607 special TableEltProp
608 redef fun compile_macros(v, value)
609 do
610 var p = _property
611 v.add_decl("#define {p.super_meth_call}(recv) (({p.cname}_t)CALL((recv), ({value})))")
612 end
613
614 redef fun compile_to_c(v, c)
615 do
616 var pc = _property.local_class
617 var g = _property.global
618 var lin = c.che.linear_extension
619 var found = false
620 for s in lin do
621 #print "{c.module}::{c} for {pc.module}::{pc}::{_property} try {s.module}:{s}"
622 if s == pc then
623 found = true
624 else if found and c.che < s then
625 if s.has_global_property(g) then
626 #print "found {s.module}::{s}::{p}"
627 return s[g].cname
628 end
629 end
630 end
631 abort
632 end
633 end
634
635 # An element that represents the value stored for a global attribute
636 class TableEltAttr
637 special TableEltProp
638 redef fun compile_macros(v, value)
639 do
640 var pg = _property.global
641 v.add_decl("#define {pg.attr_access}(recv) ATTR(recv, ({value}))")
642 end
643
644 redef fun compile_to_c(v, c)
645 do
646 var ga = v.global_analysis
647 var p = c[_property.global]
648 return "/* {ga.color(self)}: Attribute {c}::{p} */"
649 end
650 end
651
652 # An element representing a class information
653 class AbsTableEltClass
654 special AbsTableElt
655 # The local class where the information comes from
656 var _local_class: MMLocalClass
657
658 init(c: MMLocalClass)
659 do
660 _local_class = c
661 end
662
663 # The C macro name refering the value
664 fun symbol: String is abstract
665
666 redef fun compile_macros(v, value)
667 do
668 v.add_decl("#define {symbol} ({value})")
669 end
670 end
671
672 # An element of a class table representing a class information
673 class TableEltClass
674 special TableElt
675 special AbsTableEltClass
676 redef fun is_related_to(c)
677 do
678 var bc = c.module[_local_class.global]
679 return c.cshe <= bc
680 end
681 end
682
683 # An element representing the id of a class in a module table
684 class TableEltClassId
685 special ModuleTableElt
686 special AbsTableEltClass
687 redef fun symbol do return _local_class.global.id_id
688
689 redef fun value(ga)
690 do
691 return "{ga.compiled_classes[_local_class.global].id} /* Id of {_local_class} */"
692 end
693 end
694
695 # An element representing the constructor marker position in a class table
696 class TableEltClassInitTable
697 special TableEltClass
698 redef fun symbol do return _local_class.global.init_table_pos_id
699
700 redef fun compile_to_c(v, c)
701 do
702 var ga = v.global_analysis
703 var cc = ga.compiled_classes[_local_class.global]
704 var linext = c.cshe.reverse_linear_extension
705 var i = 0
706 while linext[i].global != _local_class.global do
707 i += 1
708 end
709 return "{i} /* {ga.color(self)}: {c} < {cc.local_class}: superclass init_table position */"
710 end
711 end
712
713 # An element used for a cast
714 # Note: this element is both a TableElt and a ModuleTableElt.
715 # At the TableElt offset, there is the id of the super-class
716 # At the ModuleTableElt offset, there is the TableElt offset (ie. the color of the super-class).
717 class TableEltClassColor
718 special TableEltClass
719 special ModuleTableElt
720 redef fun symbol do return _local_class.global.color_id
721
722 redef fun value(ga)
723 do
724 return "{ga.color(self)} /* Color of {_local_class} */"
725 end
726
727 redef fun compile_to_c(v, c)
728 do
729 var ga = v.global_analysis
730 var cc = ga.compiled_classes[_local_class.global]
731 return "{cc.id} /* {ga.color(self)}: {c} < {cc.local_class}: superclass typecheck marker */"
732 end
733 end
734
735 # A Group of elements introduced in the same global-class that are colored together
736 class TableEltComposite
737 special TableElt
738 var _table: Array[TableElt]
739 var _cc: CompiledClass
740 var _offsets: HashMap[MMLocalClass, Int]
741 redef fun length do return _table.length
742 redef fun is_related_to(c) do return c.cshe <= _cc.local_class
743
744 fun add(c: MMLocalClass, tab: Array[TableElt])
745 do
746 _offsets[c] = _table.length
747 _table.append(tab)
748 end
749
750 redef fun item(i) do return _table[i]
751
752 redef fun compile_to_c(v, c) do abort
753
754 init(cc: CompiledClass)
755 do
756 _cc = cc
757 _table = new Array[TableElt]
758 _offsets = new HashMap[MMLocalClass, Int]
759 end
760 end
761
762 # The element that represent the class id
763 class TableEltClassSelfId
764 special TableElt
765 redef fun is_related_to(c) do return true
766 redef fun compile_to_c(v, c)
767 do
768 var ga = v.global_analysis
769 return "{v.global_analysis.compiled_classes[c.global].id} /* {ga.color(self)}: Identity */"
770 end
771 end
772
773 # The element that represent the object id
774 class TableEltObjectId
775 special TableElt
776 redef fun is_related_to(c) do return true
777 redef fun compile_to_c(v, c)
778 do
779 var ga = v.global_analysis
780 return "/* {ga.color(self)}: Object_id */"
781 end
782 end
783
784 # The element that
785 class TableEltVftPointer
786 special TableElt
787 redef fun is_related_to(c) do return true
788 redef fun compile_to_c(v, c)
789 do
790 var ga = v.global_analysis
791 return "/* {ga.color(self)}: Pointer to the classtable */"
792 end
793 end
794
795 ###############################################################################
796
797 # Used to sort local class in a deterministic total order
798 # The total order superset the class refinement and the class specialisation relations
799 class ClassSorter
800 special AbstractSorter[MMLocalClass]
801 redef fun compare(a, b) do return a.compare(b)
802 init do end
803 end
804
805 redef class MMLocalClass
806 # Comparaison in a total order that superset the class refinement and the class specialisation relations
807 fun compare(b: MMLocalClass): Int
808 do
809 var a = self
810 if a == b then
811 return 0
812 else if a.module.mhe < b.module then
813 return 1
814 else if b.module.mhe < a.module then
815 return -1
816 end
817 var ar = a.cshe.rank
818 var br = b.cshe.rank
819 if ar > br then
820 return 1
821 else if br > ar then
822 return -1
823 else
824 return b.name.to_s <=> a.name.to_s
825 end
826 end
827
828 # Declaration and macros related to the class table
829 fun declare_tables_to_c(v: GlobalCompilerVisitor)
830 do
831 v.add_decl("")
832 var pi = primitive_info
833 v.add_decl("extern const classtable_elt_t VFT_{name}[];")
834 if name == "NativeArray".to_symbol then
835 v.add_decl("val_t NEW_NativeArray(size_t length, size_t size);")
836 else if pi == null then
837 # v.add_decl("val_t NEW_{name}(void);")
838 else if not pi.tagged then
839 var t = pi.cname
840 var tbox = "struct TBOX_{name}"
841 v.add_decl("{tbox} \{ const classtable_elt_t * vft; bigint object_id; {t} val;};")
842 v.add_decl("val_t BOX_{name}({t} val);")
843 v.add_decl("#define UNBOX_{name}(x) ((({tbox} *)(VAL2OBJ(x)))->val)")
844 end
845 end
846
847 # Compilation of table and new (or box)
848 fun compile_tables_to_c(v: GlobalCompilerVisitor)
849 do
850 var cc = v.global_analysis.compiled_classes[self.global]
851 var ctab = cc.class_table
852 var clen = ctab.length
853 if v.global_analysis.max_class_table_length > ctab.length then
854 clen = v.global_analysis.max_class_table_length
855 end
856
857 v.add_instr("const classtable_elt_t VFT_{name}[{clen}] = \{")
858 v.indent
859 for e in ctab do
860 if e == null then
861 v.add_instr("\{0} /* Class Hole :( */,")
862 else
863 v.add_instr("\{(bigint) {e.compile_to_c(v, self)}},")
864 end
865 end
866 if clen > ctab.length then
867 v.add_instr("\{0},"*(clen-ctab.length))
868 end
869 v.unindent
870 v.add_instr("};")
871 var itab = cc.instance_table
872 for e in itab do
873 if e == null then
874 v.add_instr("/* Instance Hole :( */")
875 else
876 v.add_instr(e.compile_to_c(v, self))
877 end
878 end
879
880 var pi = primitive_info
881 if name == "NativeArray".to_symbol then
882 v.add_instr("val_t NEW_NativeArray(size_t length, size_t size) \{")
883 v.indent
884 v.add_instr("Nit_NativeArray array;")
885 v.add_instr("array = (Nit_NativeArray)alloc(sizeof(struct Nit_NativeArray) + ((length - 1) * size));")
886 v.add_instr("array->vft = (classtable_elt_t*)VFT_{name};")
887 v.add_instr("array->object_id = object_id_counter;")
888 v.add_instr("object_id_counter = object_id_counter + 1;")
889 v.add_instr("array->size = length;")
890 v.add_instr("return OBJ2VAL(array);")
891 v.unindent
892 v.add_instr("}")
893 else if pi == null then
894 do
895 var iself = new IRegister(get_type)
896 var iselfa = [iself]
897 var iroutine = new IRoutine(new Array[IRegister], iself)
898 var icb = new ICodeBuilder(module, iroutine)
899 var obj = new INative("OBJ2VAL(obj)", null)
900 obj.result = iself
901 icb.stmt(obj)
902
903 for g in global_properties do
904 var p = self[g]
905 var t = p.signature.return_type
906 if p isa MMAttribute and t != null then
907 var ir = p.iroutine
908 if ir == null then continue
909 # FIXME: Not compatible with sep compilation
910 var e = icb.inline_routine(ir, iselfa, null).as(not null)
911 icb.stmt(new IAttrWrite(p, iself, e))
912 end
913 end
914
915 var cname = "NEW_{name}"
916 var args = iroutine.compile_signature_to_c(v, cname, "new {name}", null, null)
917 var ctx_old = v.ctx
918 v.ctx = new CContext
919 v.add_decl("obj_t obj;")
920 v.add_instr("obj = alloc(sizeof(val_t) * {itab.length});")
921 v.add_instr("obj->vft = (classtable_elt_t*)VFT_{name};")
922 v.add_instr("obj[1].object_id = object_id_counter;")
923 v.add_instr("object_id_counter = object_id_counter + 1;")
924 var r = iroutine.compile_to_c(v, cname, args).as(not null)
925 v.add_instr("return {r};")
926 ctx_old.append(v.ctx)
927 v.ctx = ctx_old
928 v.unindent
929 v.add_instr("}")
930 end
931
932 do
933 # Compile CHECKNAME
934 var iself = new IRegister(get_type)
935 var iselfa = [iself]
936 var iroutine = new IRoutine(iselfa, null)
937 var icb = new ICodeBuilder(module, iroutine)
938 for g in global_properties do
939 var p = self[g]
940 var t = p.signature.return_type
941 if p isa MMAttribute and t != null and not t.is_nullable then
942 icb.add_attr_check(p, iself)
943 end
944 end
945 var cname = "CHECKNEW_{name}"
946 var args = iroutine.compile_signature_to_c(v, cname, "check new {name}", null, null)
947 var ctx_old = v.ctx
948 v.ctx = new CContext
949 iroutine.compile_to_c(v, cname, args)
950 ctx_old.append(v.ctx)
951 v.ctx = ctx_old
952 v.unindent
953 v.add_instr("}")
954 end
955
956 var init_table_size = cshe.greaters.length + 1
957 var init_table_decl = "int init_table[{init_table_size}] = \{0{", 0" * (init_table_size-1)}};"
958
959 for g in global_properties do
960 var p = self[g]
961 # FIXME skip invisible constructors
962 if not p.global.is_init_for(self) then continue
963 assert p isa MMMethod
964
965 var iself = new IRegister(get_type)
966 var iparams = new Array[IRegister]
967 for i in [0..p.signature.arity[ do iparams.add(new IRegister(p.signature[i]))
968 var iroutine = new IRoutine(iparams, iself)
969 iroutine.location = p.iroutine.location
970 var icb = new ICodeBuilder(module, iroutine)
971
972 var inew = new INative("NEW_{name}()", null)
973 inew.result = iself
974 icb.stmt(inew)
975 var iargs = [iself]
976 iargs.add_all(iparams)
977 icb.stmt(new INative("{p.cname}(@@@{", @@@"*iparams.length}, init_table)", iargs))
978 icb.stmt(new INative("CHECKNEW_{name}(@@@)", [iself]))
979
980 var cname = "NEW_{self}_{p.global.intro.cname}"
981 var new_args = iroutine.compile_signature_to_c(v, cname, "new {self} {p.full_name}", null, null)
982 var ctx_old = v.ctx
983 v.ctx = new CContext
984 v.add_instr(init_table_decl)
985 var e = iroutine.compile_to_c(v, cname, new_args).as(not null)
986 v.add_instr("return {e};")
987 ctx_old.append(v.ctx)
988 v.ctx = ctx_old
989 v.unindent
990 v.add_instr("}")
991 end
992 else if not pi.tagged then
993 var t = pi.cname
994 var tbox = "struct TBOX_{name}"
995 v.add_instr("val_t BOX_{name}({t} val) \{")
996 v.indent
997 v.add_instr("{tbox} *box = ({tbox}*)alloc(sizeof({tbox}));")
998 v.add_instr("box->vft = VFT_{name};")
999 v.add_instr("box->val = val;")
1000 v.add_instr("box->object_id = object_id_counter;")
1001 v.add_instr("object_id_counter = object_id_counter + 1;")
1002 v.add_instr("return OBJ2VAL(box);")
1003 v.unindent
1004 v.add_instr("}")
1005 end
1006 end
1007 end
1008
1009 redef class MMMethod
1010 fun compile_property_to_c(v: CompilerVisitor)
1011 do
1012 var ir = iroutine
1013 assert ir != null
1014
1015 var more_params: nullable String = null
1016 if global.is_init then more_params = "int* init_table"
1017 var args = ir.compile_signature_to_c(v, cname, full_name, null, more_params)
1018 var ctx_old = v.ctx
1019 v.ctx = new CContext
1020
1021 v.out_contexts.clear
1022
1023 var itpos: nullable String = null
1024 if global.is_init then
1025 itpos = "itpos{v.new_number}"
1026 v.add_decl("int {itpos} = VAL2OBJ({args.first})->vft[{local_class.global.init_table_pos_id}].i;")
1027 v.add_instr("if (init_table[{itpos}]) return;")
1028 end
1029
1030 var s = ir.compile_to_c(v, cname, args)
1031
1032 if itpos != null then
1033 v.add_instr("init_table[{itpos}] = 1;")
1034 end
1035 if s == null then
1036 v.add_instr("return;")
1037 else
1038 v.add_instr("return ", s, ";")
1039 end
1040
1041 ctx_old.append(v.ctx)
1042 v.ctx = ctx_old
1043 v.unindent
1044 v.add_instr("}")
1045
1046 for ctx in v.out_contexts do v.ctx.merge(ctx)
1047 end
1048 end
1049