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