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