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