src: remove remaining references of subclasses on AMethPropdef
[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 import layout_builders
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 (semi-global)", "--inline-coloring-numbers")
34 # --inline-some-methods
35 var opt_inline_some_methods: OptionBool = new OptionBool("Allow the separate compiler to inline some methods (semi-global)", "--inline-some-methods")
36 # --direct-call-monomorph
37 var opt_direct_call_monomorph: OptionBool = new OptionBool("Allow the separate compiler to direct call monomorph sites (semi-global)", "--direct-call-monomorph")
38 # --skip-dead-methods
39 var opt_skip_dead_methods = new OptionBool("Do not compile dead methods (semi-global)", "--skip-dead-methods")
40 # --semi-global
41 var opt_semi_global = new OptionBool("Enable all semi-global optimizations", "--semi-global")
42 # --no-colo-dead-methods
43 var opt_no_colo_dead_methods = new OptionBool("Do not colorize dead methods", "--no-colo-dead-methods")
44 # --use-naive-coloring
45 var opt_bm_typing: OptionBool = new OptionBool("Colorize items incrementaly, used to simulate binary matrix typing", "--bm-typing")
46 # --use-mod-perfect-hashing
47 var opt_phmod_typing: OptionBool = new OptionBool("Replace coloration by perfect hashing (with mod operator)", "--phmod-typing")
48 # --use-and-perfect-hashing
49 var opt_phand_typing: OptionBool = new OptionBool("Replace coloration by perfect hashing (with and operator)", "--phand-typing")
50 # --tables-metrics
51 var opt_tables_metrics: OptionBool = new OptionBool("Enable static size measuring of tables used for vft, typing and resolution", "--tables-metrics")
52
53 redef init
54 do
55 super
56 self.option_context.add_option(self.opt_separate)
57 self.option_context.add_option(self.opt_no_inline_intern)
58 self.option_context.add_option(self.opt_no_union_attribute)
59 self.option_context.add_option(self.opt_no_shortcut_equate)
60 self.option_context.add_option(self.opt_inline_coloring_numbers, opt_inline_some_methods, opt_direct_call_monomorph, opt_skip_dead_methods, opt_semi_global)
61 self.option_context.add_option(self.opt_no_colo_dead_methods)
62 self.option_context.add_option(self.opt_bm_typing)
63 self.option_context.add_option(self.opt_phmod_typing)
64 self.option_context.add_option(self.opt_phand_typing)
65 self.option_context.add_option(self.opt_tables_metrics)
66 end
67
68 redef fun process_options(args)
69 do
70 super
71
72 var tc = self
73 if tc.opt_semi_global.value then
74 tc.opt_inline_coloring_numbers.value = true
75 tc.opt_inline_some_methods.value = true
76 tc.opt_direct_call_monomorph.value = true
77 tc.opt_skip_dead_methods.value = true
78 end
79 end
80 end
81
82 redef class ModelBuilder
83 fun run_separate_compiler(mainmodule: MModule, runtime_type_analysis: nullable RapidTypeAnalysis)
84 do
85 var time0 = get_time
86 self.toolcontext.info("*** GENERATING C ***", 1)
87
88 var compiler = new SeparateCompiler(mainmodule, self, runtime_type_analysis)
89 compiler.compile_header
90
91 # compile class structures
92 self.toolcontext.info("Property coloring", 2)
93 compiler.new_file("{mainmodule.name}.classes")
94 compiler.do_property_coloring
95 for m in mainmodule.in_importation.greaters do
96 for mclass in m.intro_mclasses do
97 if mclass.kind == abstract_kind or mclass.kind == interface_kind then continue
98 compiler.compile_class_to_c(mclass)
99 end
100 end
101
102 # The main function of the C
103 compiler.new_file("{mainmodule.name}.main")
104 compiler.compile_main_function
105
106 # compile methods
107 for m in mainmodule.in_importation.greaters do
108 self.toolcontext.info("Generate C for module {m}", 2)
109 compiler.new_file("{m.name}.sep")
110 compiler.compile_module_to_c(m)
111 end
112
113 # compile live & cast type structures
114 self.toolcontext.info("Type coloring", 2)
115 compiler.new_file("{mainmodule.name}.types")
116 var mtypes = compiler.do_type_coloring
117 for t in mtypes do
118 compiler.compile_type_to_c(t)
119 end
120 # compile remaining types structures (useless but needed for the symbol resolution at link-time)
121 for t in compiler.undead_types do
122 if mtypes.has(t) then continue
123 compiler.compile_type_to_c(t)
124 end
125
126 compiler.display_stats
127
128 var time1 = get_time
129 self.toolcontext.info("*** END GENERATING C: {time1-time0} ***", 2)
130 write_and_make(compiler)
131 end
132
133 # Count number of invocations by VFT
134 private var nb_invok_by_tables = 0
135 # Count number of invocations by direct call
136 private var nb_invok_by_direct = 0
137 # Count number of invocations by inlining
138 private var nb_invok_by_inline = 0
139 end
140
141 # Singleton that store the knowledge about the separate compilation process
142 class SeparateCompiler
143 super AbstractCompiler
144
145 redef type VISITOR: SeparateCompilerVisitor
146
147 # The result of the RTA (used to know live types and methods)
148 var runtime_type_analysis: nullable RapidTypeAnalysis
149
150 private var undead_types: Set[MType] = new HashSet[MType]
151 private var live_unresolved_types: Map[MClassDef, Set[MType]] = new HashMap[MClassDef, HashSet[MType]]
152
153 private var type_layout: nullable Layout[MType]
154 private var resolution_layout: nullable Layout[MType]
155 protected var method_layout: nullable Layout[PropertyLayoutElement]
156 protected var attr_layout: nullable Layout[MAttribute]
157
158 init(mainmodule: MModule, mmbuilder: ModelBuilder, runtime_type_analysis: nullable RapidTypeAnalysis) do
159 super(mainmodule, mmbuilder)
160 var file = new_file("nit.common")
161 self.header = new CodeWriter(file)
162 self.runtime_type_analysis = runtime_type_analysis
163 self.compile_box_kinds
164 end
165
166 redef fun compile_header_structs do
167 self.header.add_decl("typedef void(*nitmethod_t)(void); /* general C type representing a Nit method. */")
168 self.compile_header_attribute_structs
169 self.header.add_decl("struct class \{ int box_kind; nitmethod_t vft[]; \}; /* general C type representing a Nit class. */")
170
171 # With resolution_table_table, all live type resolution are stored in a big table: resolution_table
172 self.header.add_decl("struct type \{ int id; const char *name; int color; short int is_nullable; const struct types *resolution_table; int table_size; int type_table[]; \}; /* general C type representing a Nit type. */")
173 self.header.add_decl("struct instance \{ const struct type *type; const struct class *class; nitattribute_t attrs[]; \}; /* general C type representing a Nit instance. */")
174
175 if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
176 self.header.add_decl("struct types \{ int mask; const struct type *types[]; \}; /* a list types (used for vts, fts and unresolved lists). */")
177 else
178 self.header.add_decl("struct types \{ int dummy; const struct type *types[]; \}; /* a list types (used for vts, fts and unresolved lists). */")
179 end
180
181 if modelbuilder.toolcontext.opt_phmod_typing.value then
182 self.header.add_decl("#define HASH(mask, id) ((mask)%(id))")
183 else if modelbuilder.toolcontext.opt_phand_typing.value then
184 self.header.add_decl("#define HASH(mask, id) ((mask)&(id))")
185 end
186
187 self.header.add_decl("typedef struct instance val; /* general C type representing a Nit instance. */")
188 end
189
190 fun compile_header_attribute_structs
191 do
192 if modelbuilder.toolcontext.opt_no_union_attribute.value then
193 self.header.add_decl("typedef void* nitattribute_t; /* general C type representing a Nit attribute. */")
194 else
195 self.header.add_decl("typedef union \{")
196 self.header.add_decl("void* val;")
197 for c, v in self.box_kinds do
198 var t = c.mclass_type
199 self.header.add_decl("{t.ctype} {t.ctypename};")
200 end
201 self.header.add_decl("\} nitattribute_t; /* general C type representing a Nit attribute. */")
202 end
203 end
204
205 fun compile_box_kinds
206 do
207 # Collect all bas box class
208 # FIXME: this is not completely fine with a separate compilation scheme
209 for classname in ["Int", "Bool", "Char", "Float", "NativeString", "Pointer"] do
210 var classes = self.mainmodule.model.get_mclasses_by_name(classname)
211 if classes == null then continue
212 assert classes.length == 1 else print classes.join(", ")
213 self.box_kinds[classes.first] = self.box_kinds.length + 1
214 end
215 end
216
217 var box_kinds = new HashMap[MClass, Int]
218
219 fun box_kind_of(mclass: MClass): Int
220 do
221 if mclass.mclass_type.ctype == "val*" then
222 return 0
223 else if mclass.kind == extern_kind then
224 return self.box_kinds[self.mainmodule.get_primitive_class("Pointer")]
225 else
226 return self.box_kinds[mclass]
227 end
228
229 end
230
231 fun compile_color_consts(colors: Map[Object, Int]) do
232 var v = new_visitor
233 for m, c in colors do
234 compile_color_const(v, m, c)
235 end
236 end
237
238 fun compile_color_const(v: SeparateCompilerVisitor, m: Object, color: Int) do
239 if color_consts_done.has(m) then return
240 if m isa MProperty then
241 if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
242 self.provide_declaration(m.const_color, "#define {m.const_color} {color}")
243 else
244 self.provide_declaration(m.const_color, "extern const int {m.const_color};")
245 v.add("const int {m.const_color} = {color};")
246 end
247 else if m isa MPropDef then
248 if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
249 self.provide_declaration(m.const_color, "#define {m.const_color} {color}")
250 else
251 self.provide_declaration(m.const_color, "extern const int {m.const_color};")
252 v.add("const int {m.const_color} = {color};")
253 end
254 else if m isa MType then
255 if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
256 self.provide_declaration(m.const_color, "#define {m.const_color} {color}")
257 else
258 self.provide_declaration(m.const_color, "extern const int {m.const_color};")
259 v.add("const int {m.const_color} = {color};")
260 end
261 end
262 color_consts_done.add(m)
263 end
264
265 private var color_consts_done = new HashSet[Object]
266
267 # colorize classe properties
268 fun do_property_coloring do
269 var mclasses = new HashSet[MClass].from(modelbuilder.model.mclasses)
270
271 var rta = runtime_type_analysis
272
273 # Layouts
274 var method_layout_builder: PropertyLayoutBuilder[PropertyLayoutElement]
275 var attribute_layout_builder: PropertyLayoutBuilder[MAttribute]
276 #FIXME PH and BM layouts too slow for large programs
277 #if modelbuilder.toolcontext.opt_bm_typing.value then
278 # method_layout_builder = new MMethodBMizer(self.mainmodule)
279 # attribute_layout_builder = new MAttributeBMizer(self.mainmodule)
280 #else if modelbuilder.toolcontext.opt_phmod_typing.value then
281 # method_layout_builder = new MMethodHasher(new PHModOperator, self.mainmodule)
282 # attribute_layout_builder = new MAttributeHasher(new PHModOperator, self.mainmodule)
283 #else if modelbuilder.toolcontext.opt_phand_typing.value then
284 # method_layout_builder = new MMethodHasher(new PHAndOperator, self.mainmodule)
285 # attribute_layout_builder = new MAttributeHasher(new PHAndOperator, self.mainmodule)
286 #else
287
288 var class_layout_builder = new MClassColorer(self.mainmodule)
289 class_layout_builder.build_layout(mclasses)
290 method_layout_builder = new MPropertyColorer[PropertyLayoutElement](self.mainmodule, class_layout_builder)
291 attribute_layout_builder = new MPropertyColorer[MAttribute](self.mainmodule, class_layout_builder)
292 #end
293
294 # The dead methods, still need to provide a dead color symbol
295 var dead_methods = new Array[MMethod]
296
297 # lookup properties to build layout with
298 var mmethods = new HashMap[MClass, Set[PropertyLayoutElement]]
299 var mattributes = new HashMap[MClass, Set[MAttribute]]
300 for mclass in mclasses do
301 mmethods[mclass] = new HashSet[PropertyLayoutElement]
302 mattributes[mclass] = new HashSet[MAttribute]
303 for mprop in self.mainmodule.properties(mclass) do
304 if mprop isa MMethod then
305 if modelbuilder.toolcontext.opt_no_colo_dead_methods.value and rta != null and not rta.live_methods.has(mprop) then
306 dead_methods.add(mprop)
307 continue
308 end
309 mmethods[mclass].add(mprop)
310 else if mprop isa MAttribute then
311 mattributes[mclass].add(mprop)
312 end
313 end
314 end
315
316 # Collect all super calls (dead or not)
317 var all_super_calls = new HashSet[MMethodDef]
318 for mmodule in self.mainmodule.in_importation.greaters do
319 for mclassdef in mmodule.mclassdefs do
320 for mpropdef in mclassdef.mpropdefs do
321 if not mpropdef isa MMethodDef then continue
322 if mpropdef.has_supercall then
323 all_super_calls.add(mpropdef)
324 end
325 end
326 end
327 end
328
329 # lookup super calls and add it to the list of mmethods to build layout with
330 var super_calls
331 if rta != null then
332 super_calls = rta.live_super_sends
333 else
334 super_calls = all_super_calls
335 end
336
337 for mmethoddef in super_calls do
338 var mclass = mmethoddef.mclassdef.mclass
339 mmethods[mclass].add(mmethoddef)
340 for descendant in mclass.in_hierarchy(self.mainmodule).smallers do
341 mmethods[descendant].add(mmethoddef)
342 end
343 end
344
345 # methods coloration
346 self.method_layout = method_layout_builder.build_layout(mmethods)
347 self.method_tables = build_method_tables(mclasses, super_calls)
348 self.compile_color_consts(method_layout.pos)
349
350 # attribute null color to dead methods and supercalls
351 for mproperty in dead_methods do
352 compile_color_const(new_visitor, mproperty, -1)
353 end
354 for mpropdef in all_super_calls do
355 if super_calls.has(mpropdef) then continue
356 compile_color_const(new_visitor, mpropdef, -1)
357 end
358
359 # attributes coloration
360 self.attr_layout = attribute_layout_builder.build_layout(mattributes)
361 self.attr_tables = build_attr_tables(mclasses)
362 self.compile_color_consts(attr_layout.pos)
363 end
364
365 fun build_method_tables(mclasses: Set[MClass], super_calls: Set[MMethodDef]): Map[MClass, Array[nullable MPropDef]] do
366 var layout = self.method_layout
367 var tables = new HashMap[MClass, Array[nullable MPropDef]]
368 for mclass in mclasses do
369 var table = new Array[nullable MPropDef]
370 var supercalls = new List[MMethodDef]
371
372 # first, fill table from parents by reverse linearization order
373 var parents = new Array[MClass]
374 if mainmodule.flatten_mclass_hierarchy.has(mclass) then
375 parents = mclass.in_hierarchy(mainmodule).greaters.to_a
376 self.mainmodule.linearize_mclasses(parents)
377 end
378
379 for parent in parents do
380 if parent == mclass then continue
381 for mproperty in self.mainmodule.properties(parent) do
382 if not mproperty isa MMethod then continue
383 if not layout.pos.has_key(mproperty) then continue
384 var color = layout.pos[mproperty]
385 if table.length <= color then
386 for i in [table.length .. color[ do
387 table[i] = null
388 end
389 end
390 for mpropdef in mproperty.mpropdefs do
391 if mpropdef.mclassdef.mclass == parent then
392 table[color] = mpropdef
393 end
394 end
395 end
396
397 # lookup for super calls in super classes
398 for mmethoddef in super_calls do
399 for mclassdef in parent.mclassdefs do
400 if mclassdef.mpropdefs.has(mmethoddef) then
401 supercalls.add(mmethoddef)
402 end
403 end
404 end
405 end
406
407 # then override with local properties
408 for mproperty in self.mainmodule.properties(mclass) do
409 if not mproperty isa MMethod then continue
410 if not layout.pos.has_key(mproperty) then continue
411 var color = layout.pos[mproperty]
412 if table.length <= color then
413 for i in [table.length .. color[ do
414 table[i] = null
415 end
416 end
417 for mpropdef in mproperty.mpropdefs do
418 if mpropdef.mclassdef.mclass == mclass then
419 table[color] = mpropdef
420 end
421 end
422 end
423
424 # lookup for super calls in local class
425 for mmethoddef in super_calls do
426 for mclassdef in mclass.mclassdefs do
427 if mclassdef.mpropdefs.has(mmethoddef) then
428 supercalls.add(mmethoddef)
429 end
430 end
431 end
432 # insert super calls in table according to receiver
433 for supercall in supercalls do
434 var color = layout.pos[supercall]
435 if table.length <= color then
436 for i in [table.length .. color[ do
437 table[i] = null
438 end
439 end
440 var mmethoddef = supercall.lookup_next_definition(self.mainmodule, mclass.intro.bound_mtype)
441 table[color] = mmethoddef
442 end
443 tables[mclass] = table
444 end
445 return tables
446 end
447
448 fun build_attr_tables(mclasses: Set[MClass]): Map[MClass, Array[nullable MPropDef]] do
449 var layout = self.attr_layout
450 var tables = new HashMap[MClass, Array[nullable MPropDef]]
451 for mclass in mclasses do
452 var table = new Array[nullable MPropDef]
453 # first, fill table from parents by reverse linearization order
454 var parents = new Array[MClass]
455 if mainmodule.flatten_mclass_hierarchy.has(mclass) then
456 parents = mclass.in_hierarchy(mainmodule).greaters.to_a
457 self.mainmodule.linearize_mclasses(parents)
458 end
459 for parent in parents do
460 if parent == mclass then continue
461 for mproperty in self.mainmodule.properties(parent) do
462 if not mproperty isa MAttribute then continue
463 var color = layout.pos[mproperty]
464 if table.length <= color then
465 for i in [table.length .. color[ do
466 table[i] = null
467 end
468 end
469 for mpropdef in mproperty.mpropdefs do
470 if mpropdef.mclassdef.mclass == parent then
471 table[color] = mpropdef
472 end
473 end
474 end
475 end
476
477 # then override with local properties
478 for mproperty in self.mainmodule.properties(mclass) do
479 if not mproperty isa MAttribute then continue
480 var color = layout.pos[mproperty]
481 if table.length <= color then
482 for i in [table.length .. color[ do
483 table[i] = null
484 end
485 end
486 for mpropdef in mproperty.mpropdefs do
487 if mpropdef.mclassdef.mclass == mclass then
488 table[color] = mpropdef
489 end
490 end
491 end
492 tables[mclass] = table
493 end
494 return tables
495 end
496
497 # colorize live types of the program
498 private fun do_type_coloring: POSet[MType] do
499 var mtypes = new HashSet[MType]
500 mtypes.add_all(self.runtime_type_analysis.live_types)
501 mtypes.add_all(self.runtime_type_analysis.live_cast_types)
502 for c in self.box_kinds.keys do
503 mtypes.add(c.mclass_type)
504 end
505
506 # Typing Layout
507 var layout_builder: TypingLayoutBuilder[MType]
508 if modelbuilder.toolcontext.opt_bm_typing.value then
509 layout_builder = new MTypeBMizer(self.mainmodule)
510 else if modelbuilder.toolcontext.opt_phmod_typing.value then
511 layout_builder = new MTypeHasher(new PHModOperator, self.mainmodule)
512 else if modelbuilder.toolcontext.opt_phand_typing.value then
513 layout_builder = new MTypeHasher(new PHAndOperator, self.mainmodule)
514 else
515 layout_builder = new MTypeColorer(self.mainmodule)
516 end
517
518 # colorize types
519 self.type_layout = layout_builder.build_layout(mtypes)
520 var poset = layout_builder.poset.as(not null)
521 self.type_tables = self.build_type_tables(poset)
522
523 # VT and FT are stored with other unresolved types in the big resolution_tables
524 self.compile_resolution_tables(mtypes)
525
526 return poset
527 end
528
529 # Build type tables
530 fun build_type_tables(mtypes: POSet[MType]): Map[MType, Array[nullable MType]] do
531 var tables = new HashMap[MType, Array[nullable MType]]
532 var layout = self.type_layout
533 for mtype in mtypes do
534 var table = new Array[nullable MType]
535 for sup in mtypes[mtype].greaters do
536 var color: Int
537 if layout isa PHLayout[MType, MType] then
538 color = layout.hashes[mtype][sup]
539 else
540 color = layout.pos[sup]
541 end
542 if table.length <= color then
543 for i in [table.length .. color[ do
544 table[i] = null
545 end
546 end
547 table[color] = sup
548 end
549 tables[mtype] = table
550 end
551 return tables
552 end
553
554 protected fun compile_resolution_tables(mtypes: Set[MType]) do
555 # resolution_tables is used to perform a type resolution at runtime in O(1)
556
557 # During the visit of the body of classes, live_unresolved_types are collected
558 # and associated to
559 # Collect all live_unresolved_types (visited in the body of classes)
560
561 # Determinate fo each livetype what are its possible requested anchored types
562 var mtype2unresolved = new HashMap[MClassType, Set[MType]]
563 for mtype in self.runtime_type_analysis.live_types do
564 var set = new HashSet[MType]
565 for cd in mtype.collect_mclassdefs(self.mainmodule) do
566 if self.live_unresolved_types.has_key(cd) then
567 set.add_all(self.live_unresolved_types[cd])
568 end
569 end
570 mtype2unresolved[mtype] = set
571 end
572
573 # Compute the table layout with the prefered method
574 var resolution_builder: ResolutionLayoutBuilder
575 if modelbuilder.toolcontext.opt_bm_typing.value then
576 resolution_builder = new ResolutionBMizer
577 else if modelbuilder.toolcontext.opt_phmod_typing.value then
578 resolution_builder = new ResolutionHasher(new PHModOperator)
579 else if modelbuilder.toolcontext.opt_phand_typing.value then
580 resolution_builder = new ResolutionHasher(new PHAndOperator)
581 else
582 resolution_builder = new ResolutionColorer
583 end
584 self.resolution_layout = resolution_builder.build_layout(mtype2unresolved)
585 self.resolution_tables = self.build_resolution_tables(mtype2unresolved)
586
587 # Compile a C constant for each collected unresolved type.
588 # Either to a color, or to -1 if the unresolved type is dead (no live receiver can require it)
589 var all_unresolved = new HashSet[MType]
590 for t in self.live_unresolved_types.values do
591 all_unresolved.add_all(t)
592 end
593 var all_unresolved_types_colors = new HashMap[MType, Int]
594 for t in all_unresolved do
595 if self.resolution_layout.pos.has_key(t) then
596 all_unresolved_types_colors[t] = self.resolution_layout.pos[t]
597 else
598 all_unresolved_types_colors[t] = -1
599 end
600 end
601 self.compile_color_consts(all_unresolved_types_colors)
602
603 #print "tables"
604 #for k, v in unresolved_types_tables.as(not null) do
605 # print "{k}: {v.join(", ")}"
606 #end
607 #print ""
608 end
609
610 fun build_resolution_tables(elements: Map[MClassType, Set[MType]]): Map[MClassType, Array[nullable MType]] do
611 var tables = new HashMap[MClassType, Array[nullable MType]]
612 var layout = self.resolution_layout
613 for mclasstype, mtypes in elements do
614 var table = new Array[nullable MType]
615 for mtype in mtypes do
616 var color: Int
617 if layout isa PHLayout[MClassType, MType] then
618 color = layout.hashes[mclasstype][mtype]
619 else
620 color = layout.pos[mtype]
621 end
622 if table.length <= color then
623 for i in [table.length .. color[ do
624 table[i] = null
625 end
626 end
627 table[color] = mtype
628 end
629 tables[mclasstype] = table
630 end
631 return tables
632 end
633
634 # Separately compile all the method definitions of the module
635 fun compile_module_to_c(mmodule: MModule)
636 do
637 var old_module = self.mainmodule
638 self.mainmodule = mmodule
639 for cd in mmodule.mclassdefs do
640 for pd in cd.mpropdefs do
641 if not pd isa MMethodDef then continue
642 var rta = runtime_type_analysis
643 if modelbuilder.toolcontext.opt_skip_dead_methods.value and rta != null and not rta.live_methoddefs.has(pd) then continue
644 #print "compile {pd} @ {cd} @ {mmodule}"
645 var r = pd.separate_runtime_function
646 r.compile_to_c(self)
647 var r2 = pd.virtual_runtime_function
648 r2.compile_to_c(self)
649 end
650 end
651 self.mainmodule = old_module
652 end
653
654 # Globaly compile the type structure of a live type
655 fun compile_type_to_c(mtype: MType)
656 do
657 assert not mtype.need_anchor
658 var layout = self.type_layout
659 var is_live = mtype isa MClassType and runtime_type_analysis.live_types.has(mtype)
660 var is_cast_live = runtime_type_analysis.live_cast_types.has(mtype)
661 var c_name = mtype.c_name
662 var v = new SeparateCompilerVisitor(self)
663 v.add_decl("/* runtime type {mtype} */")
664
665 # extern const struct type_X
666 self.provide_declaration("type_{c_name}", "extern const struct type type_{c_name};")
667
668 # const struct type_X
669 v.add_decl("const struct type type_{c_name} = \{")
670
671 # type id (for cast target)
672 if is_cast_live then
673 v.add_decl("{layout.ids[mtype]},")
674 else
675 v.add_decl("-1, /*CAST DEAD*/")
676 end
677
678 # type name
679 v.add_decl("\"{mtype}\", /* class_name_string */")
680
681 # type color (for cast target)
682 if is_cast_live then
683 if layout isa PHLayout[MType, MType] then
684 v.add_decl("{layout.masks[mtype]},")
685 else
686 v.add_decl("{layout.pos[mtype]},")
687 end
688 else
689 v.add_decl("-1, /*CAST DEAD*/")
690 end
691
692 # is_nullable bit
693 if mtype isa MNullableType then
694 v.add_decl("1,")
695 else
696 v.add_decl("0,")
697 end
698
699 # resolution table (for receiver)
700 if is_live then
701 var mclass_type = mtype
702 if mclass_type isa MNullableType then mclass_type = mclass_type.mtype
703 assert mclass_type isa MClassType
704 if resolution_tables[mclass_type].is_empty then
705 v.add_decl("NULL, /*NO RESOLUTIONS*/")
706 else
707 compile_type_resolution_table(mtype)
708 v.require_declaration("resolution_table_{c_name}")
709 v.add_decl("&resolution_table_{c_name},")
710 end
711 else
712 v.add_decl("NULL, /*DEAD*/")
713 end
714
715 # cast table (for receiver)
716 if is_live then
717 v.add_decl("{self.type_tables[mtype].length},")
718 v.add_decl("\{")
719 for stype in self.type_tables[mtype] do
720 if stype == null then
721 v.add_decl("-1, /* empty */")
722 else
723 v.add_decl("{layout.ids[stype]}, /* {stype} */")
724 end
725 end
726 v.add_decl("\},")
727 else
728 v.add_decl("0, \{\}, /*DEAD TYPE*/")
729 end
730 v.add_decl("\};")
731 end
732
733 fun compile_type_resolution_table(mtype: MType) do
734
735 var mclass_type: MClassType
736 if mtype isa MNullableType then
737 mclass_type = mtype.mtype.as(MClassType)
738 else
739 mclass_type = mtype.as(MClassType)
740 end
741
742 var layout = self.resolution_layout
743
744 # extern const struct resolution_table_X resolution_table_X
745 self.provide_declaration("resolution_table_{mtype.c_name}", "extern const struct types resolution_table_{mtype.c_name};")
746
747 # const struct fts_table_X fts_table_X
748 var v = new_visitor
749 v.add_decl("const struct types resolution_table_{mtype.c_name} = \{")
750 if layout isa PHLayout[MClassType, MType] then
751 v.add_decl("{layout.masks[mclass_type]},")
752 else
753 v.add_decl("0, /* dummy */")
754 end
755 v.add_decl("\{")
756 for t in self.resolution_tables[mclass_type] do
757 if t == null then
758 v.add_decl("NULL, /* empty */")
759 else
760 # The table stores the result of the type resolution
761 # Therefore, for a receiver `mclass_type`, and a unresolved type `t`
762 # the value stored is tv.
763 var tv = t.resolve_for(mclass_type, mclass_type, self.mainmodule, true)
764 # FIXME: What typeids means here? How can a tv not be live?
765 if self.type_layout.ids.has_key(tv) then
766 v.require_declaration("type_{tv.c_name}")
767 v.add_decl("&type_{tv.c_name}, /* {t}: {tv} */")
768 else
769 v.add_decl("NULL, /* empty ({t}: {tv} not a live type) */")
770 end
771 end
772 end
773 v.add_decl("\}")
774 v.add_decl("\};")
775 end
776
777 # Globally compile the table of the class mclass
778 # In a link-time optimisation compiler, tables are globally computed
779 # In a true separate compiler (a with dynamic loading) you cannot do this unfortnally
780 fun compile_class_to_c(mclass: MClass)
781 do
782 var mtype = mclass.intro.bound_mtype
783 var c_name = mclass.c_name
784 var c_instance_name = mclass.c_instance_name
785
786 var vft = self.method_tables[mclass]
787 var attrs = self.attr_tables[mclass]
788 var v = new_visitor
789
790 var rta = runtime_type_analysis
791 var is_dead = rta != null and not rta.live_classes.has(mclass) and mtype.ctype == "val*" and mclass.name != "NativeArray"
792
793 v.add_decl("/* runtime class {c_name} */")
794
795 # Build class vft
796 if not is_dead then
797 self.provide_declaration("class_{c_name}", "extern const struct class class_{c_name};")
798 v.add_decl("const struct class class_{c_name} = \{")
799 v.add_decl("{self.box_kind_of(mclass)}, /* box_kind */")
800 v.add_decl("\{")
801 for i in [0 .. vft.length[ do
802 var mpropdef = vft[i]
803 if mpropdef == null then
804 v.add_decl("NULL, /* empty */")
805 else
806 assert mpropdef isa MMethodDef
807 if rta != null and not rta.live_methoddefs.has(mpropdef) then
808 v.add_decl("NULL, /* DEAD {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
809 continue
810 end
811 var rf = mpropdef.virtual_runtime_function
812 v.require_declaration(rf.c_name)
813 v.add_decl("(nitmethod_t){rf.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
814 end
815 end
816 v.add_decl("\}")
817 v.add_decl("\};")
818 end
819
820 if mtype.ctype != "val*" then
821 if mtype.mclass.name == "Pointer" or mtype.mclass.kind != extern_kind then
822 #Build instance struct
823 self.header.add_decl("struct instance_{c_instance_name} \{")
824 self.header.add_decl("const struct type *type;")
825 self.header.add_decl("const struct class *class;")
826 self.header.add_decl("{mtype.ctype} value;")
827 self.header.add_decl("\};")
828 end
829
830 if not rta.live_types.has(mtype) then return
831
832 #Build BOX
833 self.provide_declaration("BOX_{c_name}", "val* BOX_{c_name}({mtype.ctype});")
834 v.add_decl("/* allocate {mtype} */")
835 v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value) \{")
836 v.add("struct instance_{c_instance_name}*res = nit_alloc(sizeof(struct instance_{c_instance_name}));")
837 v.require_declaration("type_{c_name}")
838 v.add("res->type = &type_{c_name};")
839 v.require_declaration("class_{c_name}")
840 v.add("res->class = &class_{c_name};")
841 v.add("res->value = value;")
842 v.add("return (val*)res;")
843 v.add("\}")
844 return
845 else if mclass.name == "NativeArray" then
846 #Build instance struct
847 self.header.add_decl("struct instance_{c_instance_name} \{")
848 self.header.add_decl("const struct type *type;")
849 self.header.add_decl("const struct class *class;")
850 # NativeArrays are just a instance header followed by a length and an array of values
851 self.header.add_decl("int length;")
852 self.header.add_decl("val* values[0];")
853 self.header.add_decl("\};")
854
855 #Build NEW
856 self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(int length, const struct type* type);")
857 v.add_decl("/* allocate {mtype} */")
858 v.add_decl("{mtype.ctype} NEW_{c_name}(int length, const struct type* type) \{")
859 var res = v.get_name("self")
860 v.add_decl("struct instance_{c_instance_name} *{res};")
861 var mtype_elt = mtype.arguments.first
862 v.add("{res} = nit_alloc(sizeof(struct instance_{c_instance_name}) + length*sizeof({mtype_elt.ctype}));")
863 v.add("{res}->type = type;")
864 hardening_live_type(v, "type")
865 v.require_declaration("class_{c_name}")
866 v.add("{res}->class = &class_{c_name};")
867 v.add("{res}->length = length;")
868 v.add("return (val*){res};")
869 v.add("\}")
870 return
871 end
872
873 #Build NEW
874 self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(const struct type* type);")
875 v.add_decl("/* allocate {mtype} */")
876 v.add_decl("{mtype.ctype} NEW_{c_name}(const struct type* type) \{")
877 if is_dead then
878 v.add_abort("{mclass} is DEAD")
879 else
880 var res = v.new_named_var(mtype, "self")
881 res.is_exact = true
882 v.add("{res} = nit_alloc(sizeof(struct instance) + {attrs.length}*sizeof(nitattribute_t));")
883 v.add("{res}->type = type;")
884 hardening_live_type(v, "type")
885 v.require_declaration("class_{c_name}")
886 v.add("{res}->class = &class_{c_name};")
887 self.generate_init_attr(v, res, mtype)
888 v.add("return {res};")
889 end
890 v.add("\}")
891 end
892
893 # Add a dynamic test to ensure that the type referenced by `t` is a live type
894 fun hardening_live_type(v: VISITOR, t: String)
895 do
896 if not v.compiler.modelbuilder.toolcontext.opt_hardening.value then return
897 v.add("if({t} == NULL) \{")
898 v.add_abort("type null")
899 v.add("\}")
900 v.add("if({t}->table_size == 0) \{")
901 v.add("fprintf(stderr, \"Insantiation of a dead type: %s\\n\", {t}->name);")
902 v.add_abort("type dead")
903 v.add("\}")
904 end
905
906 redef fun new_visitor do return new SeparateCompilerVisitor(self)
907
908 # Stats
909
910 private var type_tables: Map[MType, Array[nullable MType]] = new HashMap[MType, Array[nullable MType]]
911 private var resolution_tables: Map[MClassType, Array[nullable MType]] = new HashMap[MClassType, Array[nullable MType]]
912 protected var method_tables: Map[MClass, Array[nullable MPropDef]] = new HashMap[MClass, Array[nullable MPropDef]]
913 protected var attr_tables: Map[MClass, Array[nullable MPropDef]] = new HashMap[MClass, Array[nullable MPropDef]]
914
915 redef fun display_stats
916 do
917 super
918 if self.modelbuilder.toolcontext.opt_tables_metrics.value then
919 display_sizes
920 end
921 if self.modelbuilder.toolcontext.opt_isset_checks_metrics.value then
922 display_isset_checks
923 end
924 var tc = self.modelbuilder.toolcontext
925 tc.info("# implementation of method invocation",2)
926 var nb_invok_total = modelbuilder.nb_invok_by_tables + modelbuilder.nb_invok_by_direct + modelbuilder.nb_invok_by_inline
927 tc.info("total number of invocations: {nb_invok_total}",2)
928 tc.info("invocations by VFT send: {modelbuilder.nb_invok_by_tables} ({div(modelbuilder.nb_invok_by_tables,nb_invok_total)}%)",2)
929 tc.info("invocations by direct call: {modelbuilder.nb_invok_by_direct} ({div(modelbuilder.nb_invok_by_direct,nb_invok_total)}%)",2)
930 tc.info("invocations by inlining: {modelbuilder.nb_invok_by_inline} ({div(modelbuilder.nb_invok_by_inline,nb_invok_total)}%)",2)
931 end
932
933 fun display_sizes
934 do
935 print "# size of subtyping tables"
936 print "\ttotal \tholes"
937 var total = 0
938 var holes = 0
939 for t, table in type_tables do
940 total += table.length
941 for e in table do if e == null then holes += 1
942 end
943 print "\t{total}\t{holes}"
944
945 print "# size of resolution tables"
946 print "\ttotal \tholes"
947 total = 0
948 holes = 0
949 for t, table in resolution_tables do
950 total += table.length
951 for e in table do if e == null then holes += 1
952 end
953 print "\t{total}\t{holes}"
954
955 print "# size of methods tables"
956 print "\ttotal \tholes"
957 total = 0
958 holes = 0
959 for t, table in method_tables do
960 total += table.length
961 for e in table do if e == null then holes += 1
962 end
963 print "\t{total}\t{holes}"
964
965 print "# size of attributes tables"
966 print "\ttotal \tholes"
967 total = 0
968 holes = 0
969 for t, table in attr_tables do
970 total += table.length
971 for e in table do if e == null then holes += 1
972 end
973 print "\t{total}\t{holes}"
974 end
975
976 protected var isset_checks_count = 0
977 protected var attr_read_count = 0
978
979 fun display_isset_checks do
980 print "# total number of compiled attribute reads"
981 print "\t{attr_read_count}"
982 print "# total number of compiled isset-checks"
983 print "\t{isset_checks_count}"
984 end
985
986 redef fun compile_nitni_structs
987 do
988 self.header.add_decl("struct nitni_instance \{struct instance *value;\};")
989 end
990
991 redef fun finalize_ffi_for_module(mmodule)
992 do
993 var old_module = self.mainmodule
994 self.mainmodule = mmodule
995 super
996 self.mainmodule = old_module
997 end
998 end
999
1000 # A visitor on the AST of property definition that generate the C code of a separate compilation process.
1001 class SeparateCompilerVisitor
1002 super AbstractCompilerVisitor
1003
1004 redef type COMPILER: SeparateCompiler
1005
1006 redef fun adapt_signature(m, args)
1007 do
1008 var msignature = m.msignature.resolve_for(m.mclassdef.bound_mtype, m.mclassdef.bound_mtype, m.mclassdef.mmodule, true)
1009 var recv = args.first
1010 if recv.mtype.ctype != m.mclassdef.mclass.mclass_type.ctype then
1011 args.first = self.autobox(args.first, m.mclassdef.mclass.mclass_type)
1012 end
1013 for i in [0..msignature.arity[ do
1014 var t = msignature.mparameters[i].mtype
1015 if i == msignature.vararg_rank then
1016 t = args[i+1].mtype
1017 end
1018 args[i+1] = self.autobox(args[i+1], t)
1019 end
1020 end
1021
1022 redef fun autobox(value, mtype)
1023 do
1024 if value.mtype == mtype then
1025 return value
1026 else if value.mtype.ctype == "val*" and mtype.ctype == "val*" then
1027 return value
1028 else if value.mtype.ctype == "val*" then
1029 return self.new_expr("((struct instance_{mtype.c_instance_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
1030 else if mtype.ctype == "val*" then
1031 var valtype = value.mtype.as(MClassType)
1032 var res = self.new_var(mtype)
1033 if compiler.runtime_type_analysis != null and not compiler.runtime_type_analysis.live_types.has(valtype) then
1034 self.add("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */")
1035 self.add("printf(\"Dead code executed!\\n\"); show_backtrace(1);")
1036 return res
1037 end
1038 self.require_declaration("BOX_{valtype.c_name}")
1039 self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
1040 return res
1041 else if value.mtype.ctype == "void*" and mtype.ctype == "void*" then
1042 return value
1043 else
1044 # Bad things will appen!
1045 var res = self.new_var(mtype)
1046 self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */")
1047 self.add("printf(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); show_backtrace(1);")
1048 return res
1049 end
1050 end
1051
1052 # Return a C expression returning the runtime type structure of the value
1053 # The point of the method is to works also with primitives types.
1054 fun type_info(value: RuntimeVariable): String
1055 do
1056 if value.mtype.ctype == "val*" then
1057 return "{value}->type"
1058 else
1059 compiler.undead_types.add(value.mtype)
1060 self.require_declaration("type_{value.mtype.c_name}")
1061 return "(&type_{value.mtype.c_name})"
1062 end
1063 end
1064
1065 redef fun compile_callsite(callsite, args)
1066 do
1067 var rta = compiler.runtime_type_analysis
1068 var recv = args.first.mtype
1069 if compiler.modelbuilder.toolcontext.opt_direct_call_monomorph.value and rta != null then
1070 var tgs = rta.live_targets(callsite)
1071 if tgs.length == 1 then
1072 # DIRECT CALL
1073 var mmethod = callsite.mproperty
1074 self.varargize(mmethod.intro, mmethod.intro.msignature.as(not null), args)
1075 var res0 = before_send(mmethod, args)
1076 var res = call(tgs.first, tgs.first.mclassdef.bound_mtype, args)
1077 if res0 != null then
1078 assert res != null
1079 self.assign(res0, res)
1080 res = res0
1081 end
1082 add("\}") # close the before_send
1083 return res
1084 end
1085 end
1086 return super
1087 end
1088 redef fun send(mmethod, arguments)
1089 do
1090 self.varargize(mmethod.intro, mmethod.intro.msignature.as(not null), arguments)
1091
1092 if arguments.first.mcasttype.ctype != "val*" then
1093 # In order to shortcut the primitive, we need to find the most specific method
1094 # Howverr, because of performance (no flattening), we always work on the realmainmodule
1095 var m = self.compiler.mainmodule
1096 self.compiler.mainmodule = self.compiler.realmainmodule
1097 var res = self.monomorphic_send(mmethod, arguments.first.mcasttype, arguments)
1098 self.compiler.mainmodule = m
1099 return res
1100 end
1101
1102 return table_send(mmethod, arguments, mmethod.const_color)
1103 end
1104
1105 # Handel common special cases before doing the effective method invocation
1106 # This methods handle the `==` and `!=` methods and the case of the null receiver.
1107 # Note: a { is open in the generated C, that enclose and protect the effective method invocation.
1108 # Client must not forget to close the } after them.
1109 #
1110 # The value returned is the result of the common special cases.
1111 # If not null, client must compine it with the result of their own effective method invocation.
1112 #
1113 # If `before_send` can shortcut the whole message sending, a dummy `if(0){`
1114 # is generated to cancel the effective method invocation that will follow
1115 # TODO: find a better approach
1116 private fun before_send(mmethod: MMethod, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
1117 do
1118 var res: nullable RuntimeVariable = null
1119 var recv = arguments.first
1120 var consider_null = not self.compiler.modelbuilder.toolcontext.opt_no_check_other.value or mmethod.name == "==" or mmethod.name == "!="
1121 var maybenull = recv.mcasttype isa MNullableType and consider_null
1122 if maybenull then
1123 self.add("if ({recv} == NULL) \{")
1124 if mmethod.name == "==" then
1125 res = self.new_var(bool_type)
1126 var arg = arguments[1]
1127 if arg.mcasttype isa MNullableType then
1128 self.add("{res} = ({arg} == NULL);")
1129 else if arg.mcasttype isa MNullType then
1130 self.add("{res} = 1; /* is null */")
1131 else
1132 self.add("{res} = 0; /* {arg.inspect} cannot be null */")
1133 end
1134 else if mmethod.name == "!=" then
1135 res = self.new_var(bool_type)
1136 var arg = arguments[1]
1137 if arg.mcasttype isa MNullableType then
1138 self.add("{res} = ({arg} != NULL);")
1139 else if arg.mcasttype isa MNullType then
1140 self.add("{res} = 0; /* is null */")
1141 else
1142 self.add("{res} = 1; /* {arg.inspect} cannot be null */")
1143 end
1144 else
1145 self.add_abort("Receiver is null")
1146 end
1147 self.add("\} else \{")
1148 else
1149 self.add("\{")
1150 end
1151 if not self.compiler.modelbuilder.toolcontext.opt_no_shortcut_equate.value and (mmethod.name == "==" or mmethod.name == "!=") then
1152 if res == null then res = self.new_var(bool_type)
1153 # Recv is not null, thus is arg is, it is easy to conclude (and respect the invariants)
1154 var arg = arguments[1]
1155 if arg.mcasttype isa MNullType then
1156 if mmethod.name == "==" then
1157 self.add("{res} = 0; /* arg is null but recv is not */")
1158 else
1159 self.add("{res} = 1; /* arg is null and recv is not */")
1160 end
1161 self.add("\}") # closes the null case
1162 self.add("if (0) \{") # what follow is useless, CC will drop it
1163 end
1164 end
1165 return res
1166 end
1167
1168 private fun table_send(mmethod: MMethod, arguments: Array[RuntimeVariable], const_color: String): nullable RuntimeVariable
1169 do
1170 compiler.modelbuilder.nb_invok_by_tables += 1
1171 if compiler.modelbuilder.toolcontext.opt_invocation_metrics.value then add("count_invoke_by_tables++;")
1172
1173 assert arguments.length == mmethod.intro.msignature.arity + 1 else debug("Invalid arity for {mmethod}. {arguments.length} arguments given.")
1174 var recv = arguments.first
1175
1176 var res0 = before_send(mmethod, arguments)
1177
1178 var res: nullable RuntimeVariable
1179 var msignature = mmethod.intro.msignature.resolve_for(mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.mmodule, true)
1180 var ret = msignature.return_mtype
1181 if mmethod.is_new then
1182 ret = arguments.first.mtype
1183 res = self.new_var(ret)
1184 else if ret == null then
1185 res = null
1186 else
1187 res = self.new_var(ret)
1188 end
1189
1190 var s = new FlatBuffer
1191 var ss = new FlatBuffer
1192
1193 s.append("val*")
1194 ss.append("{recv}")
1195 for i in [0..msignature.arity[ do
1196 var a = arguments[i+1]
1197 var t = msignature.mparameters[i].mtype
1198 if i == msignature.vararg_rank then
1199 t = arguments[i+1].mcasttype
1200 end
1201 s.append(", {t.ctype}")
1202 a = self.autobox(a, t)
1203 ss.append(", {a}")
1204 end
1205
1206
1207 var r
1208 if ret == null then r = "void" else r = ret.ctype
1209 self.require_declaration(const_color)
1210 var call = "(({r} (*)({s}))({arguments.first}->class->vft[{const_color}]))({ss}) /* {mmethod} on {arguments.first.inspect}*/"
1211
1212 if res != null then
1213 self.add("{res} = {call};")
1214 else
1215 self.add("{call};")
1216 end
1217
1218 if res0 != null then
1219 assert res != null
1220 assign(res0,res)
1221 res = res0
1222 end
1223
1224 self.add("\}") # closes the null case
1225
1226 return res
1227 end
1228
1229 redef fun call(mmethoddef, recvtype, arguments)
1230 do
1231 assert arguments.length == mmethoddef.msignature.arity + 1 else debug("Invalid arity for {mmethoddef}. {arguments.length} arguments given.")
1232
1233 var res: nullable RuntimeVariable
1234 var ret = mmethoddef.msignature.return_mtype
1235 if mmethoddef.mproperty.is_new then
1236 ret = arguments.first.mtype
1237 res = self.new_var(ret)
1238 else if ret == null then
1239 res = null
1240 else
1241 ret = ret.resolve_for(mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.mmodule, true)
1242 res = self.new_var(ret)
1243 end
1244
1245 if (mmethoddef.is_intern and not compiler.modelbuilder.toolcontext.opt_no_inline_intern.value) or
1246 (compiler.modelbuilder.toolcontext.opt_inline_some_methods.value and mmethoddef.can_inline(self)) then
1247 compiler.modelbuilder.nb_invok_by_inline += 1
1248 if compiler.modelbuilder.toolcontext.opt_invocation_metrics.value then add("count_invoke_by_inline++;")
1249 var frame = new Frame(self, mmethoddef, recvtype, arguments)
1250 frame.returnlabel = self.get_name("RET_LABEL")
1251 frame.returnvar = res
1252 var old_frame = self.frame
1253 self.frame = frame
1254 self.add("\{ /* Inline {mmethoddef} ({arguments.join(",")}) on {arguments.first.inspect} */")
1255 mmethoddef.compile_inside_to_c(self, arguments)
1256 self.add("{frame.returnlabel.as(not null)}:(void)0;")
1257 self.add("\}")
1258 self.frame = old_frame
1259 return res
1260 end
1261 compiler.modelbuilder.nb_invok_by_direct += 1
1262 if compiler.modelbuilder.toolcontext.opt_invocation_metrics.value then add("count_invoke_by_direct++;")
1263
1264 # Autobox arguments
1265 self.adapt_signature(mmethoddef, arguments)
1266
1267 self.require_declaration(mmethoddef.c_name)
1268 if res == null then
1269 self.add("{mmethoddef.c_name}({arguments.join(", ")}); /* Direct call {mmethoddef} on {arguments.first.inspect}*/")
1270 return null
1271 else
1272 self.add("{res} = {mmethoddef.c_name}({arguments.join(", ")});")
1273 end
1274
1275 return res
1276 end
1277
1278 redef fun supercall(m: MMethodDef, recvtype: MClassType, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
1279 do
1280 if arguments.first.mcasttype.ctype != "val*" then
1281 # In order to shortcut the primitive, we need to find the most specific method
1282 # However, because of performance (no flattening), we always work on the realmainmodule
1283 var main = self.compiler.mainmodule
1284 self.compiler.mainmodule = self.compiler.realmainmodule
1285 var res = self.monomorphic_super_send(m, recvtype, arguments)
1286 self.compiler.mainmodule = main
1287 return res
1288 end
1289 return table_send(m.mproperty, arguments, m.const_color)
1290 end
1291
1292 redef fun vararg_instance(mpropdef, recv, varargs, elttype)
1293 do
1294 # A vararg must be stored into an new array
1295 # The trick is that the dymaic type of the array may depends on the receiver
1296 # of the method (ie recv) if the static type is unresolved
1297 # This is more complex than usual because the unresolved type must not be resolved
1298 # with the current receiver (ie self).
1299 # Therefore to isolate the resolution from self, a local Frame is created.
1300 # One can see this implementation as an inlined method of the receiver whose only
1301 # job is to allocate the array
1302 var old_frame = self.frame
1303 var frame = new Frame(self, mpropdef, mpropdef.mclassdef.bound_mtype, [recv])
1304 self.frame = frame
1305 #print "required Array[{elttype}] for recv {recv.inspect}. bound=Array[{self.resolve_for(elttype, recv)}]. selfvar={frame.arguments.first.inspect}"
1306 var res = self.array_instance(varargs, elttype)
1307 self.frame = old_frame
1308 return res
1309 end
1310
1311 redef fun isset_attribute(a, recv)
1312 do
1313 self.check_recv_notnull(recv)
1314 var res = self.new_var(bool_type)
1315
1316 # What is the declared type of the attribute?
1317 var mtype = a.intro.static_mtype.as(not null)
1318 var intromclassdef = a.intro.mclassdef
1319 mtype = mtype.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
1320
1321 if mtype isa MNullableType then
1322 self.add("{res} = 1; /* easy isset: {a} on {recv.inspect} */")
1323 return res
1324 end
1325
1326 self.require_declaration(a.const_color)
1327 if self.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then
1328 self.add("{res} = {recv}->attrs[{a.const_color}] != NULL; /* {a} on {recv.inspect}*/")
1329 else
1330
1331 if mtype.ctype == "val*" then
1332 self.add("{res} = {recv}->attrs[{a.const_color}].val != NULL; /* {a} on {recv.inspect} */")
1333 else
1334 self.add("{res} = 1; /* NOT YET IMPLEMENTED: isset of primitives: {a} on {recv.inspect} */")
1335 end
1336 end
1337 return res
1338 end
1339
1340 redef fun read_attribute(a, recv)
1341 do
1342 self.check_recv_notnull(recv)
1343
1344 # What is the declared type of the attribute?
1345 var ret = a.intro.static_mtype.as(not null)
1346 var intromclassdef = a.intro.mclassdef
1347 ret = ret.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
1348
1349 if self.compiler.modelbuilder.toolcontext.opt_isset_checks_metrics.value then
1350 self.compiler.attr_read_count += 1
1351 self.add("count_attr_reads++;")
1352 end
1353
1354 self.require_declaration(a.const_color)
1355 if self.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then
1356 # Get the attribute or a box (ie. always a val*)
1357 var cret = self.object_type.as_nullable
1358 var res = self.new_var(cret)
1359 res.mcasttype = ret
1360
1361 self.add("{res} = {recv}->attrs[{a.const_color}]; /* {a} on {recv.inspect} */")
1362
1363 # Check for Uninitialized attribute
1364 if not ret isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_attr_isset.value then
1365 self.add("if (unlikely({res} == NULL)) \{")
1366 self.add_abort("Uninitialized attribute {a.name}")
1367 self.add("\}")
1368
1369 if self.compiler.modelbuilder.toolcontext.opt_isset_checks_metrics.value then
1370 self.compiler.isset_checks_count += 1
1371 self.add("count_isset_checks++;")
1372 end
1373 end
1374
1375 # Return the attribute or its unboxed version
1376 # Note: it is mandatory since we reuse the box on write, we do not whant that the box escapes
1377 return self.autobox(res, ret)
1378 else
1379 var res = self.new_var(ret)
1380 self.add("{res} = {recv}->attrs[{a.const_color}].{ret.ctypename}; /* {a} on {recv.inspect} */")
1381
1382 # Check for Uninitialized attribute
1383 if ret.ctype == "val*" and not ret isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_attr_isset.value then
1384 self.add("if (unlikely({res} == NULL)) \{")
1385 self.add_abort("Uninitialized attribute {a.name}")
1386 self.add("\}")
1387 if self.compiler.modelbuilder.toolcontext.opt_isset_checks_metrics.value then
1388 self.compiler.isset_checks_count += 1
1389 self.add("count_isset_checks++;")
1390 end
1391 end
1392
1393 return res
1394 end
1395 end
1396
1397 redef fun write_attribute(a, recv, value)
1398 do
1399 self.check_recv_notnull(recv)
1400
1401 # What is the declared type of the attribute?
1402 var mtype = a.intro.static_mtype.as(not null)
1403 var intromclassdef = a.intro.mclassdef
1404 mtype = mtype.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
1405
1406 # Adapt the value to the declared type
1407 value = self.autobox(value, mtype)
1408
1409 self.require_declaration(a.const_color)
1410 if self.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then
1411 var attr = "{recv}->attrs[{a.const_color}]"
1412 if mtype.ctype != "val*" then
1413 assert mtype isa MClassType
1414 # The attribute is primitive, thus we store it in a box
1415 # The trick is to create the box the first time then resuse the box
1416 self.add("if ({attr} != NULL) \{")
1417 self.add("((struct instance_{mtype.c_instance_name}*){attr})->value = {value}; /* {a} on {recv.inspect} */")
1418 self.add("\} else \{")
1419 value = self.autobox(value, self.object_type.as_nullable)
1420 self.add("{attr} = {value}; /* {a} on {recv.inspect} */")
1421 self.add("\}")
1422 else
1423 # The attribute is not primitive, thus store it direclty
1424 self.add("{attr} = {value}; /* {a} on {recv.inspect} */")
1425 end
1426 else
1427 self.add("{recv}->attrs[{a.const_color}].{mtype.ctypename} = {value}; /* {a} on {recv.inspect} */")
1428 end
1429 end
1430
1431 # Check that mtype is a live open type
1432 fun hardening_live_open_type(mtype: MType)
1433 do
1434 if not compiler.modelbuilder.toolcontext.opt_hardening.value then return
1435 self.require_declaration(mtype.const_color)
1436 var col = mtype.const_color
1437 self.add("if({col} == -1) \{")
1438 self.add("fprintf(stderr, \"Resolution of a dead open type: %s\\n\", \"{mtype.to_s.escape_to_c}\");")
1439 self.add_abort("open type dead")
1440 self.add("\}")
1441 end
1442
1443 # Check that mtype it a pointer to a live cast type
1444 fun hardening_cast_type(t: String)
1445 do
1446 if not compiler.modelbuilder.toolcontext.opt_hardening.value then return
1447 add("if({t} == NULL) \{")
1448 add_abort("cast type null")
1449 add("\}")
1450 add("if({t}->id == -1 || {t}->color == -1) \{")
1451 add("fprintf(stderr, \"Try to cast on a dead cast type: %s\\n\", {t}->name);")
1452 add_abort("cast type dead")
1453 add("\}")
1454 end
1455
1456 redef fun init_instance(mtype)
1457 do
1458 self.require_declaration("NEW_{mtype.mclass.c_name}")
1459 var compiler = self.compiler
1460 if mtype isa MGenericType and mtype.need_anchor then
1461 hardening_live_open_type(mtype)
1462 link_unresolved_type(self.frame.mpropdef.mclassdef, mtype)
1463 var recv = self.frame.arguments.first
1464 var recv_type_info = self.type_info(recv)
1465 self.require_declaration(mtype.const_color)
1466 if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
1467 return self.new_expr("NEW_{mtype.mclass.c_name}({recv_type_info}->resolution_table->types[HASH({recv_type_info}->resolution_table->mask, {mtype.const_color})])", mtype)
1468 else
1469 return self.new_expr("NEW_{mtype.mclass.c_name}({recv_type_info}->resolution_table->types[{mtype.const_color}])", mtype)
1470 end
1471 end
1472 compiler.undead_types.add(mtype)
1473 self.require_declaration("type_{mtype.c_name}")
1474 return self.new_expr("NEW_{mtype.mclass.c_name}(&type_{mtype.c_name})", mtype)
1475 end
1476
1477 redef fun type_test(value, mtype, tag)
1478 do
1479 self.add("/* {value.inspect} isa {mtype} */")
1480 var compiler = self.compiler
1481
1482 var recv = self.frame.arguments.first
1483 var recv_type_info = self.type_info(recv)
1484
1485 var res = self.new_var(bool_type)
1486
1487 var cltype = self.get_name("cltype")
1488 self.add_decl("int {cltype};")
1489 var idtype = self.get_name("idtype")
1490 self.add_decl("int {idtype};")
1491
1492 var maybe_null = self.maybe_null(value)
1493 var accept_null = "0"
1494 var ntype = mtype
1495 if ntype isa MNullableType then
1496 ntype = ntype.mtype
1497 accept_null = "1"
1498 end
1499
1500 if value.mcasttype.is_subtype(self.frame.mpropdef.mclassdef.mmodule, self.frame.mpropdef.mclassdef.bound_mtype, mtype) then
1501 self.add("{res} = 1; /* easy {value.inspect} isa {mtype}*/")
1502 if compiler.modelbuilder.toolcontext.opt_typing_test_metrics.value then
1503 self.compiler.count_type_test_skipped[tag] += 1
1504 self.add("count_type_test_skipped_{tag}++;")
1505 end
1506 return res
1507 end
1508
1509 if ntype.need_anchor then
1510 var type_struct = self.get_name("type_struct")
1511 self.add_decl("const struct type* {type_struct};")
1512
1513 # Either with resolution_table with a direct resolution
1514 hardening_live_open_type(mtype)
1515 link_unresolved_type(self.frame.mpropdef.mclassdef, mtype)
1516 self.require_declaration(mtype.const_color)
1517 if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
1518 self.add("{type_struct} = {recv_type_info}->resolution_table->types[HASH({recv_type_info}->resolution_table->mask, {mtype.const_color})];")
1519 else
1520 self.add("{type_struct} = {recv_type_info}->resolution_table->types[{mtype.const_color}];")
1521 end
1522 if compiler.modelbuilder.toolcontext.opt_typing_test_metrics.value then
1523 self.compiler.count_type_test_unresolved[tag] += 1
1524 self.add("count_type_test_unresolved_{tag}++;")
1525 end
1526 hardening_cast_type(type_struct)
1527 self.add("{cltype} = {type_struct}->color;")
1528 self.add("{idtype} = {type_struct}->id;")
1529 if maybe_null and accept_null == "0" then
1530 var is_nullable = self.get_name("is_nullable")
1531 self.add_decl("short int {is_nullable};")
1532 self.add("{is_nullable} = {type_struct}->is_nullable;")
1533 accept_null = is_nullable.to_s
1534 end
1535 else if ntype isa MClassType then
1536 compiler.undead_types.add(mtype)
1537 self.require_declaration("type_{mtype.c_name}")
1538 hardening_cast_type("(&type_{mtype.c_name})")
1539 self.add("{cltype} = type_{mtype.c_name}.color;")
1540 self.add("{idtype} = type_{mtype.c_name}.id;")
1541 if compiler.modelbuilder.toolcontext.opt_typing_test_metrics.value then
1542 self.compiler.count_type_test_resolved[tag] += 1
1543 self.add("count_type_test_resolved_{tag}++;")
1544 end
1545 else
1546 self.add("printf(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{value.inspect}\"); show_backtrace(1);")
1547 end
1548
1549 # check color is in table
1550 if maybe_null then
1551 self.add("if({value} == NULL) \{")
1552 self.add("{res} = {accept_null};")
1553 self.add("\} else \{")
1554 end
1555 var value_type_info = self.type_info(value)
1556 if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
1557 self.add("{cltype} = HASH({value_type_info}->color, {idtype});")
1558 end
1559 self.add("if({cltype} >= {value_type_info}->table_size) \{")
1560 self.add("{res} = 0;")
1561 self.add("\} else \{")
1562 self.add("{res} = {value_type_info}->type_table[{cltype}] == {idtype};")
1563 self.add("\}")
1564 if maybe_null then
1565 self.add("\}")
1566 end
1567
1568 return res
1569 end
1570
1571 redef fun is_same_type_test(value1, value2)
1572 do
1573 var res = self.new_var(bool_type)
1574 # Swap values to be symetric
1575 if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
1576 var tmp = value1
1577 value1 = value2
1578 value2 = tmp
1579 end
1580 if value1.mtype.ctype != "val*" then
1581 if value2.mtype == value1.mtype then
1582 self.add("{res} = 1; /* is_same_type_test: compatible types {value1.mtype} vs. {value2.mtype} */")
1583 else if value2.mtype.ctype != "val*" then
1584 self.add("{res} = 0; /* is_same_type_test: incompatible types {value1.mtype} vs. {value2.mtype}*/")
1585 else
1586 var mtype1 = value1.mtype.as(MClassType)
1587 self.require_declaration("class_{mtype1.c_name}")
1588 self.add("{res} = ({value2} != NULL) && ({value2}->class == &class_{mtype1.c_name}); /* is_same_type_test */")
1589 end
1590 else
1591 self.add("{res} = ({value1} == {value2}) || ({value1} != NULL && {value2} != NULL && {value1}->class == {value2}->class); /* is_same_type_test */")
1592 end
1593 return res
1594 end
1595
1596 redef fun class_name_string(value)
1597 do
1598 var res = self.get_name("var_class_name")
1599 self.add_decl("const char* {res};")
1600 if value.mtype.ctype == "val*" then
1601 self.add "{res} = {value} == NULL ? \"null\" : {value}->type->name;"
1602 else if value.mtype isa MClassType and value.mtype.as(MClassType).mclass.kind == extern_kind then
1603 self.add "{res} = \"{value.mtype.as(MClassType).mclass}\";"
1604 else
1605 self.require_declaration("type_{value.mtype.c_name}")
1606 self.add "{res} = type_{value.mtype.c_name}.name;"
1607 end
1608 return res
1609 end
1610
1611 redef fun equal_test(value1, value2)
1612 do
1613 var res = self.new_var(bool_type)
1614 if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
1615 var tmp = value1
1616 value1 = value2
1617 value2 = tmp
1618 end
1619 if value1.mtype.ctype != "val*" then
1620 if value2.mtype == value1.mtype then
1621 self.add("{res} = {value1} == {value2};")
1622 else if value2.mtype.ctype != "val*" then
1623 self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
1624 else
1625 var mtype1 = value1.mtype.as(MClassType)
1626 self.require_declaration("class_{mtype1.c_name}")
1627 self.add("{res} = ({value2} != NULL) && ({value2}->class == &class_{mtype1.c_name});")
1628 self.add("if ({res}) \{")
1629 self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
1630 self.add("\}")
1631 end
1632 return res
1633 end
1634 var maybe_null = true
1635 var test = new Array[String]
1636 var t1 = value1.mcasttype
1637 if t1 isa MNullableType then
1638 test.add("{value1} != NULL")
1639 t1 = t1.mtype
1640 else
1641 maybe_null = false
1642 end
1643 var t2 = value2.mcasttype
1644 if t2 isa MNullableType then
1645 test.add("{value2} != NULL")
1646 t2 = t2.mtype
1647 else
1648 maybe_null = false
1649 end
1650
1651 var incompatible = false
1652 var primitive
1653 if t1.ctype != "val*" then
1654 primitive = t1
1655 if t1 == t2 then
1656 # No need to compare class
1657 else if t2.ctype != "val*" then
1658 incompatible = true
1659 else if can_be_primitive(value2) then
1660 test.add("{value1}->class == {value2}->class")
1661 else
1662 incompatible = true
1663 end
1664 else if t2.ctype != "val*" then
1665 primitive = t2
1666 if can_be_primitive(value1) then
1667 test.add("{value1}->class == {value2}->class")
1668 else
1669 incompatible = true
1670 end
1671 else
1672 primitive = null
1673 end
1674
1675 if incompatible then
1676 if maybe_null then
1677 self.add("{res} = {value1} == {value2}; /* incompatible types {t1} vs. {t2}; but may be NULL*/")
1678 return res
1679 else
1680 self.add("{res} = 0; /* incompatible types {t1} vs. {t2}; cannot be NULL */")
1681 return res
1682 end
1683 end
1684 if primitive != null then
1685 test.add("((struct instance_{primitive.c_instance_name}*){value1})->value == ((struct instance_{primitive.c_instance_name}*){value2})->value")
1686 else if can_be_primitive(value1) and can_be_primitive(value2) then
1687 test.add("{value1}->class == {value2}->class")
1688 var s = new Array[String]
1689 for t, v in self.compiler.box_kinds do
1690 s.add "({value1}->class->box_kind == {v} && ((struct instance_{t.c_instance_name}*){value1})->value == ((struct instance_{t.c_instance_name}*){value2})->value)"
1691 end
1692 test.add("({s.join(" || ")})")
1693 else
1694 self.add("{res} = {value1} == {value2};")
1695 return res
1696 end
1697 self.add("{res} = {value1} == {value2} || ({test.join(" && ")});")
1698 return res
1699 end
1700
1701 fun can_be_primitive(value: RuntimeVariable): Bool
1702 do
1703 var t = value.mcasttype
1704 if t isa MNullableType then t = t.mtype
1705 if not t isa MClassType then return false
1706 var k = t.mclass.kind
1707 return k == interface_kind or t.ctype != "val*"
1708 end
1709
1710 fun maybe_null(value: RuntimeVariable): Bool
1711 do
1712 var t = value.mcasttype
1713 return t isa MNullableType or t isa MNullType
1714 end
1715
1716 redef fun array_instance(array, elttype)
1717 do
1718 var nclass = self.get_class("NativeArray")
1719 var arrayclass = self.get_class("Array")
1720 var arraytype = arrayclass.get_mtype([elttype])
1721 var res = self.init_instance(arraytype)
1722 self.add("\{ /* {res} = array_instance Array[{elttype}] */")
1723 var length = self.int_instance(array.length)
1724 var nat = native_array_instance(elttype, length)
1725 for i in [0..array.length[ do
1726 var r = self.autobox(array[i], self.object_type)
1727 self.add("((struct instance_{nclass.c_name}*){nat})->values[{i}] = (val*) {r};")
1728 end
1729 self.send(self.get_property("with_native", arrayclass.intro.bound_mtype), [res, nat, length])
1730 self.add("\}")
1731 return res
1732 end
1733
1734 fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable
1735 do
1736 var mtype = self.get_class("NativeArray").get_mtype([elttype])
1737 self.require_declaration("NEW_{mtype.mclass.c_name}")
1738 assert mtype isa MGenericType
1739 var compiler = self.compiler
1740 if mtype.need_anchor then
1741 hardening_live_open_type(mtype)
1742 link_unresolved_type(self.frame.mpropdef.mclassdef, mtype)
1743 var recv = self.frame.arguments.first
1744 var recv_type_info = self.type_info(recv)
1745 self.require_declaration(mtype.const_color)
1746 if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
1747 return self.new_expr("NEW_{mtype.mclass.c_name}({length}, {recv_type_info}->resolution_table->types[HASH({recv_type_info}->resolution_table->mask, {mtype.const_color})])", mtype)
1748 else
1749 return self.new_expr("NEW_{mtype.mclass.c_name}({length}, {recv_type_info}->resolution_table->types[{mtype.const_color}])", mtype)
1750 end
1751 end
1752 compiler.undead_types.add(mtype)
1753 self.require_declaration("type_{mtype.c_name}")
1754 return self.new_expr("NEW_{mtype.mclass.c_name}({length}, &type_{mtype.c_name})", mtype)
1755 end
1756
1757 redef fun native_array_def(pname, ret_type, arguments)
1758 do
1759 var elttype = arguments.first.mtype
1760 var nclass = self.get_class("NativeArray")
1761 var recv = "((struct instance_{nclass.c_instance_name}*){arguments[0]})->values"
1762 if pname == "[]" then
1763 self.ret(self.new_expr("{recv}[{arguments[1]}]", ret_type.as(not null)))
1764 return
1765 else if pname == "[]=" then
1766 self.add("{recv}[{arguments[1]}]={arguments[2]};")
1767 return
1768 else if pname == "length" then
1769 self.ret(self.new_expr("((struct instance_{nclass.c_instance_name}*){arguments[0]})->length", ret_type.as(not null)))
1770 return
1771 else if pname == "copy_to" then
1772 var recv1 = "((struct instance_{nclass.c_instance_name}*){arguments[1]})->values"
1773 self.add("memcpy({recv1}, {recv}, {arguments[2]}*sizeof({elttype.ctype}));")
1774 return
1775 end
1776 end
1777
1778 redef fun calloc_array(ret_type, arguments)
1779 do
1780 var mclass = self.get_class("ArrayCapable")
1781 var ft = mclass.mclass_type.arguments.first.as(MParameterType)
1782 var res = self.native_array_instance(ft, arguments[1])
1783 self.ret(res)
1784 end
1785
1786 fun link_unresolved_type(mclassdef: MClassDef, mtype: MType) do
1787 assert mtype.need_anchor
1788 var compiler = self.compiler
1789 if not compiler.live_unresolved_types.has_key(self.frame.mpropdef.mclassdef) then
1790 compiler.live_unresolved_types[self.frame.mpropdef.mclassdef] = new HashSet[MType]
1791 end
1792 compiler.live_unresolved_types[self.frame.mpropdef.mclassdef].add(mtype)
1793 end
1794 end
1795
1796 redef class MMethodDef
1797 fun separate_runtime_function: AbstractRuntimeFunction
1798 do
1799 var res = self.separate_runtime_function_cache
1800 if res == null then
1801 res = new SeparateRuntimeFunction(self)
1802 self.separate_runtime_function_cache = res
1803 end
1804 return res
1805 end
1806 private var separate_runtime_function_cache: nullable SeparateRuntimeFunction
1807
1808 fun virtual_runtime_function: AbstractRuntimeFunction
1809 do
1810 var res = self.virtual_runtime_function_cache
1811 if res == null then
1812 res = new VirtualRuntimeFunction(self)
1813 self.virtual_runtime_function_cache = res
1814 end
1815 return res
1816 end
1817 private var virtual_runtime_function_cache: nullable VirtualRuntimeFunction
1818 end
1819
1820 # The C function associated to a methoddef separately compiled
1821 class SeparateRuntimeFunction
1822 super AbstractRuntimeFunction
1823
1824 redef fun build_c_name: String do return "{mmethoddef.c_name}"
1825
1826 redef fun to_s do return self.mmethoddef.to_s
1827
1828 redef fun compile_to_c(compiler)
1829 do
1830 var mmethoddef = self.mmethoddef
1831
1832 var recv = self.mmethoddef.mclassdef.bound_mtype
1833 var v = compiler.new_visitor
1834 var selfvar = new RuntimeVariable("self", recv, recv)
1835 var arguments = new Array[RuntimeVariable]
1836 var frame = new Frame(v, mmethoddef, recv, arguments)
1837 v.frame = frame
1838
1839 var msignature = mmethoddef.msignature.resolve_for(mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.mmodule, true)
1840
1841 var sig = new FlatBuffer
1842 var comment = new FlatBuffer
1843 var ret = msignature.return_mtype
1844 if ret != null then
1845 sig.append("{ret.ctype} ")
1846 else if mmethoddef.mproperty.is_new then
1847 ret = recv
1848 sig.append("{ret.ctype} ")
1849 else
1850 sig.append("void ")
1851 end
1852 sig.append(self.c_name)
1853 sig.append("({selfvar.mtype.ctype} {selfvar}")
1854 comment.append("({selfvar}: {selfvar.mtype}")
1855 arguments.add(selfvar)
1856 for i in [0..msignature.arity[ do
1857 var mtype = msignature.mparameters[i].mtype
1858 if i == msignature.vararg_rank then
1859 mtype = v.get_class("Array").get_mtype([mtype])
1860 end
1861 comment.append(", {mtype}")
1862 sig.append(", {mtype.ctype} p{i}")
1863 var argvar = new RuntimeVariable("p{i}", mtype, mtype)
1864 arguments.add(argvar)
1865 end
1866 sig.append(")")
1867 comment.append(")")
1868 if ret != null then
1869 comment.append(": {ret}")
1870 end
1871 compiler.provide_declaration(self.c_name, "{sig};")
1872
1873 v.add_decl("/* method {self} for {comment} */")
1874 v.add_decl("{sig} \{")
1875 if ret != null then
1876 frame.returnvar = v.new_var(ret)
1877 end
1878 frame.returnlabel = v.get_name("RET_LABEL")
1879
1880 if recv != arguments.first.mtype then
1881 #print "{self} {recv} {arguments.first}"
1882 end
1883 mmethoddef.compile_inside_to_c(v, arguments)
1884
1885 v.add("{frame.returnlabel.as(not null)}:;")
1886 if ret != null then
1887 v.add("return {frame.returnvar.as(not null)};")
1888 end
1889 v.add("\}")
1890 if not self.c_name.has_substring("VIRTUAL", 0) then compiler.names[self.c_name] = "{mmethoddef.mclassdef.mmodule.name}::{mmethoddef.mclassdef.mclass.name}::{mmethoddef.mproperty.name} ({mmethoddef.location.file.filename}:{mmethoddef.location.line_start})"
1891 end
1892 end
1893
1894 # The C function associated to a methoddef on a primitive type, stored into a VFT of a class
1895 # The first parameter (the reciever) is always typed by val* in order to accept an object value
1896 class VirtualRuntimeFunction
1897 super AbstractRuntimeFunction
1898
1899 redef fun build_c_name: String do return "VIRTUAL_{mmethoddef.c_name}"
1900
1901 redef fun to_s do return self.mmethoddef.to_s
1902
1903 redef fun compile_to_c(compiler)
1904 do
1905 var mmethoddef = self.mmethoddef
1906
1907 var recv = self.mmethoddef.mclassdef.bound_mtype
1908 var v = compiler.new_visitor
1909 var selfvar = new RuntimeVariable("self", v.object_type, recv)
1910 var arguments = new Array[RuntimeVariable]
1911 var frame = new Frame(v, mmethoddef, recv, arguments)
1912 v.frame = frame
1913
1914 var sig = new FlatBuffer
1915 var comment = new FlatBuffer
1916
1917 # Because the function is virtual, the signature must match the one of the original class
1918 var intromclassdef = self.mmethoddef.mproperty.intro.mclassdef
1919 var msignature = mmethoddef.mproperty.intro.msignature.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
1920 var ret = msignature.return_mtype
1921 if ret != null then
1922 sig.append("{ret.ctype} ")
1923 else if mmethoddef.mproperty.is_new then
1924 ret = recv
1925 sig.append("{ret.ctype} ")
1926 else
1927 sig.append("void ")
1928 end
1929 sig.append(self.c_name)
1930 sig.append("({selfvar.mtype.ctype} {selfvar}")
1931 comment.append("({selfvar}: {selfvar.mtype}")
1932 arguments.add(selfvar)
1933 for i in [0..msignature.arity[ do
1934 var mtype = msignature.mparameters[i].mtype
1935 if i == msignature.vararg_rank then
1936 mtype = v.get_class("Array").get_mtype([mtype])
1937 end
1938 comment.append(", {mtype}")
1939 sig.append(", {mtype.ctype} p{i}")
1940 var argvar = new RuntimeVariable("p{i}", mtype, mtype)
1941 arguments.add(argvar)
1942 end
1943 sig.append(")")
1944 comment.append(")")
1945 if ret != null then
1946 comment.append(": {ret}")
1947 end
1948 compiler.provide_declaration(self.c_name, "{sig};")
1949
1950 v.add_decl("/* method {self} for {comment} */")
1951 v.add_decl("{sig} \{")
1952 if ret != null then
1953 frame.returnvar = v.new_var(ret)
1954 end
1955 frame.returnlabel = v.get_name("RET_LABEL")
1956
1957 var subret = v.call(mmethoddef, recv, arguments)
1958 if ret != null then
1959 assert subret != null
1960 v.assign(frame.returnvar.as(not null), subret)
1961 end
1962
1963 v.add("{frame.returnlabel.as(not null)}:;")
1964 if ret != null then
1965 v.add("return {frame.returnvar.as(not null)};")
1966 end
1967 v.add("\}")
1968 if not self.c_name.has_substring("VIRTUAL", 0) then compiler.names[self.c_name] = "{mmethoddef.mclassdef.mmodule.name}::{mmethoddef.mclassdef.mclass.name}::{mmethoddef.mproperty.name} ({mmethoddef.location.file.filename}--{mmethoddef.location.line_start})"
1969 end
1970
1971 # TODO ?
1972 redef fun call(v, arguments) do abort
1973 end
1974
1975 redef class MType
1976 fun const_color: String do return "COLOR_{c_name}"
1977
1978 # C name of the instance type to use
1979 fun c_instance_name: String do return c_name
1980 end
1981
1982 redef class MClassType
1983 redef fun c_instance_name do return mclass.c_instance_name
1984 end
1985
1986 redef class MClass
1987 # Extern classes use the C instance of kernel::Pointer
1988 fun c_instance_name: String
1989 do
1990 if kind == extern_kind then
1991 return "kernel__Pointer"
1992 else return c_name
1993 end
1994 end
1995
1996 redef class MProperty
1997 fun const_color: String do return "COLOR_{c_name}"
1998 end
1999
2000 redef class MPropDef
2001 fun const_color: String do return "COLOR_{c_name}"
2002 end