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