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