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