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