nitg-s: element set is no more required at colorer initialization
[nit.git] / src / separate_compiler.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Separate compilation of a Nit program
16 module separate_compiler
17
18 import abstract_compiler
19 import coloring
20
21 # Add separate compiler specific options
22 redef class ToolContext
23 # --separate
24 var opt_separate: OptionBool = new OptionBool("Use separate compilation", "--separate")
25 # --no-inline-intern
26 var opt_no_inline_intern: OptionBool = new OptionBool("Do not inline call to intern methods", "--no-inline-intern")
27 # --no-union-attribute
28 var opt_no_union_attribute: OptionBool = new OptionBool("Put primitive attibutes in a box instead of an union", "--no-union-attribute")
29 # --no-shortcut-equate
30 var opt_no_shortcut_equate: OptionBool = new OptionBool("Always call == in a polymorphic way", "--no-shortcut-equal")
31 # --inline-coloring-numbers
32 var opt_inline_coloring_numbers: OptionBool = new OptionBool("Inline colors and ids", "--inline-coloring-numbers")
33 # --use-naive-coloring
34 var opt_bm_typing: OptionBool = new OptionBool("Colorize items incrementaly, used to simulate binary matrix typing", "--bm-typing")
35 # --use-mod-perfect-hashing
36 var opt_phmod_typing: OptionBool = new OptionBool("Replace coloration by perfect hashing (with mod operator)", "--phmod-typing")
37 # --use-and-perfect-hashing
38 var opt_phand_typing: OptionBool = new OptionBool("Replace coloration by perfect hashing (with and operator)", "--phand-typing")
39 # --generic-resolution-tree
40 var opt_typing_table_metrics: OptionBool = new OptionBool("Enable static size measuring of tables used for typing and resolution", "--typing-table-metrics")
41
42 redef init
43 do
44 super
45 self.option_context.add_option(self.opt_separate)
46 self.option_context.add_option(self.opt_no_inline_intern)
47 self.option_context.add_option(self.opt_no_union_attribute)
48 self.option_context.add_option(self.opt_no_shortcut_equate)
49 self.option_context.add_option(self.opt_inline_coloring_numbers)
50 self.option_context.add_option(self.opt_bm_typing)
51 self.option_context.add_option(self.opt_phmod_typing)
52 self.option_context.add_option(self.opt_phand_typing)
53 self.option_context.add_option(self.opt_typing_table_metrics)
54 end
55 end
56
57 redef class ModelBuilder
58 fun run_separate_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis)
59 do
60 var time0 = get_time
61 self.toolcontext.info("*** COMPILING TO C ***", 1)
62
63 var compiler = new SeparateCompiler(mainmodule, self, runtime_type_analysis)
64 compiler.compile_header
65
66 # compile class structures
67 for m in mainmodule.in_importation.greaters do
68 for mclass in m.intro_mclasses do
69 compiler.compile_class_to_c(mclass)
70 end
71 end
72
73 # The main function of the C
74 compiler.new_file
75 compiler.compile_main_function
76
77 # compile methods
78 for m in mainmodule.in_importation.greaters do
79 compiler.new_file
80 compiler.compile_module_to_c(m)
81 end
82
83 # compile live & cast type structures
84 compiler.new_file
85 var mtypes = compiler.do_type_coloring
86 for t in mtypes do
87 compiler.compile_type_to_c(t)
88 end
89
90 compiler.display_stats
91
92 write_and_make(compiler)
93 end
94 end
95
96 # Singleton that store the knowledge about the separate compilation process
97 class SeparateCompiler
98 super AbstractCompiler
99
100 # Cache for classid
101 protected var classids: HashMap[MClassType, String] = new HashMap[MClassType, String]
102
103 # The result of the RTA (used to know live types and methods)
104 var runtime_type_analysis: RapidTypeAnalysis
105
106 private var undead_types: Set[MType] = new HashSet[MType]
107 private var partial_types: Set[MType] = new HashSet[MType]
108 protected var typeids: HashMap[MType, Int] protected writable = new HashMap[MType, Int]
109
110 private var type_colors: Map[MType, Int] = typeids
111 private var type_tables: nullable Map[MType, Array[nullable MType]] = null
112
113 private var live_unanchored_types: Map[MClassDef, Set[MType]] = new HashMap[MClassDef, HashSet[MType]]
114
115 private var unanchored_types_colors: nullable Map[MType, Int]
116 private var unanchored_types_tables: nullable Map[MClassType, Array[nullable MType]]
117 private var unanchored_types_masks: nullable Map[MClassType, Int]
118
119 protected var class_coloring: ClassColoring
120
121 protected var method_colors: Map[MMethod, Int]
122 protected var method_tables: Map[MClass, Array[nullable MMethodDef]]
123
124 protected var attr_colors: Map[MAttribute, Int]
125 protected var attr_tables: Map[MClass, Array[nullable MAttributeDef]]
126
127 protected var vt_colors: Map[MVirtualTypeProp, Int]
128 protected var vt_tables: Map[MClass, Array[nullable MVirtualTypeDef]]
129 protected var vt_masks: nullable Map[MClass, Int]
130
131 private var ft_colors: nullable Map[MParameterType, Int]
132 private var ft_tables: nullable Map[MClass, Array[nullable MParameterType]]
133 private var ft_masks: nullable Map[MClass, Int]
134
135 init(mainmodule: MModule, mmbuilder: ModelBuilder, runtime_type_analysis: RapidTypeAnalysis) do
136 super
137 self.header = new_visitor
138 self.runtime_type_analysis = runtime_type_analysis
139 self.do_property_coloring
140 self.compile_box_kinds
141 end
142
143 redef fun compile_header_structs do
144 self.header.add_decl("typedef void(*nitmethod_t)(void); /* general C type representing a Nit method. */")
145 self.compile_header_attribute_structs
146 self.header.add_decl("struct class \{ int box_kind; nitmethod_t vft[1]; \}; /* general C type representing a Nit class. */")
147
148 # With unanchored_table, all live type resolution are stored in a big table: unanchored_table
149 self.header.add_decl("struct type \{ int id; const char *name; int color; short int is_nullable; struct types *unanchored_table; int table_size; int type_table[1]; \}; /* general C type representing a Nit type. */")
150
151 if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
152 self.header.add_decl("struct types \{ int mask; struct type *types[1]; \}; /* a list types (used for vts, fts and unanchored lists). */")
153 else
154 self.header.add_decl("struct types \{ struct type *types[1]; \}; /* a list types (used for vts, fts and unanchored lists). */")
155 end
156
157 self.header.add_decl("typedef struct \{ struct type *type; struct class *class; nitattribute_t attrs[1]; \} val; /* general C type representing a Nit instance. */")
158 end
159
160 fun compile_header_attribute_structs
161 do
162 if modelbuilder.toolcontext.opt_no_union_attribute.value then
163 self.header.add_decl("typedef void* nitattribute_t; /* general C type representing a Nit attribute. */")
164 else
165 self.header.add_decl("typedef union \{")
166 self.header.add_decl("void* val;")
167 for c, v in self.box_kinds do
168 var t = c.mclass_type
169 self.header.add_decl("{t.ctype} {t.ctypename};")
170 end
171 self.header.add_decl("\} nitattribute_t; /* general C type representing a Nit attribute. */")
172 end
173 end
174
175 fun compile_box_kinds
176 do
177 # Collect all bas box class
178 # FIXME: this is not completely fine with a separate compilation scheme
179 for classname in ["Int", "Bool", "Char", "Float", "NativeString", "Pointer"] do
180 var classes = self.mainmodule.model.get_mclasses_by_name(classname)
181 if classes == null then continue
182 assert classes.length == 1 else print classes.join(", ")
183 self.box_kinds[classes.first] = self.box_kinds.length + 1
184 end
185 end
186
187 var box_kinds = new HashMap[MClass, Int]
188
189 fun box_kind_of(mclass: MClass): Int
190 do
191 if mclass.mclass_type.ctype == "val*" then
192 return 0
193 else if mclass.kind == extern_kind then
194 return self.box_kinds[self.mainmodule.get_primitive_class("Pointer")]
195 else
196 return self.box_kinds[mclass]
197 end
198
199 end
200
201 fun compile_color_consts(colors: Map[Object, Int]) do
202 for m, c in colors do
203 if m isa MProperty then
204 if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
205 self.header.add_decl("#define {m.const_color} {c}")
206 else
207 self.header.add_decl("extern const int {m.const_color};")
208 self.header.add("const int {m.const_color} = {c};")
209 end
210 else if m isa MType then
211 if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
212 self.header.add_decl("#define {m.const_color} {c}")
213 else
214 self.header.add_decl("extern const int {m.const_color};")
215 self.header.add("const int {m.const_color} = {c};")
216 end
217 end
218 end
219 end
220
221 # colorize classe properties
222 fun do_property_coloring do
223
224 # classes coloration
225 var mclasses = new HashSet[MClass].from(modelbuilder.model.mclasses)
226 self.class_coloring = new ClassColoring(mainmodule)
227 class_coloring.colorize(mclasses)
228
229 # methods coloration
230 var method_coloring = new MethodColoring(self.class_coloring)
231 self.method_colors = method_coloring.colorize
232 self.method_tables = method_coloring.build_property_tables
233 self.compile_color_consts(self.method_colors)
234
235 # attributes coloration
236 var attribute_coloring = new AttributeColoring(self.class_coloring)
237 self.attr_colors = attribute_coloring.colorize
238 self.attr_tables = attribute_coloring.build_property_tables
239 self.compile_color_consts(self.attr_colors)
240
241 if modelbuilder.toolcontext.opt_bm_typing.value then
242 self.class_coloring = new NaiveClassColoring(mainmodule)
243 self.class_coloring.colorize(mclasses)
244 end
245
246 # vt coloration
247 if modelbuilder.toolcontext.opt_bm_typing.value then
248 var vt_coloring = new NaiveVTColoring(self.class_coloring)
249 self.vt_colors = vt_coloring.colorize
250 self.vt_tables = vt_coloring.build_property_tables
251 else if modelbuilder.toolcontext.opt_phmod_typing.value then
252 var vt_coloring = new VTModPerfectHashing(self.class_coloring)
253 self.vt_colors = vt_coloring.colorize
254 self.vt_masks = vt_coloring.compute_masks
255 self.vt_tables = vt_coloring.build_property_tables
256 else if modelbuilder.toolcontext.opt_phand_typing.value then
257 var vt_coloring = new VTAndPerfectHashing(self.class_coloring)
258 self.vt_colors = vt_coloring.colorize
259 self.vt_masks = vt_coloring.compute_masks
260 self.vt_tables = vt_coloring.build_property_tables
261 else
262 var vt_coloring = new VTColoring(self.class_coloring)
263 self.vt_colors = vt_coloring.colorize
264 self.vt_tables = vt_coloring.build_property_tables
265 end
266 self.compile_color_consts(self.vt_colors)
267 end
268
269 # colorize live types of the program
270 private fun do_type_coloring: Set[MType] do
271 var mtypes = new HashSet[MType]
272 mtypes.add_all(self.runtime_type_analysis.live_types)
273 mtypes.add_all(self.runtime_type_analysis.live_cast_types)
274 mtypes.add_all(self.undead_types)
275 for c in self.box_kinds.keys do
276 mtypes.add(c.mclass_type)
277 end
278
279 for mtype in mtypes do
280 retieve_live_partial_types(mtype)
281 end
282 mtypes.add_all(self.partial_types)
283
284 # set type unique id
285 if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
286 var sorted_mtypes = new Array[MType].from(mtypes)
287 var sorter = new ReverseTypeSorter(self.mainmodule)
288 sorter.sort(sorted_mtypes)
289 for mtype in sorted_mtypes do
290 self.typeids[mtype] = self.typeids.length + 1
291 end
292 else
293 for mtype in mtypes do
294 self.typeids[mtype] = self.typeids.length
295 end
296 end
297
298 # VT and FT are stored with other unresolved types in the big unanchored_tables
299 self.compile_unanchored_tables(mtypes)
300
301 # colorize types
302 if modelbuilder.toolcontext.opt_bm_typing.value then
303 var type_coloring = new NaiveTypeColoring(self.mainmodule)
304 self.type_colors = type_coloring.colorize(mtypes)
305 self.type_tables = type_coloring.build_type_tables(mtypes, type_colors)
306 else if modelbuilder.toolcontext.opt_phmod_typing.value then
307 var type_coloring = new TypeModPerfectHashing(self.mainmodule)
308 self.type_colors = type_coloring.compute_masks(mtypes, typeids)
309 self.type_tables = type_coloring.hash_type_tables(mtypes, typeids, type_colors)
310 self.header.add_decl("#define HASH(mask, id) ((mask)%(id))")
311 else if modelbuilder.toolcontext.opt_phand_typing.value then
312 var type_coloring = new TypeAndPerfectHashing(self.mainmodule)
313 self.type_colors = type_coloring.compute_masks(mtypes, typeids)
314 self.type_tables = type_coloring.hash_type_tables(mtypes, typeids, type_colors)
315 self.header.add_decl("#define HASH(mask, id) ((mask)&(id))")
316 else
317 var type_coloring = new TypeColoring(self.mainmodule)
318 self.type_colors = type_coloring.colorize(mtypes)
319 self.type_tables = type_coloring.build_type_tables(mtypes, type_colors)
320 end
321
322
323 return mtypes
324 end
325
326 protected fun compile_unanchored_tables(mtypes: Set[MType]) do
327 # Unanchored_tables is used to perform a type resolution at runtime in O(1)
328
329 # During the visit of the body of classes, live_unanchored_types are collected
330 # and associated to
331 # Collect all live_unanchored_types (visited in the body of classes)
332
333 # Determinate fo each livetype what are its possible requested anchored types
334 var mtype2unanchored = new HashMap[MClassType, Set[MType]]
335 for mtype in self.runtime_type_analysis.live_types do
336 var set = new HashSet[MType]
337 for cd in mtype.collect_mclassdefs(self.mainmodule) do
338 if self.live_unanchored_types.has_key(cd) then
339 set.add_all(self.live_unanchored_types[cd])
340 end
341 end
342 mtype2unanchored[mtype] = set
343 end
344
345 # Compute the table layout with the prefered method
346 if modelbuilder.toolcontext.opt_bm_typing.value then
347 var unanchored_type_coloring = new NaiveUnanchoredTypeColoring
348 self.unanchored_types_colors = unanchored_type_coloring.colorize(mtype2unanchored)
349 self.unanchored_types_tables = unanchored_type_coloring.build_tables(mtype2unanchored)
350 else if modelbuilder.toolcontext.opt_phmod_typing.value then
351 var unanchored_type_coloring = new UnanchoredTypeModPerfectHashing
352 self.unanchored_types_colors = unanchored_type_coloring.colorize(mtype2unanchored)
353 self.unanchored_types_masks = unanchored_type_coloring.compute_masks(mtype2unanchored)
354 self.unanchored_types_tables = unanchored_type_coloring.build_tables(mtype2unanchored)
355 else if modelbuilder.toolcontext.opt_phand_typing.value then
356 var unanchored_type_coloring = new UnanchoredTypeAndPerfectHashing
357 self.unanchored_types_colors = unanchored_type_coloring.colorize(mtype2unanchored)
358 self.unanchored_types_masks = unanchored_type_coloring.compute_masks(mtype2unanchored)
359 self.unanchored_types_tables = unanchored_type_coloring.build_tables(mtype2unanchored)
360 else
361 var unanchored_type_coloring = new UnanchoredTypeColoring
362 self.unanchored_types_colors = unanchored_type_coloring.colorize(mtype2unanchored)
363 self.unanchored_types_tables = unanchored_type_coloring.build_tables(mtype2unanchored)
364 end
365
366 # Compile a C constant for each collected unanchored type.
367 # Either to a color, or to -1 if the unanchored type is dead (no live receiver can require it)
368 var all_unanchored = new HashSet[MType]
369 for t in self.live_unanchored_types.values do
370 all_unanchored.add_all(t)
371 end
372 var all_unanchored_types_colors = new HashMap[MType, Int]
373 for t in all_unanchored do
374 if unanchored_types_colors.has_key(t) then
375 all_unanchored_types_colors[t] = unanchored_types_colors[t]
376 else
377 all_unanchored_types_colors[t] = -1
378 end
379 end
380 self.compile_color_consts(all_unanchored_types_colors)
381
382 #print "tables"
383 #for k, v in unanchored_types_tables.as(not null) do
384 # print "{k}: {v.join(", ")}"
385 #end
386 #print ""
387 end
388
389 fun retieve_live_partial_types(mtype: MType) do
390 # add formal types arguments to mtypes
391 if mtype isa MGenericType then
392 for ft in mtype.arguments do
393 if ft.need_anchor then
394 print("Why do we need anchor here ?")
395 abort
396 end
397 self.partial_types.add(ft)
398 retieve_live_partial_types(ft)
399 end
400 end
401 var mclass_type: MClassType
402 if mtype isa MNullableType then
403 mclass_type = mtype.mtype.as(MClassType)
404 else
405 mclass_type = mtype.as(MClassType)
406 end
407
408 # add virtual types to mtypes
409 for vt in self.vt_tables[mclass_type.mclass] do
410 if vt != null then
411 var anchored = vt.bound.anchor_to(self.mainmodule, mclass_type)
412 self.partial_types.add(anchored)
413 end
414 end
415 end
416
417 # Separately compile all the method definitions of the module
418 fun compile_module_to_c(mmodule: MModule)
419 do
420 var old_module = self.mainmodule
421 self.mainmodule = mmodule
422 for cd in mmodule.mclassdefs do
423 for pd in cd.mpropdefs do
424 if not pd isa MMethodDef then continue
425 #print "compile {pd} @ {cd} @ {mmodule}"
426 var r = new SeparateRuntimeFunction(pd)
427 r.compile_to_c(self)
428 if true or cd.bound_mtype.ctype != "val*" then
429 var r2 = new VirtualRuntimeFunction(pd)
430 r2.compile_to_c(self)
431 end
432 end
433 end
434 self.mainmodule = old_module
435 end
436
437 # Globaly compile the type structure of a live type
438 fun compile_type_to_c(mtype: MType)
439 do
440 var c_name = mtype.c_name
441 var v = new SeparateCompilerVisitor(self)
442 v.add_decl("/* runtime type {mtype} */")
443
444 # extern const struct type_X
445 self.header.add_decl("extern const struct type_{c_name} type_{c_name};")
446 self.header.add_decl("struct type_{c_name} \{")
447 self.header.add_decl("int id;")
448 self.header.add_decl("const char *name;")
449 self.header.add_decl("int color;")
450 self.header.add_decl("short int is_nullable;")
451 self.header.add_decl("const struct types *unanchored_table;")
452 self.header.add_decl("int table_size;")
453 self.header.add_decl("int type_table[{self.type_tables[mtype].length}];")
454 self.header.add_decl("\};")
455
456 # const struct type_X
457 v.add_decl("const struct type_{c_name} type_{c_name} = \{")
458 v.add_decl("{self.typeids[mtype]},")
459 v.add_decl("\"{mtype}\", /* class_name_string */")
460 v.add_decl("{self.type_colors[mtype]},")
461 if mtype isa MNullableType then
462 v.add_decl("1,")
463 else
464 v.add_decl("0,")
465 end
466 if compile_type_unanchored_table(mtype) then
467 v.add_decl("(struct types*) &unanchored_table_{c_name},")
468 else
469 v.add_decl("NULL,")
470 end
471 v.add_decl("{self.type_tables[mtype].length},")
472 v.add_decl("\{")
473 for stype in self.type_tables[mtype] do
474 if stype == null then
475 v.add_decl("-1, /* empty */")
476 else
477 v.add_decl("{self.typeids[stype]}, /* {stype} */")
478 end
479 end
480 v.add_decl("\},")
481 v.add_decl("\};")
482 end
483
484 protected fun compile_type_fts_table(mtype: MType): Bool do
485
486 var mclass_type: MClassType
487 if mtype isa MNullableType then
488 mclass_type = mtype.mtype.as(MClassType)
489 else
490 mclass_type = mtype.as(MClassType)
491 end
492 if self.ft_tables[mclass_type.mclass].is_empty then return false
493
494 # extern const struct fst_table_X fst_table_X
495 self.header.add_decl("extern const struct fts_table_{mtype.c_name} fts_table_{mtype.c_name};")
496 self.header.add_decl("struct fts_table_{mtype.c_name} \{")
497 if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
498 self.header.add_decl("int mask;")
499 end
500 self.header.add_decl("struct type *types[{self.ft_tables[mclass_type.mclass].length}];")
501 self.header.add_decl("\};")
502
503 # const struct fts_table_X fts_table_X
504 var v = new_visitor
505 v.add_decl("const struct fts_table_{mtype.c_name} fts_table_{mtype.c_name} = \{")
506 if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
507 v.add_decl("{self.ft_masks[mclass_type.mclass]},")
508 end
509 v.add_decl("\{")
510 for ft in self.ft_tables[mclass_type.mclass] do
511 if ft == null then
512 v.add_decl("NULL, /* empty */")
513 else
514 var ntype: MType
515 if ft.mclass == mclass_type.mclass then
516 ntype = mclass_type.arguments[ft.rank]
517 else
518 ntype = ft.anchor_to(self.mainmodule, mclass_type)
519 end
520 if self.typeids.has_key(ntype) then
521 v.add_decl("(struct type*)&type_{ntype.c_name}, /* {ft} ({ntype}) */")
522 else
523 v.add_decl("NULL, /* empty ({ft} not a live type) */")
524 end
525 end
526 end
527 v.add_decl("\},")
528 v.add_decl("\};")
529 return true
530 end
531
532 protected fun compile_type_vts_table(mtype: MType): Bool do
533
534 var mclass_type: MClassType
535 if mtype isa MNullableType then
536 mclass_type = mtype.mtype.as(MClassType)
537 else
538 mclass_type = mtype.as(MClassType)
539 end
540 if self.vt_tables[mclass_type.mclass].is_empty then return false
541
542 # extern const struct vts_table_X vts_table_X
543 self.header.add_decl("extern const struct vts_table_{mtype.c_name} vts_table_{mtype.c_name};")
544 self.header.add_decl("struct vts_table_{mtype.c_name} \{")
545 if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
546 self.header.add_decl("int mask;")
547 end
548 self.header.add_decl("struct type *types[{self.vt_tables[mclass_type.mclass].length}];")
549 self.header.add_decl("\};")
550
551 # const struct vts_table_X vts_table_X
552 var v = new_visitor
553 v.add_decl("const struct vts_table_{mtype.c_name} vts_table_{mtype.c_name} = \{")
554 if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
555 v.add_decl("{vt_masks[mclass_type.mclass]},")
556 end
557 v.add_decl("\{")
558
559 for vt in self.vt_tables[mclass_type.mclass] do
560 if vt == null then
561 v.add_decl("NULL, /* empty */")
562 else
563 var bound = vt.bound
564 if bound == null then
565 #FIXME how can a bound be null here ?
566 print "No bound found for virtual type {vt} ?"
567 abort
568 else
569 var is_nullable = ""
570 if bound isa MNullableType then
571 bound = bound.mtype
572 is_nullable = "nullable_"
573 end
574 if bound isa MVirtualType then
575 bound = bound.anchor_to(self.mainmodule, mclass_type)
576 else if bound isa MParameterType then
577 bound = bound.anchor_to(self.mainmodule, mclass_type)
578 else if bound isa MGenericType and bound.need_anchor then
579 bound = bound.anchor_to(self.mainmodule, mclass_type)
580 else if bound isa MClassType then
581 else
582 print "NOT YET IMPLEMENTED: mtype_to_livetype with type: {bound}"
583 abort
584 end
585
586 if self.typeids.has_key(bound) then
587 v.add_decl("(struct type*)&type_{is_nullable}{bound.c_name}, /* {bound} */")
588 else
589 v.add_decl("NULL, /* dead type {bound} */")
590 end
591 end
592 end
593 end
594 v.add_decl("\},")
595 v.add_decl("\};")
596 return true
597 end
598
599 fun compile_type_unanchored_table(mtype: MType): Bool do
600
601 var mclass_type: MClassType
602 if mtype isa MNullableType then
603 mclass_type = mtype.mtype.as(MClassType)
604 else
605 mclass_type = mtype.as(MClassType)
606 end
607 if not self.unanchored_types_tables.has_key(mclass_type) then return false
608
609 # extern const struct unanchored_table_X unanchored_table_X
610 self.header.add_decl("extern const struct unanchored_table_{mtype.c_name} unanchored_table_{mtype.c_name};")
611
612 self.header.add_decl("struct unanchored_table_{mtype.c_name} \{")
613 if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
614 self.header.add_decl("int mask;")
615 end
616 self.header.add_decl("struct type *types[{self.unanchored_types_tables[mclass_type].length}];")
617 self.header.add_decl("\};")
618
619 # const struct fts_table_X fts_table_X
620 var v = new_visitor
621 v.add_decl("const struct unanchored_table_{mtype.c_name} unanchored_table_{mtype.c_name} = \{")
622 if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
623 v.add_decl("{self.unanchored_types_masks[mclass_type]},")
624 end
625 v.add_decl("\{")
626 for t in self.unanchored_types_tables[mclass_type] do
627 if t == null then
628 v.add_decl("NULL, /* empty */")
629 else
630 # The table stores the result of the type resolution
631 # Therefore, for a receiver `mclass_type`, and a unresolved type `t`
632 # the value stored is tv.
633 var tv = t.resolve_for(mclass_type, mclass_type, self.mainmodule, true)
634 # FIXME: What typeids means here? How can a tv not be live?
635 if self.typeids.has_key(tv) then
636 v.add_decl("(struct type*)&type_{tv.c_name}, /* {t}: {tv} */")
637 else
638 v.add_decl("NULL, /* empty ({t}: {tv} not a live type) */")
639 end
640 end
641 end
642 v.add_decl("\},")
643 v.add_decl("\};")
644 return true
645 end
646
647 # Globally compile the table of the class mclass
648 # In a link-time optimisation compiler, tables are globally computed
649 # In a true separate compiler (a with dynamic loading) you cannot do this unfortnally
650 fun compile_class_to_c(mclass: MClass)
651 do
652 var mtype = mclass.intro.bound_mtype
653 var c_name = mclass.c_name
654
655 var vft = self.method_tables[mclass]
656 var attrs = self.attr_tables[mclass]
657 var v = new_visitor
658
659 v.add_decl("/* runtime class {c_name} */")
660 var idnum = classids.length
661 var idname = "ID_" + c_name
662 self.classids[mtype] = idname
663 #self.header.add_decl("#define {idname} {idnum} /* {c_name} */")
664
665 self.header.add_decl("struct class_{c_name} \{")
666 self.header.add_decl("int box_kind;")
667 self.header.add_decl("nitmethod_t vft[{vft.length}];")
668 self.header.add_decl("\};")
669
670 # Build class vft
671 self.header.add_decl("extern const struct class_{c_name} class_{c_name};")
672 v.add_decl("const struct class_{c_name} class_{c_name} = \{")
673 v.add_decl("{self.box_kind_of(mclass)}, /* box_kind */")
674 v.add_decl("\{")
675 for i in [0 .. vft.length[ do
676 var mpropdef = vft[i]
677 if mpropdef == null then
678 v.add_decl("NULL, /* empty */")
679 else
680 if true or mpropdef.mclassdef.bound_mtype.ctype != "val*" then
681 v.add_decl("(nitmethod_t)VIRTUAL_{mpropdef.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
682 else
683 v.add_decl("(nitmethod_t){mpropdef.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
684 end
685 end
686 end
687 v.add_decl("\}")
688 v.add_decl("\};")
689
690 if mtype.ctype != "val*" then
691 #Build instance struct
692 self.header.add_decl("struct instance_{c_name} \{")
693 self.header.add_decl("const struct type *type;")
694 self.header.add_decl("const struct class *class;")
695 self.header.add_decl("{mtype.ctype} value;")
696 self.header.add_decl("\};")
697
698 if not self.runtime_type_analysis.live_types.has(mtype) then return
699
700 self.header.add_decl("val* BOX_{c_name}({mtype.ctype});")
701 v.add_decl("/* allocate {mtype} */")
702 v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value) \{")
703 v.add("struct instance_{c_name}*res = GC_MALLOC(sizeof(struct instance_{c_name}));")
704 v.add("res->type = (struct type*) &type_{c_name};")
705 v.add("res->class = (struct class*) &class_{c_name};")
706 v.add("res->value = value;")
707 v.add("return (val*)res;")
708 v.add("\}")
709 return
710 end
711
712 var is_native_array = mclass.name == "NativeArray"
713
714 var sig
715 if is_native_array then
716 sig = "int length, struct type* type"
717 else
718 sig = "struct type* type"
719 end
720
721 #Build instance struct
722 #extern const struct instance_array__NativeArray instance_array__NativeArray;
723 self.header.add_decl("struct instance_{c_name} \{")
724 self.header.add_decl("const struct type *type;")
725 self.header.add_decl("const struct class *class;")
726 self.header.add_decl("nitattribute_t attrs[{attrs.length}];")
727 if is_native_array then
728 # NativeArrays are just a instance header followed by an array of values
729 self.header.add_decl("val* values[0];")
730 end
731 self.header.add_decl("\};")
732
733
734 self.header.add_decl("{mtype.ctype} NEW_{c_name}({sig});")
735 v.add_decl("/* allocate {mtype} */")
736 v.add_decl("{mtype.ctype} NEW_{c_name}({sig}) \{")
737 var res = v.new_named_var(mtype, "self")
738 res.is_exact = true
739 if is_native_array then
740 var mtype_elt = mtype.arguments.first
741 v.add("{res} = GC_MALLOC(sizeof(struct instance_{c_name}) + length*sizeof({mtype_elt.ctype}));")
742 else
743 v.add("{res} = GC_MALLOC(sizeof(struct instance_{c_name}));")
744 end
745 v.add("{res}->type = type;")
746 if v.compiler.modelbuilder.toolcontext.opt_hardening.value then
747 v.add("if(type == NULL) \{")
748 v.add_abort("type null")
749 v.add("\}")
750 v.add("if(type->unanchored_table == NULL) \{")
751 v.add("fprintf(stderr, \"Insantiation of a dead type: %s\\n\", type->name);")
752 v.add_abort("type dead")
753 v.add("\}")
754 end
755 v.add("{res}->class = (struct class*) &class_{c_name};")
756
757 self.generate_init_attr(v, res, mtype)
758 v.add("return {res};")
759 v.add("\}")
760
761 generate_check_init_instance(mtype)
762 end
763
764 redef fun generate_check_init_instance(mtype)
765 do
766 if self.modelbuilder.toolcontext.opt_no_check_initialization.value then return
767
768 var v = self.new_visitor
769 var c_name = mtype.mclass.c_name
770 var res = new RuntimeVariable("self", mtype, mtype)
771 self.header.add_decl("void CHECK_NEW_{c_name}({mtype.ctype});")
772 v.add_decl("/* allocate {mtype} */")
773 v.add_decl("void CHECK_NEW_{c_name}({mtype.ctype} {res}) \{")
774 self.generate_check_attr(v, res, mtype)
775 v.add("\}")
776 end
777
778 redef fun new_visitor do return new SeparateCompilerVisitor(self)
779
780 # Stats
781
782 redef fun display_stats
783 do
784 super
785 if self.modelbuilder.toolcontext.opt_typing_table_metrics.value then
786 display_sizes
787 end
788 end
789
790 fun display_sizes
791 do
792 print "# size of tables"
793 print "\trs size\trs hole\tst size\tst hole"
794 var rt_table = 0
795 var rt_holes = 0
796 var st_table = 0
797 var st_holes = 0
798 var rtables = unanchored_types_tables
799 if rtables != null then
800 for unanch, table in rtables do
801 rt_table += table.length
802 for e in table do if e == null then rt_holes += 1
803 end
804 end
805
806 var ttables = type_tables
807 if ttables != null then
808 for t, table in ttables do
809 st_table += table.length
810 for e in table do if e == null then st_holes += 1
811 end
812 end
813 print "\t{rt_table}\t{rt_holes}\t{st_table}\t{st_holes}"
814 end
815 end
816
817 # A visitor on the AST of property definition that generate the C code of a separate compilation process.
818 class SeparateCompilerVisitor
819 super AbstractCompilerVisitor
820
821 redef type COMPILER: SeparateCompiler
822
823 redef fun adapt_signature(m, args)
824 do
825 var msignature = m.msignature.resolve_for(m.mclassdef.bound_mtype, m.mclassdef.bound_mtype, m.mclassdef.mmodule, true)
826 var recv = args.first
827 if recv.mtype.ctype != m.mclassdef.mclass.mclass_type.ctype then
828 args.first = self.autobox(args.first, m.mclassdef.mclass.mclass_type)
829 end
830 for i in [0..msignature.arity[ do
831 var t = msignature.mparameters[i].mtype
832 if i == msignature.vararg_rank then
833 t = args[i+1].mtype
834 end
835 args[i+1] = self.autobox(args[i+1], t)
836 end
837 end
838
839 redef fun autobox(value, mtype)
840 do
841 if value.mtype == mtype then
842 return value
843 else if value.mtype.ctype == "val*" and mtype.ctype == "val*" then
844 return value
845 else if value.mtype.ctype == "val*" then
846 return self.new_expr("((struct instance_{mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
847 else if mtype.ctype == "val*" then
848 var valtype = value.mtype.as(MClassType)
849 var res = self.new_var(mtype)
850 if not compiler.runtime_type_analysis.live_types.has(valtype) then
851 self.add("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */")
852 self.add("printf(\"Dead code executed!\\n\"); exit(1);")
853 return res
854 end
855 self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
856 return res
857 else
858 # Bad things will appen!
859 var res = self.new_var(mtype)
860 self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */")
861 self.add("printf(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); exit(1);")
862 return res
863 end
864 end
865
866 # Return a C expression returning the runtime type structure of the value
867 # The point of the method is to works also with primitives types.
868 fun type_info(value: RuntimeVariable): String
869 do
870 if value.mtype.ctype == "val*" then
871 return "{value}->type"
872 else
873 return "(&type_{value.mtype.c_name})"
874 end
875 end
876
877 redef fun send(mmethod, arguments)
878 do
879 if arguments.first.mcasttype.ctype != "val*" then
880 return self.monomorphic_send(mmethod, arguments.first.mcasttype, arguments)
881 end
882
883 var res: nullable RuntimeVariable
884 var msignature = mmethod.intro.msignature.resolve_for(mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.mmodule, true)
885 var ret = msignature.return_mtype
886 if mmethod.is_new then
887 ret = arguments.first.mtype
888 res = self.new_var(ret)
889 else if ret == null then
890 res = null
891 else
892 res = self.new_var(ret)
893 end
894
895 var s = new Buffer
896 var ss = new Buffer
897
898 var recv = arguments.first
899 s.append("val*")
900 ss.append("{recv}")
901 self.varargize(mmethod.intro, mmethod.intro.msignature.as(not null), arguments)
902 for i in [0..msignature.arity[ do
903 var a = arguments[i+1]
904 var t = msignature.mparameters[i].mtype
905 if i == msignature.vararg_rank then
906 t = arguments[i+1].mcasttype
907 end
908 s.append(", {t.ctype}")
909 a = self.autobox(a, t)
910 ss.append(", {a}")
911 end
912
913 var consider_null = not self.compiler.modelbuilder.toolcontext.opt_no_check_other.value or mmethod.name == "==" or mmethod.name == "!="
914 var maybenull = recv.mcasttype isa MNullableType and consider_null
915 if maybenull then
916 self.add("if ({recv} == NULL) \{")
917 if mmethod.name == "==" then
918 assert res != null
919 var arg = arguments[1]
920 if arg.mcasttype isa MNullableType then
921 self.add("{res} = ({arg} == NULL);")
922 else if arg.mcasttype isa MNullType then
923 self.add("{res} = 1; /* is null */")
924 else
925 self.add("{res} = 0; /* {arg.inspect} cannot be null */")
926 end
927 else if mmethod.name == "!=" then
928 assert res != null
929 var arg = arguments[1]
930 if arg.mcasttype isa MNullableType then
931 self.add("{res} = ({arg} != NULL);")
932 else if arg.mcasttype isa MNullType then
933 self.add("{res} = 0; /* is null */")
934 else
935 self.add("{res} = 1; /* {arg.inspect} cannot be null */")
936 end
937 else
938 self.add_abort("Reciever is null")
939 end
940 self.add("\} else \{")
941 end
942 if not self.compiler.modelbuilder.toolcontext.opt_no_shortcut_equate.value and (mmethod.name == "==" or mmethod.name == "!=") then
943 assert res != null
944 # Recv is not null, thus is arg is, it is easy to conclude (and respect the invariants)
945 var arg = arguments[1]
946 if arg.mcasttype isa MNullType then
947 if mmethod.name == "==" then
948 self.add("{res} = 0; /* arg is null but recv is not */")
949 else
950 self.add("{res} = 1; /* arg is null and recv is not */")
951 end
952 if maybenull then
953 self.add("\}")
954 end
955 return res
956 end
957 end
958
959 var r
960 if ret == null then r = "void" else r = ret.ctype
961 var call = "(({r} (*)({s}))({arguments.first}->class->vft[{mmethod.const_color}]))({ss}) /* {mmethod} on {arguments.first.inspect}*/"
962
963 if res != null then
964 self.add("{res} = {call};")
965 else
966 self.add("{call};")
967 end
968
969 if maybenull then
970 self.add("\}")
971 end
972
973 return res
974 end
975
976 redef fun call(mmethoddef, recvtype, arguments)
977 do
978 var res: nullable RuntimeVariable
979 var ret = mmethoddef.msignature.return_mtype
980 if mmethoddef.mproperty.is_new then
981 ret = arguments.first.mtype
982 res = self.new_var(ret)
983 else if ret == null then
984 res = null
985 else
986 ret = ret.resolve_for(mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.mmodule, true)
987 res = self.new_var(ret)
988 end
989
990 if self.compiler.modelbuilder.mpropdef2npropdef.has_key(mmethoddef) and
991 self.compiler.modelbuilder.mpropdef2npropdef[mmethoddef] isa AInternMethPropdef and
992 not compiler.modelbuilder.toolcontext.opt_no_inline_intern.value then
993 var frame = new Frame(self, mmethoddef, recvtype, arguments)
994 frame.returnlabel = self.get_name("RET_LABEL")
995 frame.returnvar = res
996 var old_frame = self.frame
997 self.frame = frame
998 self.add("\{ /* Inline {mmethoddef} ({arguments.join(",")}) */")
999 mmethoddef.compile_inside_to_c(self, arguments)
1000 self.add("{frame.returnlabel.as(not null)}:(void)0;")
1001 self.add("\}")
1002 self.frame = old_frame
1003 return res
1004 end
1005
1006 # Autobox arguments
1007 self.adapt_signature(mmethoddef, arguments)
1008
1009 if res == null then
1010 self.add("{mmethoddef.c_name}({arguments.join(", ")});")
1011 return null
1012 else
1013 self.add("{res} = {mmethoddef.c_name}({arguments.join(", ")});")
1014 end
1015
1016 return res
1017 end
1018
1019 redef fun vararg_instance(mpropdef, recv, varargs, elttype)
1020 do
1021 # A vararg must be stored into an new array
1022 # The trick is that the dymaic type of the array may depends on the receiver
1023 # of the method (ie recv) if the static type is unresolved
1024 # This is more complex than usual because the unanchored type must not be resolved
1025 # with the current receiver (ie self).
1026 # Therefore to isolate the resolution from self, a local Frame is created.
1027 # One can see this implementation as an inlined method of the receiver whose only
1028 # job is to allocate the array
1029 var old_frame = self.frame
1030 var frame = new Frame(self, mpropdef, mpropdef.mclassdef.bound_mtype, [recv])
1031 self.frame = frame
1032 #print "required Array[{elttype}] for recv {recv.inspect}. bound=Array[{self.resolve_for(elttype, recv)}]. selfvar={frame.arguments.first.inspect}"
1033 var res = self.array_instance(varargs, elttype)
1034 self.frame = old_frame
1035 return res
1036 end
1037
1038 redef fun isset_attribute(a, recv)
1039 do
1040 self.check_recv_notnull(recv)
1041 var res = self.new_var(bool_type)
1042
1043 # What is the declared type of the attribute?
1044 var mtype = a.intro.static_mtype.as(not null)
1045 var intromclassdef = a.intro.mclassdef
1046 mtype = mtype.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
1047
1048 if mtype isa MNullableType then
1049 self.add("{res} = 1; /* easy isset: {a} on {recv.inspect} */")
1050 return res
1051 end
1052
1053 if self.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then
1054 self.add("{res} = {recv}->attrs[{a.const_color}] != NULL; /* {a} on {recv.inspect}*/")
1055 else
1056
1057 if mtype.ctype == "val*" then
1058 self.add("{res} = {recv}->attrs[{a.const_color}].val != NULL; /* {a} on {recv.inspect} */")
1059 else
1060 self.add("{res} = 1; /* NOT YET IMPLEMENTED: isset of primitives: {a} on {recv.inspect} */")
1061 end
1062 end
1063 return res
1064 end
1065
1066 redef fun read_attribute(a, recv)
1067 do
1068 self.check_recv_notnull(recv)
1069
1070 # What is the declared type of the attribute?
1071 var ret = a.intro.static_mtype.as(not null)
1072 var intromclassdef = a.intro.mclassdef
1073 ret = ret.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
1074
1075 if self.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then
1076 # Get the attribute or a box (ie. always a val*)
1077 var cret = self.object_type.as_nullable
1078 var res = self.new_var(cret)
1079 res.mcasttype = ret
1080
1081 self.add("{res} = {recv}->attrs[{a.const_color}]; /* {a} on {recv.inspect} */")
1082
1083 # Check for Uninitialized attribute
1084 if not ret isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_initialization.value then
1085 self.add("if ({res} == NULL) \{")
1086 self.add_abort("Uninitialized attribute {a.name}")
1087 self.add("\}")
1088 end
1089
1090 # Return the attribute or its unboxed version
1091 # Note: it is mandatory since we reuse the box on write, we do not whant that the box escapes
1092 return self.autobox(res, ret)
1093 else
1094 var res = self.new_var(ret)
1095 self.add("{res} = {recv}->attrs[{a.const_color}].{ret.ctypename}; /* {a} on {recv.inspect} */")
1096
1097 # Check for Uninitialized attribute
1098 if ret.ctype == "val*" and not ret isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_initialization.value then
1099 self.add("if ({res} == NULL) \{")
1100 self.add_abort("Uninitialized attribute {a.name}")
1101 self.add("\}")
1102 end
1103
1104 return res
1105 end
1106 end
1107
1108 redef fun write_attribute(a, recv, value)
1109 do
1110 self.check_recv_notnull(recv)
1111
1112 # What is the declared type of the attribute?
1113 var mtype = a.intro.static_mtype.as(not null)
1114 var intromclassdef = a.intro.mclassdef
1115 mtype = mtype.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
1116
1117 # Adapt the value to the declared type
1118 value = self.autobox(value, mtype)
1119
1120 if self.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then
1121 var attr = "{recv}->attrs[{a.const_color}]"
1122 if mtype.ctype != "val*" then
1123 assert mtype isa MClassType
1124 # The attribute is primitive, thus we store it in a box
1125 # The trick is to create the box the first time then resuse the box
1126 self.add("if ({attr} != NULL) \{")
1127 self.add("((struct instance_{mtype.c_name}*){attr})->value = {value}; /* {a} on {recv.inspect} */")
1128 self.add("\} else \{")
1129 value = self.autobox(value, self.object_type.as_nullable)
1130 self.add("{attr} = {value}; /* {a} on {recv.inspect} */")
1131 self.add("\}")
1132 else
1133 # The attribute is not primitive, thus store it direclty
1134 self.add("{attr} = {value}; /* {a} on {recv.inspect} */")
1135 end
1136 else
1137 self.add("{recv}->attrs[{a.const_color}].{mtype.ctypename} = {value}; /* {a} on {recv.inspect} */")
1138 end
1139 end
1140
1141 # Build livetype structure retrieving
1142 # ENSURE: mtype.need_anchor
1143 fun retrieve_anchored_livetype(mtype: MGenericType, buffer: Buffer) do
1144 assert mtype.need_anchor
1145
1146 var compiler = self.compiler
1147 for ft in mtype.arguments do
1148
1149 var ntype = ft
1150 var s: String = ""
1151 if ntype isa MNullableType then
1152 ntype = ntype.mtype
1153 end
1154
1155 var recv = self.frame.arguments.first
1156 var recv_type_info = self.type_info(recv)
1157 if ntype isa MParameterType then
1158 if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
1159 buffer.append("[{recv_type_info}->fts_table->types[HASH({recv_type_info}->fts_table->mask, {ntype.const_color})]->livecolor]")
1160 else
1161 buffer.append("[{recv_type_info}->fts_table->types[{ntype.const_color}]->livecolor]")
1162 end
1163 else if ntype isa MVirtualType then
1164 if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
1165 buffer.append("[{recv_type_info}->vts_table->types[HASH({recv_type_info}->vts_table->mask, {ntype.mproperty.const_color})]->livecolor]")
1166 else
1167 buffer.append("[{recv_type_info}->vts_table->types[{ntype.mproperty.const_color}]->livecolor]")
1168 end
1169 else if ntype isa MGenericType and ntype.need_anchor then
1170 var bbuff = new Buffer
1171 retrieve_anchored_livetype(ntype, bbuff)
1172 buffer.append("[livetypes_{ntype.mclass.c_name}{bbuff.to_s}->livecolor]")
1173 else if ntype isa MClassType then
1174 compiler.undead_types.add(ft)
1175 buffer.append("[type_{ft.c_name}.livecolor]")
1176 else
1177 self.add("printf(\"NOT YET IMPLEMENTED: init_instance(%s, {mtype}).\\n\", \"{ft}\"); exit(1);")
1178 end
1179 end
1180 end
1181
1182 redef fun init_instance(mtype)
1183 do
1184 var compiler = self.compiler
1185 if mtype isa MGenericType and mtype.need_anchor then
1186 link_unanchored_type(self.frame.mpropdef.mclassdef, mtype)
1187 var recv = self.frame.arguments.first
1188 var recv_type_info = self.type_info(recv)
1189 if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
1190 return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) {recv_type_info}->unanchored_table->types[HASH({recv_type_info}->unanchored_table->mask, {mtype.const_color})])", mtype)
1191 else
1192 return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) {recv_type_info}->unanchored_table->types[{mtype.const_color}])", mtype)
1193 end
1194 end
1195 compiler.undead_types.add(mtype)
1196 return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) &type_{mtype.c_name})", mtype)
1197 end
1198
1199 redef fun check_init_instance(value, mtype)
1200 do
1201 if self.compiler.modelbuilder.toolcontext.opt_no_check_initialization.value then return
1202 self.add("CHECK_NEW_{mtype.mclass.c_name}({value});")
1203 end
1204
1205 redef fun type_test(value, mtype, tag)
1206 do
1207 self.add("/* {value.inspect} isa {mtype} */")
1208 var compiler = self.compiler
1209
1210 var recv = self.frame.arguments.first
1211 var recv_type_info = self.type_info(recv)
1212
1213 var res = self.new_var(bool_type)
1214
1215 var cltype = self.get_name("cltype")
1216 self.add_decl("int {cltype};")
1217 var idtype = self.get_name("idtype")
1218 self.add_decl("int {idtype};")
1219
1220 var maybe_null = self.maybe_null(value)
1221 var accept_null = "0"
1222 var ntype = mtype
1223 if ntype isa MNullableType then
1224 ntype = ntype.mtype
1225 accept_null = "1"
1226 end
1227
1228 if value.mcasttype.is_subtype(self.frame.mpropdef.mclassdef.mmodule, self.frame.mpropdef.mclassdef.bound_mtype, mtype) then
1229 self.add("{res} = 1; /* easy {value.inspect} isa {mtype}*/")
1230 if compiler.modelbuilder.toolcontext.opt_typing_test_metrics.value then
1231 self.compiler.count_type_test_skipped[tag] += 1
1232 self.add("count_type_test_skipped_{tag}++;")
1233 end
1234 return res
1235 end
1236
1237 if ntype.need_anchor then
1238 var type_struct = self.get_name("type_struct")
1239 self.add_decl("struct type* {type_struct};")
1240
1241 # Either with unanchored_table with a direct resolution
1242 link_unanchored_type(self.frame.mpropdef.mclassdef, ntype)
1243 if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
1244 self.add("{type_struct} = {recv_type_info}->unanchored_table->types[HASH({recv_type_info}->unanchored_table->mask, {ntype.const_color})];")
1245 else
1246 self.add("{type_struct} = {recv_type_info}->unanchored_table->types[{ntype.const_color}];")
1247 end
1248 if compiler.modelbuilder.toolcontext.opt_typing_test_metrics.value then
1249 self.compiler.count_type_test_unresolved[tag] += 1
1250 self.add("count_type_test_unresolved_{tag}++;")
1251 end
1252 self.add("{cltype} = {type_struct}->color;")
1253 self.add("{idtype} = {type_struct}->id;")
1254 if maybe_null and accept_null == "0" then
1255 var is_nullable = self.get_name("is_nullable")
1256 self.add_decl("short int {is_nullable};")
1257 self.add("{is_nullable} = {type_struct}->is_nullable;")
1258 accept_null = is_nullable.to_s
1259 end
1260 else if ntype isa MClassType then
1261 compiler.undead_types.add(mtype)
1262 self.add("{cltype} = type_{mtype.c_name}.color;")
1263 self.add("{idtype} = type_{mtype.c_name}.id;")
1264 if compiler.modelbuilder.toolcontext.opt_typing_test_metrics.value then
1265 self.compiler.count_type_test_resolved[tag] += 1
1266 self.add("count_type_test_resolved_{tag}++;")
1267 end
1268 else
1269 self.add("printf(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{value.inspect}\"); exit(1);")
1270 end
1271
1272 # check color is in table
1273 if maybe_null then
1274 self.add("if({value} == NULL) \{")
1275 self.add("{res} = {accept_null};")
1276 self.add("\} else \{")
1277 end
1278 var value_type_info = self.type_info(value)
1279 if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
1280 self.add("{cltype} = HASH({value_type_info}->color, {idtype});")
1281 end
1282 self.add("if({cltype} >= {value_type_info}->table_size) \{")
1283 self.add("{res} = 0;")
1284 self.add("\} else \{")
1285 self.add("{res} = {value_type_info}->type_table[{cltype}] == {idtype};")
1286 self.add("\}")
1287 if maybe_null then
1288 self.add("\}")
1289 end
1290
1291 return res
1292 end
1293
1294 redef fun is_same_type_test(value1, value2)
1295 do
1296 var res = self.new_var(bool_type)
1297 # Swap values to be symetric
1298 if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
1299 var tmp = value1
1300 value1 = value2
1301 value2 = tmp
1302 end
1303 if value1.mtype.ctype != "val*" then
1304 if value2.mtype == value1.mtype then
1305 self.add("{res} = 1; /* is_same_type_test: compatible types {value1.mtype} vs. {value2.mtype} */")
1306 else if value2.mtype.ctype != "val*" then
1307 self.add("{res} = 0; /* is_same_type_test: incompatible types {value1.mtype} vs. {value2.mtype}*/")
1308 else
1309 var mtype1 = value1.mtype.as(MClassType)
1310 self.add("{res} = ({value2} != NULL) && ({value2}->class == (struct class*) &class_{mtype1.c_name}); /* is_same_type_test */")
1311 end
1312 else
1313 self.add("{res} = ({value1} == {value2}) || ({value1} != NULL && {value2} != NULL && {value1}->class == {value2}->class); /* is_same_type_test */")
1314 end
1315 return res
1316 end
1317
1318 redef fun class_name_string(value)
1319 do
1320 var res = self.get_name("var_class_name")
1321 self.add_decl("const char* {res};")
1322 if value.mtype.ctype == "val*" then
1323 self.add "{res} = {value} == NULL ? \"null\" : {value}->type->name;"
1324 else
1325 self.add "{res} = type_{value.mtype.c_name}.name;"
1326 end
1327 return res
1328 end
1329
1330 redef fun equal_test(value1, value2)
1331 do
1332 var res = self.new_var(bool_type)
1333 if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
1334 var tmp = value1
1335 value1 = value2
1336 value2 = tmp
1337 end
1338 if value1.mtype.ctype != "val*" then
1339 if value2.mtype == value1.mtype then
1340 self.add("{res} = {value1} == {value2};")
1341 else if value2.mtype.ctype != "val*" then
1342 self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
1343 else
1344 var mtype1 = value1.mtype.as(MClassType)
1345 self.add("{res} = ({value2} != NULL) && ({value2}->class == (struct class*) &class_{mtype1.c_name});")
1346 self.add("if ({res}) \{")
1347 self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
1348 self.add("\}")
1349 end
1350 return res
1351 end
1352 var maybe_null = true
1353 var test = new Array[String]
1354 var t1 = value1.mcasttype
1355 if t1 isa MNullableType then
1356 test.add("{value1} != NULL")
1357 t1 = t1.mtype
1358 else
1359 maybe_null = false
1360 end
1361 var t2 = value2.mcasttype
1362 if t2 isa MNullableType then
1363 test.add("{value2} != NULL")
1364 t2 = t2.mtype
1365 else
1366 maybe_null = false
1367 end
1368
1369 var incompatible = false
1370 var primitive
1371 if t1.ctype != "val*" then
1372 primitive = t1
1373 if t1 == t2 then
1374 # No need to compare class
1375 else if t2.ctype != "val*" then
1376 incompatible = true
1377 else if can_be_primitive(value2) then
1378 test.add("{value1}->class == {value2}->class")
1379 else
1380 incompatible = true
1381 end
1382 else if t2.ctype != "val*" then
1383 primitive = t2
1384 if can_be_primitive(value1) then
1385 test.add("{value1}->class == {value2}->class")
1386 else
1387 incompatible = true
1388 end
1389 else
1390 primitive = null
1391 end
1392
1393 if incompatible then
1394 if maybe_null then
1395 self.add("{res} = {value1} == {value2}; /* incompatible types {t1} vs. {t2}; but may be NULL*/")
1396 return res
1397 else
1398 self.add("{res} = 0; /* incompatible types {t1} vs. {t2}; cannot be NULL */")
1399 return res
1400 end
1401 end
1402 if primitive != null then
1403 test.add("((struct instance_{primitive.c_name}*){value1})->value == ((struct instance_{primitive.c_name}*){value2})->value")
1404 else if can_be_primitive(value1) and can_be_primitive(value2) then
1405 test.add("{value1}->class == {value2}->class")
1406 var s = new Array[String]
1407 for t, v in self.compiler.box_kinds do
1408 s.add "({value1}->class->box_kind == {v} && ((struct instance_{t.c_name}*){value1})->value == ((struct instance_{t.c_name}*){value2})->value)"
1409 end
1410 test.add("({s.join(" || ")})")
1411 else
1412 self.add("{res} = {value1} == {value2};")
1413 return res
1414 end
1415 self.add("{res} = {value1} == {value2} || ({test.join(" && ")});")
1416 return res
1417 end
1418
1419 fun can_be_primitive(value: RuntimeVariable): Bool
1420 do
1421 var t = value.mcasttype
1422 if t isa MNullableType then t = t.mtype
1423 if not t isa MClassType then return false
1424 var k = t.mclass.kind
1425 return k == interface_kind or t.ctype != "val*"
1426 end
1427
1428 fun maybe_null(value: RuntimeVariable): Bool
1429 do
1430 var t = value.mcasttype
1431 return t isa MNullableType or t isa MNullType
1432 end
1433
1434 redef fun array_instance(array, elttype)
1435 do
1436 var nclass = self.get_class("NativeArray")
1437 var arrayclass = self.get_class("Array")
1438 var arraytype = arrayclass.get_mtype([elttype])
1439 var res = self.init_instance(arraytype)
1440 self.add("\{ /* {res} = array_instance Array[{elttype}] */")
1441 var length = self.int_instance(array.length)
1442 var nat = native_array_instance(elttype, length)
1443 for i in [0..array.length[ do
1444 var r = self.autobox(array[i], self.object_type)
1445 self.add("((struct instance_{nclass.c_name}*){nat})->values[{i}] = (val*) {r};")
1446 end
1447 self.send(self.get_property("with_native", arrayclass.intro.bound_mtype), [res, nat, length])
1448 self.check_init_instance(res, arraytype)
1449 self.add("\}")
1450 return res
1451 end
1452
1453 fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable
1454 do
1455 var mtype = self.get_class("NativeArray").get_mtype([elttype])
1456 assert mtype isa MGenericType
1457 var compiler = self.compiler
1458 if mtype.need_anchor then
1459 link_unanchored_type(self.frame.mpropdef.mclassdef, mtype)
1460 var recv = self.frame.arguments.first
1461 var recv_type_info = self.type_info(recv)
1462 if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
1463 return self.new_expr("NEW_{mtype.mclass.c_name}({length}, (struct type *) {recv_type_info}->unanchored_table->types[HASH({recv_type_info}->unanchored_table->mask, {mtype.const_color})])", mtype)
1464 else
1465 return self.new_expr("NEW_{mtype.mclass.c_name}({length}, (struct type *) {recv_type_info}->unanchored_table->types[{mtype.const_color}])", mtype)
1466 end
1467 end
1468 compiler.undead_types.add(mtype)
1469 return self.new_expr("NEW_{mtype.mclass.c_name}({length}, (struct type *) &type_{mtype.c_name})", mtype)
1470 end
1471
1472 redef fun native_array_def(pname, ret_type, arguments)
1473 do
1474 var elttype = arguments.first.mtype
1475 var nclass = self.get_class("NativeArray")
1476 var recv = "((struct instance_{nclass.c_name}*){arguments[0]})->values"
1477 if pname == "[]" then
1478 self.ret(self.new_expr("{recv}[{arguments[1]}]", ret_type.as(not null)))
1479 return
1480 else if pname == "[]=" then
1481 self.add("{recv}[{arguments[1]}]={arguments[2]};")
1482 return
1483 else if pname == "copy_to" then
1484 var recv1 = "((struct instance_{nclass.c_name}*){arguments[1]})->values"
1485 self.add("memcpy({recv1}, {recv}, {arguments[2]}*sizeof({elttype.ctype}));")
1486 return
1487 end
1488 end
1489
1490 redef fun calloc_array(ret_type, arguments)
1491 do
1492 var mclass = self.get_class("ArrayCapable")
1493 var ft = mclass.mclass_type.arguments.first.as(MParameterType)
1494 var res = self.native_array_instance(ft, arguments[1])
1495 self.ret(res)
1496 end
1497
1498 fun link_unanchored_type(mclassdef: MClassDef, mtype: MType) do
1499 assert mtype.need_anchor
1500 var compiler = self.compiler
1501 if not compiler.live_unanchored_types.has_key(self.frame.mpropdef.mclassdef) then
1502 compiler.live_unanchored_types[self.frame.mpropdef.mclassdef] = new HashSet[MType]
1503 end
1504 compiler.live_unanchored_types[self.frame.mpropdef.mclassdef].add(mtype)
1505 end
1506 end
1507
1508 # The C function associated to a methoddef separately compiled
1509 class SeparateRuntimeFunction
1510 super AbstractRuntimeFunction
1511
1512 redef fun build_c_name: String do return "{mmethoddef.c_name}"
1513
1514 redef fun to_s do return self.mmethoddef.to_s
1515
1516 redef fun compile_to_c(compiler)
1517 do
1518 var mmethoddef = self.mmethoddef
1519
1520 var recv = self.mmethoddef.mclassdef.bound_mtype
1521 var v = compiler.new_visitor
1522 var selfvar = new RuntimeVariable("self", recv, recv)
1523 var arguments = new Array[RuntimeVariable]
1524 var frame = new Frame(v, mmethoddef, recv, arguments)
1525 v.frame = frame
1526
1527 var msignature = mmethoddef.msignature.resolve_for(mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.mmodule, true)
1528
1529 var sig = new Buffer
1530 var comment = new Buffer
1531 var ret = msignature.return_mtype
1532 if ret != null then
1533 sig.append("{ret.ctype} ")
1534 else if mmethoddef.mproperty.is_new then
1535 ret = recv
1536 sig.append("{ret.ctype} ")
1537 else
1538 sig.append("void ")
1539 end
1540 sig.append(self.c_name)
1541 sig.append("({selfvar.mtype.ctype} {selfvar}")
1542 comment.append("(self: {selfvar}")
1543 arguments.add(selfvar)
1544 for i in [0..msignature.arity[ do
1545 var mtype = msignature.mparameters[i].mtype
1546 if i == msignature.vararg_rank then
1547 mtype = v.get_class("Array").get_mtype([mtype])
1548 end
1549 comment.append(", {mtype}")
1550 sig.append(", {mtype.ctype} p{i}")
1551 var argvar = new RuntimeVariable("p{i}", mtype, mtype)
1552 arguments.add(argvar)
1553 end
1554 sig.append(")")
1555 comment.append(")")
1556 if ret != null then
1557 comment.append(": {ret}")
1558 end
1559 compiler.header.add_decl("{sig};")
1560
1561 v.add_decl("/* method {self} for {comment} */")
1562 v.add_decl("{sig} \{")
1563 if ret != null then
1564 frame.returnvar = v.new_var(ret)
1565 end
1566 frame.returnlabel = v.get_name("RET_LABEL")
1567
1568 if recv != arguments.first.mtype then
1569 #print "{self} {recv} {arguments.first}"
1570 end
1571 mmethoddef.compile_inside_to_c(v, arguments)
1572
1573 v.add("{frame.returnlabel.as(not null)}:;")
1574 if ret != null then
1575 v.add("return {frame.returnvar.as(not null)};")
1576 end
1577 v.add("\}")
1578 end
1579 end
1580
1581 # The C function associated to a methoddef on a primitive type, stored into a VFT of a class
1582 # The first parameter (the reciever) is always typed by val* in order to accept an object value
1583 class VirtualRuntimeFunction
1584 super AbstractRuntimeFunction
1585
1586 redef fun build_c_name: String do return "VIRTUAL_{mmethoddef.c_name}"
1587
1588 redef fun to_s do return self.mmethoddef.to_s
1589
1590 redef fun compile_to_c(compiler)
1591 do
1592 var mmethoddef = self.mmethoddef
1593
1594 var recv = self.mmethoddef.mclassdef.bound_mtype
1595 var v = compiler.new_visitor
1596 var selfvar = new RuntimeVariable("self", v.object_type, recv)
1597 var arguments = new Array[RuntimeVariable]
1598 var frame = new Frame(v, mmethoddef, recv, arguments)
1599 v.frame = frame
1600
1601 var sig = new Buffer
1602 var comment = new Buffer
1603
1604 # Because the function is virtual, the signature must match the one of the original class
1605 var intromclassdef = self.mmethoddef.mproperty.intro.mclassdef
1606 var msignature = mmethoddef.mproperty.intro.msignature.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
1607 var ret = msignature.return_mtype
1608 if ret != null then
1609 sig.append("{ret.ctype} ")
1610 else if mmethoddef.mproperty.is_new then
1611 ret = recv
1612 sig.append("{ret.ctype} ")
1613 else
1614 sig.append("void ")
1615 end
1616 sig.append(self.c_name)
1617 sig.append("({selfvar.mtype.ctype} {selfvar}")
1618 comment.append("(self: {selfvar}")
1619 arguments.add(selfvar)
1620 for i in [0..msignature.arity[ do
1621 var mtype = msignature.mparameters[i].mtype
1622 if i == msignature.vararg_rank then
1623 mtype = v.get_class("Array").get_mtype([mtype])
1624 end
1625 comment.append(", {mtype}")
1626 sig.append(", {mtype.ctype} p{i}")
1627 var argvar = new RuntimeVariable("p{i}", mtype, mtype)
1628 arguments.add(argvar)
1629 end
1630 sig.append(")")
1631 comment.append(")")
1632 if ret != null then
1633 comment.append(": {ret}")
1634 end
1635 compiler.header.add_decl("{sig};")
1636
1637 v.add_decl("/* method {self} for {comment} */")
1638 v.add_decl("{sig} \{")
1639 if ret != null then
1640 frame.returnvar = v.new_var(ret)
1641 end
1642 frame.returnlabel = v.get_name("RET_LABEL")
1643
1644 if recv != arguments.first.mtype then
1645 #print "{self} {recv} {arguments.first}"
1646 end
1647 mmethoddef.compile_inside_to_c(v, arguments)
1648
1649 v.add("{frame.returnlabel.as(not null)}:;")
1650 if ret != null then
1651 v.add("return {frame.returnvar.as(not null)};")
1652 end
1653 v.add("\}")
1654 end
1655
1656 # TODO ?
1657 redef fun call(v, arguments) do abort
1658 end
1659
1660 redef class MType
1661 fun const_color: String do return "COLOR_{c_name}"
1662 end
1663
1664 redef class MProperty
1665 fun const_color: String do return "COLOR_{c_name}"
1666 end