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