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