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