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