nitg-sep: fix FTs tables generation and selection
[nit.git] / src / separate_compiler.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Separate compilation of a Nit program
16 module separate_compiler
17
18
19 import global_compiler # TODO better separation of concerns
20 intrude import coloring
21 redef class ToolContext
22 # --separate
23 var opt_separate: OptionBool = new OptionBool("Use separate compilation", "--separate")
24
25 redef init
26 do
27 super
28 self.option_context.add_option(self.opt_separate)
29 end
30 end
31
32 redef class ModelBuilder
33 redef fun run_global_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis)
34 do
35 # Hijack the run_global_compiler to run the separate one if requested.
36 if self.toolcontext.opt_separate.value then
37 run_separate_compiler(mainmodule, runtime_type_analysis)
38 else
39 super
40 end
41 end
42
43 fun run_separate_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis)
44 do
45 var time0 = get_time
46 self.toolcontext.info("*** COMPILING TO C ***", 1)
47
48 var compiler = new SeparateCompiler(mainmodule, runtime_type_analysis, self)
49 var v = new SeparateCompilerVisitor(compiler)
50 compiler.header = v
51 v.add_decl("#include <stdlib.h>")
52 v.add_decl("#include <stdio.h>")
53 v.add_decl("#include <string.h>")
54 v.add_decl("#include <gc/gc.h>")
55 v.add_decl("typedef void(*nitmethod_t)(void); /* general C type representing a Nit method. */")
56 v.add_decl("typedef void* nitattribute_t; /* general C type representing a Nit attribute. */")
57
58 # Class abstract representation
59 v.add_decl("struct class \{ nitmethod_t vft[1]; \}; /* general C type representing a Nit class. */")
60 # Type abstract representation
61 v.add_decl("struct type \{ int id; int color; struct fts_table *fts_table; int type_table[1]; \}; /* general C type representing a Nit type. */")
62 v.add_decl("struct fts_table \{ struct type *fts[1]; \}; /* fts list of a C type representation. */")
63 # Instance abstract representation
64 v.add_decl("typedef struct \{ struct type *type; struct class *class; nitattribute_t attrs[1]; \} val; /* general C type representing a Nit instance. */")
65
66 # Class names (for the class_name and output_class_name methods)
67 v.add_decl("extern const char const * class_names[];")
68 v.add("const char const * class_names[] = \{")
69 for t in runtime_type_analysis.live_types do
70 v.add("\"{t}\",")
71 end
72 v.add("\};")
73
74 # The main function of the C
75
76 v = new SeparateCompilerVisitor(compiler)
77 v.add_decl("int glob_argc;")
78 v.add_decl("char **glob_argv;")
79 v.add_decl("val *glob_sys;")
80 v.add_decl("int main(int argc, char** argv) \{")
81 v.add("glob_argc = argc; glob_argv = argv;")
82 var main_type = mainmodule.sys_type
83 if main_type == null then return # Nothing to compile
84 var glob_sys = v.init_instance(main_type)
85 v.add("glob_sys = {glob_sys};")
86 var main_init = mainmodule.try_get_primitive_method("init", main_type)
87 if main_init != null then
88 v.send(main_init, [glob_sys])
89 end
90 var main_method = mainmodule.try_get_primitive_method("main", main_type)
91 if main_method != null then
92 v.send(main_method, [glob_sys])
93 end
94 v.add("\}")
95
96 # compile class structures
97 for m in mainmodule.in_importation.greaters do
98 for mclass in m.intro_mclasses do
99 compiler.compile_class_to_c(mclass)
100 end
101 end
102
103 # compile methods
104 for m in mainmodule.in_importation.greaters do
105 compiler.compile_module_to_c(m)
106 end
107
108 # compile live & cast type structures
109 var mtypes = compiler.do_global_type_coloring
110 for t in mtypes do
111 compiler.compile_type_to_c(t)
112 end
113
114 # compile live generic types selection structures
115 for mclass in model.mclasses do
116 compiler.compile_live_gentype_to_c(mclass)
117 end
118
119 write_and_make(compiler)
120 end
121 end
122
123 # Singleton that store the knowledge about the separate compilation process
124 class SeparateCompiler
125 super GlobalCompiler # TODO better separation of concerns
126
127 private var undead_types: Set[MClassType] = new HashSet[MClassType]
128 protected var typeids: HashMap[MClassType, Int] = new HashMap[MClassType, Int]
129
130 private var type_colors: Map[MClassType, Int] = typeids
131 private var type_tables: nullable Map[MClassType, Array[nullable MClassType]] = null
132 private var livetypes_tables: nullable Map[MClass, Array[nullable Object]]
133 private var livetypes_tables_sizes: nullable Map[MClass, Array[Int]]
134
135 private var class_colors: Map[MClass, Int]
136
137 private var method_colors: Map[MMethod, Int]
138 private var method_tables: Map[MClass, Array[nullable MMethodDef]]
139
140 private var attr_colors: Map[MAttribute, Int]
141 private var attr_tables: Map[MClass, Array[nullable MAttributeDef]]
142
143 private var ft_colors: Map[MParameterType, Int]
144 private var ft_tables: Map[MClass, Array[nullable MParameterType]]
145
146 init(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis, mmbuilder: ModelBuilder) do
147 # classes coloration
148 var class_coloring = new ClassColoring(mainmodule)
149 self.class_colors = class_coloring.colorize(mmbuilder.model.mclasses)
150
151 # methods coloration
152 var method_coloring = new MethodColoring(class_coloring)
153 self.method_colors = method_coloring.colorize
154 self.method_tables = method_coloring.build_property_tables
155
156 # attributes coloration
157 var attribute_coloring = new AttributeColoring(class_coloring)
158 self.attr_colors = attribute_coloring.colorize
159 self.attr_tables = attribute_coloring.build_property_tables
160
161 # fts coloration
162 var ft_coloring = new FTColoring(class_coloring)
163 self.ft_colors = ft_coloring.colorize
164 self.ft_tables = ft_coloring.build_ft_tables
165 end
166
167 # colorize live types of the program
168 private fun do_global_type_coloring: Set[MClassType] do
169 var mtypes = new HashSet[MClassType]
170 #print "undead types:"
171 #for t in self.undead_types do
172 # print t
173 #end
174 #print "live types:"
175 #for t in runtime_type_analysis.live_types do
176 # print t
177 #end
178 #print "cast types:"
179 #for t in runtime_type_analysis.live_cast_types do
180 # print t
181 #end
182 #print "--"
183 mtypes.add_all(self.runtime_type_analysis.live_types)
184 mtypes.add_all(self.runtime_type_analysis.live_cast_types)
185 mtypes.add_all(self.undead_types)
186
187 # add formal types arguments to mtypes
188 for mtype in mtypes do
189 if mtype isa MGenericType then
190 #TODO do it recursive
191 for ft in mtype.arguments do
192 if ft isa MNullableType then ft = ft.mtype
193 mtypes.add(ft.as(MClassType))
194 end
195 end
196 end
197
198 # set type unique id
199 for mtype in mtypes do
200 self.typeids[mtype] = self.typeids.length
201 end
202
203 # build livetypes tables
204 self.livetypes_tables = new HashMap[MClass, Array[nullable Object]]
205 self.livetypes_tables_sizes = new HashMap[MClass, Array[Int]]
206 for mtype in mtypes do
207 if mtype isa MGenericType then
208 var table: Array[nullable Object]
209 var sizes: Array[Int]
210 if livetypes_tables.has_key(mtype.mclass) then
211 table = livetypes_tables[mtype.mclass]
212 else
213 table = new Array[nullable Object]
214 self.livetypes_tables[mtype.mclass] = table
215 end
216 if livetypes_tables_sizes.has_key(mtype.mclass) then
217 sizes = livetypes_tables_sizes[mtype.mclass]
218 else
219 sizes = new Array[Int]
220 self.livetypes_tables_sizes[mtype.mclass] = sizes
221 end
222 build_livetype_table(mtype, 0, table, sizes)
223 end
224 end
225
226 # colorize
227 var type_coloring = new TypeColoring(self.mainmodule, self.runtime_type_analysis)
228 self.type_colors = type_coloring.colorize(mtypes)
229 self.type_tables = type_coloring.build_type_tables(mtypes, type_colors)
230
231 return mtypes
232 end
233
234 # build live gentype table recursively
235 private fun build_livetype_table(mtype: MGenericType, current_rank: Int, table: Array[nullable Object], sizes: Array[Int]) do
236 var ft = mtype.arguments[current_rank]
237 if ft isa MNullableType then ft = ft.mtype
238 var id = self.typeids[ft.as(MClassType)]
239
240 if current_rank >= sizes.length then
241 sizes[current_rank] = id + 1
242 else if id >= sizes[current_rank] then
243 sizes[current_rank] = id + 1
244 end
245
246 if id > table.length then
247 for i in [table.length .. id[ do table[i] = null
248 end
249
250 if current_rank == mtype.arguments.length - 1 then
251 table[id] = mtype
252 else
253 var ft_table = new Array[nullable Object]
254 table[id] = ft_table
255 build_livetype_table(mtype, current_rank + 1, ft_table, sizes)
256 end
257 end
258
259 private fun add_to_livetypes_table(table: Array[nullable Object], ft: MClassType) do
260 var id = self.typeids[ft]
261 for i in [table.length .. id[ do
262 table[i] = null
263 end
264 table[id] = ft
265 end
266
267 private fun compile_livetype_table(table: Array[nullable Object], buffer: Buffer, depth: Int, max: Int) do
268 for obj in table do
269 if obj == null then
270 if depth == max then
271 buffer.append("NULL,\n")
272 else
273 buffer.append("\{\},\n")
274 end
275 else if obj isa MClassType then
276 buffer.append("(struct type*) &type_{obj.c_name}, /* {obj} */\n")
277 else if obj isa Array[nullable Object] then
278 buffer.append("\{\n")
279 compile_livetype_table(obj, buffer, depth + 1, max)
280 buffer.append("\},\n")
281 end
282 end
283 end
284
285 # declare live generic types tables selection
286 private fun compile_live_gentype_to_c(mclass: MClass) do
287 if mclass.arity > 0 then
288 if self.livetypes_tables.has_key(mclass) then
289 var table = self.livetypes_tables[mclass]
290 var sign = self.livetypes_tables_sizes[mclass]
291 var table_buffer = new Buffer.from("const struct type *livetypes_{mclass.c_name}[{sign.join("][")}] = \{\n")
292 compile_livetype_table(table, table_buffer, 1, mclass.arity)
293 table_buffer.append("\};")
294
295 var v = new SeparateCompilerVisitor(self)
296 self.header.add_decl("extern const struct type *livetypes_{mclass.c_name}[{sign.join("][")}];")
297 v.add_decl(table_buffer.to_s)
298 else
299 var sign = new Array[Int].filled_with(0, mclass.arity)
300 var v = new SeparateCompilerVisitor(self)
301 self.header.add_decl("extern const struct type *livetypes_{mclass.c_name}[{sign.join("][")}];")
302 v.add_decl("const struct type *livetypes_{mclass.c_name}[{sign.join("][")}];")
303 end
304 end
305 end
306
307 # Separately compile all the method definitions of the module
308 fun compile_module_to_c(mmodule: MModule)
309 do
310 for cd in mmodule.mclassdefs do
311 for pd in cd.mpropdefs do
312 if not pd isa MMethodDef then continue
313 #print "compile {pd} @ {cd} @ {mmodule}"
314 var r = new SeparateRuntimeFunction(pd)
315 r.compile_to_c(self)
316 if cd.bound_mtype.ctype != "val*" then
317 var r2 = new VirtualRuntimeFunction(pd)
318 r2.compile_to_c(self)
319 end
320 end
321 end
322 end
323
324 # Globaly compile the type structure of a live type
325 fun compile_type_to_c(mtype: MClassType)
326 do
327 var c_name = mtype.c_name
328 var v = new SeparateCompilerVisitor(self)
329 v.add_decl("/* runtime type {mtype} */")
330
331 # extern const struct type_X
332 self.header.add_decl("extern const struct type_{c_name} type_{c_name};")
333 self.header.add_decl("struct type_{c_name} \{")
334 self.header.add_decl("int id;")
335 self.header.add_decl("int color;")
336 self.header.add_decl("const struct fts_table_{c_name} *fts_table;")
337 self.header.add_decl("int type_table[{self.type_tables[mtype].length}];")
338 self.header.add_decl("\};")
339
340 # extern const struct fst_table_X fst_table_X
341 self.header.add_decl("extern const struct fts_table_{c_name} fts_table_{c_name};")
342 self.header.add_decl("struct fts_table_{c_name} \{")
343 self.header.add_decl("struct type *fts[{self.ft_tables[mtype.mclass].length}];")
344 self.header.add_decl("\};")
345
346 # const struct type_X
347 v.add_decl("const struct type_{c_name} type_{c_name} = \{")
348 v.add_decl("{self.typeids[mtype]},")
349 v.add_decl("{self.type_colors[mtype]},")
350 v.add_decl("&fts_table_{c_name},")
351 v.add_decl("\{")
352 for stype in self.type_tables[mtype] do
353 if stype == null then
354 v.add_decl("-1, /* empty */")
355 else
356 v.add_decl("{self.typeids[stype]}, /* {stype} */")
357 end
358 end
359 v.add_decl("\},")
360 v.add_decl("\};")
361
362 # const struct fst_table_X fst_table_X
363 v.add_decl("const struct fts_table_{c_name} fts_table_{c_name} = \{")
364 v.add_decl("\{")
365
366 for ft in self.ft_tables[mtype.mclass] do
367 if ft == null then
368 v.add_decl("NULL, /* empty */")
369 else
370 var id = -1
371 var ntype: MType
372 if ft.mclass == mtype.mclass then
373 ntype = mtype.arguments[ft.rank]
374 else
375 ntype = ft.anchor_to(self.mainmodule, mtype)
376 end
377 if ntype isa MNullableType then ntype = ntype.mtype
378 var ftype = ntype.as(MClassType)
379 if self.typeids.has_key(ftype) then
380 v.add_decl("(struct type*)&type_{ftype.c_name}, /* {ft} ({ftype}) */")
381 else
382 v.add_decl("NULL, /* empty ({ft} not a live type) */")
383 end
384 end
385 end
386
387 v.add_decl("\},")
388 v.add_decl("\};")
389 end
390
391 # Globally compile the table of the class mclass
392 # In a link-time optimisation compiler, tables are globally computed
393 # In a true separate compiler (a with dynamic loading) you cannot do this unfortnally
394 fun compile_class_to_c(mclass: MClass)
395 do
396 var mtype = mclass.intro.bound_mtype
397 var c_name = mclass.c_name
398
399 var vft = self.method_tables[mclass]
400 var attrs = self.attr_tables[mclass]
401 var v = new SeparateCompilerVisitor(self)
402
403 v.add_decl("/* runtime class {c_name} */")
404 var idnum = classids.length
405 var idname = "ID_" + c_name
406 self.classids[mtype] = idname
407 #self.header.add_decl("#define {idname} {idnum} /* {c_name} */")
408
409 self.header.add_decl("struct class_{c_name} \{")
410 self.header.add_decl("nitmethod_t vft[{vft.length}];")
411
412 if mtype.ctype != "val*" then
413 # Is the Nit type is native then the struct is a box with two fields:
414 # * the `vft` to be polymorph
415 # * the `value` that contains the native value.
416 self.header.add_decl("{mtype.ctype} value;")
417 end
418
419 # Collect all attributes and associate them a field in the structure.
420 # Note: we do not try to optimize the order and helps CC to optimize the client code.
421 for cd in mtype.collect_mclassdefs(self.mainmodule) do
422 for p in cd.intro_mproperties do
423 if not p isa MAttribute then continue
424 var t = p.intro.static_mtype.as(not null)
425 t = t.anchor_to(self.mainmodule, mtype)
426 self.header.add_decl("{t.ctype} {p.intro.c_name}; /* {p}: {t} */")
427 end
428 end
429 self.header.add_decl("\};")
430
431 # Build class vft
432 self.header.add_decl("extern const struct class_{c_name} class_{c_name};")
433 v.add_decl("const struct class_{c_name} class_{c_name} = \{")
434 v.add_decl("\{")
435 for i in [0 .. vft.length[ do
436 var mpropdef = vft[i]
437 if mpropdef == null then
438 v.add_decl("NULL, /* empty */")
439 else
440 if mpropdef.mclassdef.bound_mtype.ctype != "val*" then
441 v.add_decl("(nitmethod_t)VIRTUAL_{mpropdef.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
442 else
443 v.add_decl("(nitmethod_t){mpropdef.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
444 end
445 end
446 end
447 v.add_decl("\}")
448 v.add_decl("\};")
449
450 if mtype.ctype != "val*" then
451 #Build instance struct
452 self.header.add_decl("struct instance_{c_name} \{")
453 self.header.add_decl("const struct type *type;")
454 self.header.add_decl("const struct class *class;")
455 self.header.add_decl("{mtype.ctype} value;")
456 self.header.add_decl("\};")
457
458 self.header.add_decl("val* BOX_{c_name}({mtype.ctype}, struct type*);")
459 v.add_decl("/* allocate {mtype} */")
460 v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value, struct type* type) \{")
461 v.add("struct instance_{c_name}*res = GC_MALLOC(sizeof(struct instance_{c_name}));")
462 v.add("res->type = type;")
463 v.add("res->class = (struct class*) &class_{c_name};")
464 v.add("res->value = value;")
465 v.add("return (val*)res;")
466 v.add("\}")
467 return
468 end
469
470 var is_native_array = mclass.name == "NativeArray"
471
472 var sig
473 if is_native_array then
474 sig = "int length, struct type* type"
475 else
476 sig = "struct type* type"
477 end
478
479 #Build instance struct
480 #extern const struct instance_array__NativeArray instance_array__NativeArray;
481 self.header.add_decl("struct instance_{c_name} \{")
482 self.header.add_decl("const struct type *type;")
483 self.header.add_decl("const struct class *class;")
484 self.header.add_decl("nitattribute_t attrs[{attrs.length}];")
485 if is_native_array then
486 # NativeArrays are just a instance header followed by an array of values
487 self.header.add_decl("val* values[0];")
488 end
489 self.header.add_decl("\};")
490
491
492 self.header.add_decl("{mtype.ctype} NEW_{c_name}({sig});")
493 v.add_decl("/* allocate {mtype} */")
494 v.add_decl("{mtype.ctype} NEW_{c_name}({sig}) \{")
495 var res = v.new_named_var(mtype, "self")
496 res.is_exact = true
497 if is_native_array then
498 var mtype_elt = mtype.arguments.first
499 v.add("{res} = GC_MALLOC(sizeof(struct instance_{c_name}) + length*sizeof({mtype_elt.ctype}));")
500 else
501 v.add("{res} = GC_MALLOC(sizeof(struct instance_{c_name}));")
502 end
503 #v.add("{res} = calloc(sizeof(struct instance_{c_name}), 1);")
504 v.add("{res}->type = type;")
505 v.add("{res}->class = (struct class*) &class_{c_name};")
506
507 for cd in mtype.collect_mclassdefs(self.mainmodule)
508 do
509 var n = self.modelbuilder.mclassdef2nclassdef[cd]
510 for npropdef in n.n_propdefs do
511 if npropdef isa AAttrPropdef then
512 npropdef.init_expr(v, res)
513 end
514 end
515 end
516 v.add("return {res};")
517 v.add("\}")
518 end
519 end
520
521 # The C function associated to a methoddef separately compiled
522 class SeparateRuntimeFunction
523 super AbstractRuntimeFunction
524
525 redef fun build_c_name: String
526 do
527 return "{mmethoddef.c_name}"
528 end
529
530 redef fun to_s do return self.mmethoddef.to_s
531
532 redef fun compile_to_c(compiler)
533 do
534 var mmethoddef = self.mmethoddef
535
536 var recv = self.mmethoddef.mclassdef.bound_mtype
537 var v = new SeparateCompilerVisitor(compiler)
538 var selfvar = new RuntimeVariable("self", recv, recv)
539 var arguments = new Array[RuntimeVariable]
540 var frame = new Frame(v, mmethoddef, recv, arguments)
541 v.frame = frame
542
543 var sig = new Buffer
544 var comment = new Buffer
545 var ret = mmethoddef.msignature.return_mtype
546 if ret != null then
547 ret = v.resolve_for(ret, selfvar)
548 sig.append("{ret.ctype} ")
549 else if mmethoddef.mproperty.is_new then
550 ret = recv
551 sig.append("{ret.ctype} ")
552 else
553 sig.append("void ")
554 end
555 sig.append(self.c_name)
556 sig.append("({selfvar.mtype.ctype} {selfvar}")
557 comment.append("(self: {selfvar}")
558 arguments.add(selfvar)
559 for i in [0..mmethoddef.msignature.arity[ do
560 var mtype = mmethoddef.msignature.mparameters[i].mtype
561 if i == mmethoddef.msignature.vararg_rank then
562 mtype = v.get_class("Array").get_mtype([mtype])
563 end
564 mtype = v.resolve_for(mtype, selfvar)
565 comment.append(", {mtype}")
566 sig.append(", {mtype.ctype} p{i}")
567 var argvar = new RuntimeVariable("p{i}", mtype, mtype)
568 arguments.add(argvar)
569 end
570 sig.append(")")
571 comment.append(")")
572 if ret != null then
573 comment.append(": {ret}")
574 end
575 compiler.header.add_decl("{sig};")
576
577 v.add_decl("/* method {self} for {comment} */")
578 v.add_decl("{sig} \{")
579 if ret != null then
580 frame.returnvar = v.new_var(ret)
581 end
582 frame.returnlabel = v.get_name("RET_LABEL")
583
584 if recv != arguments.first.mtype then
585 #print "{self} {recv} {arguments.first}"
586 end
587 mmethoddef.compile_inside_to_c(v, arguments)
588
589 v.add("{frame.returnlabel.as(not null)}:;")
590 if ret != null then
591 v.add("return {frame.returnvar.as(not null)};")
592 end
593 v.add("\}")
594 end
595 end
596
597 # The C function associated to a methoddef on a primitive type, stored into a VFT of a class
598 # The first parameter (the reciever) is always typed by val* in order to accept an object value
599 class VirtualRuntimeFunction
600 super AbstractRuntimeFunction
601
602 redef fun build_c_name: String
603 do
604 return "VIRTUAL_{mmethoddef.c_name}"
605 end
606
607 redef fun to_s do return self.mmethoddef.to_s
608
609 redef fun compile_to_c(compiler)
610 do
611 var mmethoddef = self.mmethoddef
612
613 var recv = self.mmethoddef.mclassdef.bound_mtype
614 var v = new SeparateCompilerVisitor(compiler)
615 var selfvar = new RuntimeVariable("self", v.object_type, recv)
616 var arguments = new Array[RuntimeVariable]
617 var frame = new Frame(v, mmethoddef, recv, arguments)
618 v.frame = frame
619
620 var sig = new Buffer
621 var comment = new Buffer
622
623 # Because the function is virtual, the signature must match the one of the original class
624 var intromclassdef = self.mmethoddef.mproperty.intro.mclassdef
625 var msignature = mmethoddef.mproperty.intro.msignature.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
626 var ret = msignature.return_mtype
627 if ret != null then
628 sig.append("{ret.ctype} ")
629 else if mmethoddef.mproperty.is_new then
630 ret = recv
631 sig.append("{ret.ctype} ")
632 else
633 sig.append("void ")
634 end
635 sig.append(self.c_name)
636 sig.append("({selfvar.mtype.ctype} {selfvar}")
637 comment.append("(self: {selfvar}")
638 arguments.add(selfvar)
639 for i in [0..msignature.arity[ do
640 var mtype = msignature.mparameters[i].mtype
641 if i == msignature.vararg_rank then
642 mtype = v.get_class("Array").get_mtype([mtype])
643 end
644 comment.append(", {mtype}")
645 sig.append(", {mtype.ctype} p{i}")
646 var argvar = new RuntimeVariable("p{i}", mtype, mtype)
647 arguments.add(argvar)
648 end
649 sig.append(")")
650 comment.append(")")
651 if ret != null then
652 comment.append(": {ret}")
653 end
654 compiler.header.add_decl("{sig};")
655
656 v.add_decl("/* method {self} for {comment} */")
657 v.add_decl("{sig} \{")
658 if ret != null then
659 frame.returnvar = v.new_var(ret)
660 end
661 frame.returnlabel = v.get_name("RET_LABEL")
662
663 if recv != arguments.first.mtype then
664 #print "{self} {recv} {arguments.first}"
665 end
666 mmethoddef.compile_inside_to_c(v, arguments)
667
668 v.add("{frame.returnlabel.as(not null)}:;")
669 if ret != null then
670 v.add("return {frame.returnvar.as(not null)};")
671 end
672 v.add("\}")
673 end
674
675 redef fun call(v, arguments)
676 do
677 abort
678 # TODO ?
679 end
680 end
681
682 # A visitor on the AST of property definition that generate the C code of a separate compilation process.
683 class SeparateCompilerVisitor
684 super GlobalCompilerVisitor # TODO better separation of concerns
685
686 redef fun adapt_signature(m: MMethodDef, args: Array[RuntimeVariable])
687 do
688 var recv = args.first
689 if recv.mtype.ctype != m.mclassdef.mclass.mclass_type.ctype then
690 args.first = self.autobox(args.first, m.mclassdef.mclass.mclass_type)
691 end
692 for i in [0..m.msignature.arity[ do
693 var t = m.msignature.mparameters[i].mtype
694 if i == m.msignature.vararg_rank then
695 t = args[i+1].mtype
696 end
697 t = self.resolve_for(t, recv)
698 args[i+1] = self.autobox(args[i+1], t)
699 end
700 end
701
702 # Box or unbox a value to another type iff a C type conversion is needed
703 # ENSURE: result.mtype.ctype == mtype.ctype
704 redef fun autobox(value: RuntimeVariable, mtype: MType): RuntimeVariable
705 do
706 if value.mtype.ctype == mtype.ctype then
707 return value
708 else if value.mtype.ctype == "val*" then
709 return self.new_expr("((struct instance_{mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
710 else if mtype.ctype == "val*" then
711 var valtype = value.mtype.as(MClassType)
712 var res = self.new_var(mtype)
713 if not compiler.runtime_type_analysis.live_types.has(valtype) then
714 self.add("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */")
715 self.add("printf(\"Dead code executed!\\n\"); exit(1);")
716 return res
717 end
718 var totype = value.mtype
719 if totype isa MNullableType then totype = totype.mtype
720 self.add("{res} = BOX_{valtype.c_name}({value}, (struct type*) &type_{totype.c_name}); /* autobox from {value.mtype} to {mtype} */")
721 return res
722 else
723 # Bad things will appen!
724 var res = self.new_var(mtype)
725 self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */")
726 self.add("printf(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); exit(1);")
727 return res
728 end
729 end
730
731 redef fun send(mmethod, arguments)
732 do
733 if arguments.first.mtype.ctype != "val*" then
734 assert arguments.first.mtype == arguments.first.mcasttype
735 return self.monomorphic_send(mmethod, arguments.first.mtype, arguments)
736 end
737
738 var res: nullable RuntimeVariable
739 var msignature = mmethod.intro.msignature.resolve_for(mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.mmodule, true)
740 var ret = msignature.return_mtype
741 if mmethod.is_new then
742 ret = arguments.first.mtype
743 res = self.new_var(ret)
744 else if ret == null then
745 res = null
746 else
747 ret = self.resolve_for(ret, arguments.first)
748 res = self.new_var(ret)
749 end
750
751 var s = new Buffer
752 var ss = new Buffer
753
754 var recv = arguments.first
755 s.append("val*")
756 ss.append("{recv}")
757 for i in [0..msignature.arity[ do
758 var a = arguments[i+1]
759 var t = msignature.mparameters[i].mtype
760 s.append(", {t.ctype}")
761 a = self.autobox(a, t)
762 ss.append(", {a}")
763 end
764
765 var maybenull = recv.mcasttype isa MNullableType
766 if maybenull then
767 self.add("if ({recv} == NULL) \{")
768 if mmethod.name == "==" then
769 assert res != null
770 var arg = arguments[1]
771 if arg.mcasttype isa MNullableType then
772 self.add("{res} = ({arg} == NULL);")
773 else if arg.mcasttype isa MNullType then
774 self.add("{res} = 1; /* is null */")
775 else
776 self.add("{res} = 0; /* {arg.inspect} cannot be null */")
777 end
778 else if mmethod.name == "!=" then
779 assert res != null
780 var arg = arguments[1]
781 if arg.mcasttype isa MNullableType then
782 self.add("{res} = ({arg} != NULL);")
783 else if arg.mcasttype isa MNullType then
784 self.add("{res} = 0; /* is null */")
785 else
786 self.add("{res} = 1; /* {arg.inspect} cannot be null */")
787 end
788 else
789 self.add_abort("Reciever is null")
790 end
791 self.add("\} else \{")
792 end
793
794 var color = self.compiler.as(SeparateCompiler).method_colors[mmethod]
795 var r
796 if ret == null then r = "void" else r = ret.ctype
797 var call = "(({r} (*)({s}))({arguments.first}->class->vft[{color}]))({ss}) /* {mmethod} on {arguments.first.inspect}*/"
798
799 if res != null then
800 self.add("{res} = {call};")
801 else
802 self.add("{call};")
803 end
804
805 if maybenull then
806 self.add("\}")
807 end
808
809 return res
810 end
811
812 redef fun call(mmethoddef, recvtype, arguments)
813 do
814 var res: nullable RuntimeVariable
815 var ret = mmethoddef.msignature.return_mtype
816 if mmethoddef.mproperty.is_new then
817 ret = arguments.first.mtype
818 res = self.new_var(ret)
819 else if ret == null then
820 res = null
821 else
822 ret = self.resolve_for(ret, arguments.first)
823 res = self.new_var(ret)
824 end
825
826 # Autobox arguments
827 self.adapt_signature(mmethoddef, arguments)
828
829 if res == null then
830 self.add("{mmethoddef.c_name}({arguments.join(", ")});")
831 return null
832 else
833 self.add("{res} = {mmethoddef.c_name}({arguments.join(", ")});")
834 end
835
836 return res
837 end
838
839 redef fun isset_attribute(a, recv)
840 do
841 # FIXME: Here we inconditionally return boxed primitive attributes
842 var res = self.new_var(bool_type)
843 self.add("{res} = {recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}] != NULL; /* {a} on {recv.inspect}*/")
844 return res
845 end
846
847 redef fun read_attribute(a, recv)
848 do
849 # FIXME: Here we inconditionally return boxed primitive attributes
850 var ret = a.intro.static_mtype.as(not null)
851 ret = self.resolve_for(ret, recv)
852 var cret = self.object_type.as_nullable
853 var res = self.new_var(cret)
854 res.mcasttype = ret
855 self.add("{res} = {recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}]; /* {a} on {recv.inspect} */")
856 if not ret isa MNullableType then
857 self.add("if ({res} == NULL) \{")
858 self.add_abort("Uninitialized attribute {a.name}")
859 self.add("\}")
860 end
861
862 return res
863 end
864
865 redef fun write_attribute(a, recv, value)
866 do
867 # FIXME: Here we inconditionally box primitive attributes
868 value = self.autobox(value, self.object_type.as_nullable)
869 self.add("{recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}] = {value}; /* {a} on {recv.inspect} */")
870 end
871
872 redef fun init_instance(mtype)
873 do
874 var compiler = self.compiler.as(SeparateCompiler)
875 if mtype isa MGenericType and mtype.need_anchor then
876 var buff = new Buffer
877 var rank = 0
878 for ft in mtype.arguments do
879 if ft isa MParameterType then
880 var ftcolor = compiler.ft_colors[ft]
881 buff.append("[self->type->fts_table->fts[{ftcolor}]->id]")
882 else if ft isa MGenericType and ft.need_anchor then
883 var ft_decl = mtype.mclass.mclass_type.arguments[rank]
884 var ftcolor = compiler.ft_colors[ft_decl.as(MParameterType)]
885 buff.append("[self->type->fts_table->fts[{ftcolor}]->id]")
886 else
887 var typecolor = compiler.type_colors[ft.as(MClassType)]
888 buff.append("[{typecolor}]")
889 end
890 rank += 1
891 end
892 mtype = self.anchor(mtype).as(MClassType)
893 return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) livetypes_{mtype.mclass.c_name}{buff.to_s})", mtype)
894 end
895 compiler.undead_types.add(mtype)
896 return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) &type_{mtype.c_name})", mtype)
897 end
898
899 redef fun type_test(value, mtype)
900 do
901 var compiler = self.compiler.as(SeparateCompiler)
902 var res = self.new_var(bool_type)
903 var buff = new Buffer
904
905 var s: String
906 if mtype isa MNullableType then
907 mtype = mtype.mtype
908 s = "{value} == NULL ||"
909 else
910 s = "{value} != NULL &&"
911 end
912 if mtype isa MGenericType and mtype.need_anchor then
913 for ft in mtype.mclass.mclass_type.arguments do
914 var ftcolor = compiler.ft_colors[ft.as(MParameterType)]
915 buff.append("[self->type->fts_table->fts[{ftcolor}]->id]")
916 end
917 self.add("{res} = {s} {value}->type->type_table[livetypes_{mtype.mclass.c_name}{buff.to_s}->color] == livetypes_{mtype.mclass.c_name}{buff.to_s}->id;")
918 else if mtype isa MClassType then
919 compiler.undead_types.add(mtype)
920 self.add("{res} = {s} {value}->type->type_table[type_{mtype.c_name}.color] == type_{mtype.c_name}.id;")
921 else if mtype isa MParameterType then
922 var ftcolor = compiler.ft_colors[mtype]
923 self.add("{res} = {s} {value}->type->type_table[self->type->fts_table->fts[{ftcolor}]->color] == self->type->fts_table->fts[{ftcolor}]->id;")
924 else
925 add("printf(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{value.inspect}\"); exit(1);")
926 end
927
928 return res
929 end
930
931 redef fun is_same_type_test(value1, value2)
932 do
933 var res = self.new_var(bool_type)
934 # Swap values to be symetric
935 if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
936 var tmp = value1
937 value1 = value2
938 value2 = tmp
939 end
940 if value1.mtype.ctype != "val*" then
941 if value2.mtype.ctype == value1.mtype.ctype then
942 self.add("{res} = 1; /* is_same_type_test: compatible types {value1.mtype} vs. {value2.mtype} */")
943 else if value2.mtype.ctype != "val*" then
944 self.add("{res} = 0; /* is_same_type_test: incompatible types {value1.mtype} vs. {value2.mtype}*/")
945 else
946 var mtype1 = value1.mtype.as(MClassType)
947 self.add("{res} = ({value2} != NULL) && ({value2}->class == (struct class*) &class_{mtype1.c_name}); /* is_same_type_test */")
948 end
949 else
950 self.add("{res} = ({value1} == {value2}) || ({value1} != NULL && {value2} != NULL && {value1}->class == {value2}->class); /* is_same_type_test */")
951 end
952 return res
953 end
954
955 redef fun class_name_string(value1)
956 do
957 var res = self.get_name("var_class_name")
958 self.add_decl("const char* {res};")
959 # TODO
960 add("printf(\"NOT YET IMPLEMENTED: class_name_string(%s).\\n\", \"{value1.inspect}\"); exit(1);")
961 return res
962 end
963
964 redef fun equal_test(value1, value2)
965 do
966 var res = self.new_var(bool_type)
967 if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
968 var tmp = value1
969 value1 = value2
970 value2 = tmp
971 end
972 if value1.mtype.ctype != "val*" then
973 if value2.mtype.ctype == value1.mtype.ctype then
974 self.add("{res} = {value1} == {value2};")
975 else if value2.mtype.ctype != "val*" then
976 self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
977 else
978 var mtype1 = value1.mtype.as(MClassType)
979 self.add("{res} = ({value2} != NULL) && ({value2}->class == (struct class*) &class_{mtype1.c_name});")
980 self.add("if ({res}) \{")
981 self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
982 self.add("\}")
983 end
984 else
985 var s = new Array[String]
986 # This is just ugly on so many level. this works but must be rewriten
987 for t in self.compiler.live_primitive_types do
988 if not t.is_subtype(self.compiler.mainmodule, null, value1.mcasttype) then continue
989 if not t.is_subtype(self.compiler.mainmodule, null, value2.mcasttype) then continue
990 s.add "({value1}->class == (struct class*)&class_{t.c_name} && ((struct instance_{t.c_name}*){value1})->value == ((struct instance_{t.c_name}*){value2})->value)"
991 end
992 if s.is_empty then
993 self.add("{res} = {value1} == {value2};")
994 else
995 self.add("{res} = {value1} == {value2} || ({value1} != NULL && {value2} != NULL && {value1}->class == {value2}->class && ({s.join(" || ")}));")
996 end
997 end
998 return res
999 end
1000
1001 redef fun array_instance(array, elttype)
1002 do
1003 var compiler = self.compiler.as(SeparateCompiler)
1004 var nclass = self.get_class("NativeArray")
1005 elttype = self.anchor(elttype)
1006 var arraytype = self.get_class("Array").get_mtype([elttype])
1007 var res = self.init_instance(arraytype)
1008 self.add("\{ /* {res} = array_instance Array[{elttype}] */")
1009 var nat = self.new_var(self.get_class("NativeArray").get_mtype([elttype]))
1010 nat.is_exact = true
1011 compiler.undead_types.add(nat.mtype.as(MClassType))
1012 self.add("{nat} = NEW_{nclass.c_name}({array.length}, (struct type *) &type_{nat.mtype.c_name});")
1013 for i in [0..array.length[ do
1014 var r = self.autobox(array[i], self.object_type)
1015 self.add("((struct instance_{nclass.c_name}*){nat})->values[{i}] = (val*) {r};")
1016 end
1017 var length = self.int_instance(array.length)
1018 self.send(self.get_property("with_native", arraytype), [res, nat, length])
1019 self.check_init_instance(res)
1020 self.add("\}")
1021 return res
1022 end
1023
1024 redef fun native_array_def(pname, ret_type, arguments)
1025 do
1026 var elttype = arguments.first.mtype
1027 var nclass = self.get_class("NativeArray")
1028 var recv = "((struct instance_{nclass.c_name}*){arguments[0]})->values"
1029 if pname == "[]" then
1030 self.ret(self.new_expr("{recv}[{arguments[1]}]", ret_type.as(not null)))
1031 return
1032 else if pname == "[]=" then
1033 self.add("{recv}[{arguments[1]}]={arguments[2]};")
1034 return
1035 else if pname == "copy_to" then
1036 var recv1 = "((struct instance_{nclass.c_name}*){arguments[1]})->values"
1037 self.add("memcpy({recv1}, {recv}, {arguments[2]}*sizeof({elttype.ctype}));")
1038 return
1039 end
1040 end
1041
1042 redef fun calloc_array(ret_type, arguments)
1043 do
1044 var ret = ret_type.as(MClassType)
1045 var compiler = self.compiler.as(SeparateCompiler)
1046 compiler.undead_types.add(ret)
1047 self.ret(self.new_expr("NEW_{ret.mclass.c_name}({arguments[1]}, (struct type*) &type_{ret_type.c_name})", ret_type))
1048 end
1049 end
1050
1051 redef class MClass
1052 # Return the name of the C structure associated to a Nit class
1053 fun c_name: String do
1054 var res = self.c_name_cache
1055 if res != null then return res
1056 res = "{intro_mmodule.name.to_cmangle}__{name.to_cmangle}"
1057 self.c_name_cache = res
1058 return res
1059 end
1060 private var c_name_cache: nullable String
1061 end