nitg-sep: handles native arrays
[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 v.add_decl("struct instance_{c_name} \{")
483 v.add_decl("const struct type *type;")
484 v.add_decl("const struct class *class;")
485 v.add_decl("nitattribute_t attrs[{attrs.length}];")
486 if is_native_array then
487 # NativeArrays are just a instance header followed by an array of values
488 v.add_decl("val* values[1];")
489 end
490 v.add_decl("\};")
491
492
493 self.header.add_decl("{mtype.ctype} NEW_{c_name}({sig});")
494 v.add_decl("/* allocate {mtype} */")
495 v.add_decl("{mtype.ctype} NEW_{c_name}({sig}) \{")
496 var res = v.new_named_var(mtype, "self")
497 res.is_exact = true
498 if is_native_array then
499 var mtype_elt = mtype.arguments.first
500 v.add("{res} = GC_MALLOC(sizeof(struct instance_{c_name}) + length*sizeof({mtype_elt.ctype}));")
501 else
502 v.add("{res} = GC_MALLOC(sizeof(struct instance_{c_name}));")
503 end
504 #v.add("{res} = calloc(sizeof(struct instance_{c_name}), 1);")
505 v.add("{res}->type = type;")
506 v.add("{res}->class = (struct class*) &class_{c_name};")
507
508 for cd in mtype.collect_mclassdefs(self.mainmodule)
509 do
510 var n = self.modelbuilder.mclassdef2nclassdef[cd]
511 for npropdef in n.n_propdefs do
512 if npropdef isa AAttrPropdef then
513 npropdef.init_expr(v, res)
514 end
515 end
516 end
517 v.add("return {res};")
518 v.add("\}")
519 end
520 end
521
522 # The C function associated to a methoddef separately compiled
523 class SeparateRuntimeFunction
524 super AbstractRuntimeFunction
525
526 redef fun build_c_name: String
527 do
528 return "{mmethoddef.c_name}"
529 end
530
531 redef fun to_s do return self.mmethoddef.to_s
532
533 redef fun compile_to_c(compiler)
534 do
535 var mmethoddef = self.mmethoddef
536
537 var recv = self.mmethoddef.mclassdef.bound_mtype
538 var v = new SeparateCompilerVisitor(compiler)
539 var selfvar = new RuntimeVariable("self", recv, recv)
540 var arguments = new Array[RuntimeVariable]
541 var frame = new Frame(v, mmethoddef, recv, arguments)
542 v.frame = frame
543
544 var sig = new Buffer
545 var comment = new Buffer
546 var ret = mmethoddef.msignature.return_mtype
547 if ret != null then
548 ret = v.resolve_for(ret, selfvar)
549 sig.append("{ret.ctype} ")
550 else if mmethoddef.mproperty.is_new then
551 ret = recv
552 sig.append("{ret.ctype} ")
553 else
554 sig.append("void ")
555 end
556 sig.append(self.c_name)
557 sig.append("({selfvar.mtype.ctype} {selfvar}")
558 comment.append("(self: {selfvar}")
559 arguments.add(selfvar)
560 for i in [0..mmethoddef.msignature.arity[ do
561 var mtype = mmethoddef.msignature.mparameters[i].mtype
562 if i == mmethoddef.msignature.vararg_rank then
563 mtype = v.get_class("Array").get_mtype([mtype])
564 end
565 mtype = v.resolve_for(mtype, selfvar)
566 comment.append(", {mtype}")
567 sig.append(", {mtype.ctype} p{i}")
568 var argvar = new RuntimeVariable("p{i}", mtype, mtype)
569 arguments.add(argvar)
570 end
571 sig.append(")")
572 comment.append(")")
573 if ret != null then
574 comment.append(": {ret}")
575 end
576 compiler.header.add_decl("{sig};")
577
578 v.add_decl("/* method {self} for {comment} */")
579 v.add_decl("{sig} \{")
580 if ret != null then
581 frame.returnvar = v.new_var(ret)
582 end
583 frame.returnlabel = v.get_name("RET_LABEL")
584
585 if recv != arguments.first.mtype then
586 #print "{self} {recv} {arguments.first}"
587 end
588 mmethoddef.compile_inside_to_c(v, arguments)
589
590 v.add("{frame.returnlabel.as(not null)}:;")
591 if ret != null then
592 v.add("return {frame.returnvar.as(not null)};")
593 end
594 v.add("\}")
595 end
596 end
597
598 # The C function associated to a methoddef on a primitive type, stored into a VFT of a class
599 # The first parameter (the reciever) is always typed by val* in order to accept an object value
600 class VirtualRuntimeFunction
601 super AbstractRuntimeFunction
602
603 redef fun build_c_name: String
604 do
605 return "VIRTUAL_{mmethoddef.c_name}"
606 end
607
608 redef fun to_s do return self.mmethoddef.to_s
609
610 redef fun compile_to_c(compiler)
611 do
612 var mmethoddef = self.mmethoddef
613
614 var recv = self.mmethoddef.mclassdef.bound_mtype
615 var v = new SeparateCompilerVisitor(compiler)
616 var selfvar = new RuntimeVariable("self", v.object_type, recv)
617 var arguments = new Array[RuntimeVariable]
618 var frame = new Frame(v, mmethoddef, recv, arguments)
619 v.frame = frame
620
621 var sig = new Buffer
622 var comment = new Buffer
623
624 # Because the function is virtual, the signature must match the one of the original class
625 var intromclassdef = self.mmethoddef.mproperty.intro.mclassdef
626 var msignature = mmethoddef.mproperty.intro.msignature.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
627 var ret = msignature.return_mtype
628 if ret != null then
629 sig.append("{ret.ctype} ")
630 else if mmethoddef.mproperty.is_new then
631 ret = recv
632 sig.append("{ret.ctype} ")
633 else
634 sig.append("void ")
635 end
636 sig.append(self.c_name)
637 sig.append("({selfvar.mtype.ctype} {selfvar}")
638 comment.append("(self: {selfvar}")
639 arguments.add(selfvar)
640 for i in [0..msignature.arity[ do
641 var mtype = msignature.mparameters[i].mtype
642 if i == msignature.vararg_rank then
643 mtype = v.get_class("Array").get_mtype([mtype])
644 end
645 comment.append(", {mtype}")
646 sig.append(", {mtype.ctype} p{i}")
647 var argvar = new RuntimeVariable("p{i}", mtype, mtype)
648 arguments.add(argvar)
649 end
650 sig.append(")")
651 comment.append(")")
652 if ret != null then
653 comment.append(": {ret}")
654 end
655 compiler.header.add_decl("{sig};")
656
657 v.add_decl("/* method {self} for {comment} */")
658 v.add_decl("{sig} \{")
659 if ret != null then
660 frame.returnvar = v.new_var(ret)
661 end
662 frame.returnlabel = v.get_name("RET_LABEL")
663
664 if recv != arguments.first.mtype then
665 #print "{self} {recv} {arguments.first}"
666 end
667 mmethoddef.compile_inside_to_c(v, arguments)
668
669 v.add("{frame.returnlabel.as(not null)}:;")
670 if ret != null then
671 v.add("return {frame.returnvar.as(not null)};")
672 end
673 v.add("\}")
674 end
675
676 redef fun call(v, arguments)
677 do
678 abort
679 # TODO ?
680 end
681 end
682
683 # A visitor on the AST of property definition that generate the C code of a separate compilation process.
684 class SeparateCompilerVisitor
685 super GlobalCompilerVisitor # TODO better separation of concerns
686
687 redef fun adapt_signature(m: MMethodDef, args: Array[RuntimeVariable])
688 do
689 var recv = args.first
690 if recv.mtype.ctype != m.mclassdef.mclass.mclass_type.ctype then
691 args.first = self.autobox(args.first, m.mclassdef.mclass.mclass_type)
692 end
693 for i in [0..m.msignature.arity[ do
694 var t = m.msignature.mparameters[i].mtype
695 if i == m.msignature.vararg_rank then
696 t = args[i+1].mtype
697 end
698 t = self.resolve_for(t, recv)
699 args[i+1] = self.autobox(args[i+1], t)
700 end
701 end
702
703 # Box or unbox a value to another type iff a C type conversion is needed
704 # ENSURE: result.mtype.ctype == mtype.ctype
705 redef fun autobox(value: RuntimeVariable, mtype: MType): RuntimeVariable
706 do
707 if value.mtype.ctype == mtype.ctype then
708 return value
709 else if value.mtype.ctype == "val*" then
710 return self.new_expr("((struct instance_{mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
711 else if mtype.ctype == "val*" then
712 var valtype = value.mtype.as(MClassType)
713 var res = self.new_var(mtype)
714 if not compiler.runtime_type_analysis.live_types.has(valtype) then
715 self.add("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */")
716 self.add("printf(\"Dead code executed!\\n\"); exit(1);")
717 return res
718 end
719 var totype = value.mtype
720 if totype isa MNullableType then totype = totype.mtype
721 self.add("{res} = BOX_{valtype.c_name}({value}, (struct type*) &type_{totype.c_name}); /* autobox from {value.mtype} to {mtype} */")
722 return res
723 else
724 # Bad things will appen!
725 var res = self.new_var(mtype)
726 self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */")
727 self.add("printf(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); exit(1);")
728 return res
729 end
730 end
731
732 redef fun send(mmethod, arguments)
733 do
734 if arguments.first.mtype.ctype != "val*" then
735 assert arguments.first.mtype == arguments.first.mcasttype
736 return self.monomorphic_send(mmethod, arguments.first.mtype, arguments)
737 end
738
739 var res: nullable RuntimeVariable
740 var msignature = mmethod.intro.msignature.resolve_for(mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.mmodule, true)
741 var ret = msignature.return_mtype
742 if mmethod.is_new then
743 ret = arguments.first.mtype
744 res = self.new_var(ret)
745 else if ret == null then
746 res = null
747 else
748 ret = self.resolve_for(ret, arguments.first)
749 res = self.new_var(ret)
750 end
751
752 var s = new Buffer
753 var ss = new Buffer
754
755 var recv = arguments.first
756 s.append("val*")
757 ss.append("{recv}")
758 for i in [0..msignature.arity[ do
759 var a = arguments[i+1]
760 var t = msignature.mparameters[i].mtype
761 s.append(", {t.ctype}")
762 a = self.autobox(a, t)
763 ss.append(", {a}")
764 end
765
766 var maybenull = recv.mcasttype isa MNullableType
767 if maybenull then
768 self.add("if ({recv} == NULL) \{")
769 if mmethod.name == "==" then
770 assert res != null
771 var arg = arguments[1]
772 if arg.mcasttype isa MNullableType then
773 self.add("{res} = ({arg} == NULL);")
774 else if arg.mcasttype isa MNullType then
775 self.add("{res} = 1; /* is null */")
776 else
777 self.add("{res} = 0; /* {arg.inspect} cannot be null */")
778 end
779 else if mmethod.name == "!=" then
780 assert res != null
781 var arg = arguments[1]
782 if arg.mcasttype isa MNullableType then
783 self.add("{res} = ({arg} != NULL);")
784 else if arg.mcasttype isa MNullType then
785 self.add("{res} = 0; /* is null */")
786 else
787 self.add("{res} = 1; /* {arg.inspect} cannot be null */")
788 end
789 else
790 self.add_abort("Reciever is null")
791 end
792 self.add("\} else \{")
793 end
794
795 var color = self.compiler.as(SeparateCompiler).method_colors[mmethod]
796 var r
797 if ret == null then r = "void" else r = ret.ctype
798 var call = "(({r} (*)({s}))({arguments.first}->class->vft[{color}]))({ss}) /* {mmethod} on {arguments.first.inspect}*/"
799
800 if res != null then
801 self.add("{res} = {call};")
802 else
803 self.add("{call};")
804 end
805
806 if maybenull then
807 self.add("\}")
808 end
809
810 return res
811 end
812
813 redef fun call(mmethoddef, recvtype, arguments)
814 do
815 var res: nullable RuntimeVariable
816 var ret = mmethoddef.msignature.return_mtype
817 if mmethoddef.mproperty.is_new then
818 ret = arguments.first.mtype
819 res = self.new_var(ret)
820 else if ret == null then
821 res = null
822 else
823 ret = self.resolve_for(ret, arguments.first)
824 res = self.new_var(ret)
825 end
826
827 # Autobox arguments
828 self.adapt_signature(mmethoddef, arguments)
829
830 if res == null then
831 self.add("{mmethoddef.c_name}({arguments.join(", ")});")
832 return null
833 else
834 self.add("{res} = {mmethoddef.c_name}({arguments.join(", ")});")
835 end
836
837 return res
838 end
839
840 redef fun isset_attribute(a, recv)
841 do
842 # FIXME: Here we inconditionally return boxed primitive attributes
843 var res = self.new_var(bool_type)
844 self.add("{res} = {recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}] != NULL; /* {a} on {recv.inspect}*/")
845 return res
846 end
847
848 redef fun read_attribute(a, recv)
849 do
850 # FIXME: Here we inconditionally return boxed primitive attributes
851 var ret = a.intro.static_mtype.as(not null)
852 ret = self.resolve_for(ret, recv)
853 var cret = self.object_type.as_nullable
854 var res = self.new_var(cret)
855 res.mcasttype = ret
856 self.add("{res} = {recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}]; /* {a} on {recv.inspect} */")
857 if not ret isa MNullableType then
858 self.add("if ({res} == NULL) \{")
859 self.add_abort("Uninitialized attribute {a.name}")
860 self.add("\}")
861 end
862
863 return res
864 end
865
866 redef fun write_attribute(a, recv, value)
867 do
868 # FIXME: Here we inconditionally box primitive attributes
869 value = self.autobox(value, self.object_type.as_nullable)
870 self.add("{recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}] = {value}; /* {a} on {recv.inspect} */")
871 end
872
873 redef fun init_instance(mtype)
874 do
875 var compiler = self.compiler.as(SeparateCompiler)
876 if mtype isa MGenericType and mtype.need_anchor then
877 var buff = new Buffer
878 for ft in mtype.mclass.mclass_type.arguments do
879 var ftcolor = compiler.ft_colors[ft.as(MParameterType)]
880 buff.append("[self->type->fts_table->fts[{ftcolor}]->id]")
881 end
882 mtype = self.anchor(mtype).as(MClassType)
883 return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) livetypes_{mtype.mclass.c_name}{buff.to_s})", mtype)
884 end
885 compiler.undead_types.add(mtype)
886 return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) &type_{mtype.c_name})", mtype)
887 end
888
889 redef fun type_test(value, mtype)
890 do
891 var compiler = self.compiler.as(SeparateCompiler)
892 var res = self.new_var(bool_type)
893 var buff = new Buffer
894
895 if mtype isa MNullableType then mtype = mtype.mtype
896 if mtype isa MGenericType and mtype.need_anchor then
897 for ft in mtype.mclass.mclass_type.arguments do
898 var ftcolor = compiler.ft_colors[ft.as(MParameterType)]
899 buff.append("[self->type->fts_table->fts[{ftcolor}]->id]")
900 end
901 self.add("{res} = {value}->type->type_table[livetypes_{mtype.mclass.c_name}{buff.to_s}->color] == livetypes_{mtype.mclass.c_name}{buff.to_s}->id;")
902 else if mtype isa MClassType then
903 compiler.undead_types.add(mtype)
904 self.add("{res} = {value}->type->type_table[type_{mtype.c_name}.color] == type_{mtype.c_name}.id;")
905 else if mtype isa MParameterType then
906 var ftcolor = compiler.ft_colors[mtype]
907 self.add("{res} = {value}->type->type_table[self->type->fts_table->fts[{ftcolor}]->color] == self->type->fts_table->fts[{ftcolor}]->id;")
908 end
909
910 return res
911 end
912
913 redef fun is_same_type_test(value1, value2)
914 do
915 var res = self.new_var(bool_type)
916 # TODO
917 add("printf(\"NOT YET IMPLEMENTED: is_same_type(%s,%s).\\n\", \"{value1.inspect}\", \"{value2.inspect}\"); exit(1);")
918 return res
919 end
920
921 redef fun class_name_string(value1)
922 do
923 var res = self.get_name("var_class_name")
924 self.add_decl("const char* {res};")
925 # TODO
926 add("printf(\"NOT YET IMPLEMENTED: class_name_string(%s).\\n\", \"{value1.inspect}\"); exit(1);")
927 return res
928 end
929
930 redef fun equal_test(value1, value2)
931 do
932 var res = self.new_var(bool_type)
933 if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
934 var tmp = value1
935 value1 = value2
936 value2 = tmp
937 end
938 if value1.mtype.ctype != "val*" then
939 if value2.mtype.ctype == value1.mtype.ctype then
940 self.add("{res} = {value1} == {value2};")
941 else if value2.mtype.ctype != "val*" then
942 self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
943 else
944 var mtype1 = value1.mtype.as(MClassType)
945 self.add("{res} = ({value2} != NULL) && ({value2}->class == (struct class*) &class_{mtype1.c_name});")
946 self.add("if ({res}) \{")
947 self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
948 self.add("\}")
949 end
950 else
951 self.add("{res} = {value1} == {value2};")
952 end
953 return res
954 end
955
956 redef fun array_instance(array, elttype)
957 do
958 var compiler = self.compiler.as(SeparateCompiler)
959 var nclass = self.get_class("NativeArray")
960 elttype = self.anchor(elttype)
961 var arraytype = self.get_class("Array").get_mtype([elttype])
962 var res = self.init_instance(arraytype)
963 self.add("\{ /* {res} = array_instance Array[{elttype}] */")
964 var nat = self.new_var(self.get_class("NativeArray").get_mtype([elttype]))
965 nat.is_exact = true
966 compiler.undead_types.add(nat.mtype.as(MClassType))
967 self.add("{nat} = NEW_{nclass.c_name}({array.length}, (struct type *) &type_{nat.mtype.c_name});")
968 for i in [0..array.length[ do
969 var r = self.autobox(array[i], self.object_type)
970 self.add("((struct instance_{nclass.c_name}*){nat})->values[{i}] = (val*) {r};")
971 end
972 var length = self.int_instance(array.length)
973 self.send(self.get_property("with_native", arraytype), [res, nat, length])
974 self.check_init_instance(res)
975 self.add("\}")
976 return res
977 end
978
979 redef fun native_array_def(pname, ret_type, arguments)
980 do
981 var elttype = arguments.first.mtype
982 var nclass = self.get_class("NativeArray")
983 var recv = "((struct instance_{nclass.c_name}*){arguments[0]})->values"
984 if pname == "[]" then
985 self.ret(self.new_expr("{recv}[{arguments[1]}]", ret_type.as(not null)))
986 return
987 else if pname == "[]=" then
988 self.add("{recv}[{arguments[1]}]={arguments[2]};")
989 return
990 else if pname == "copy_to" then
991 var recv1 = "((struct instance_{nclass.c_name}*){arguments[1]})->values"
992 self.add("memcpy({recv1}, {recv}, {arguments[2]}*sizeof({elttype.ctype}));")
993 return
994 end
995 end
996
997 redef fun calloc_array(ret_type, arguments)
998 do
999 var ret = ret_type.as(MClassType)
1000 var compiler = self.compiler.as(SeparateCompiler)
1001 compiler.undead_types.add(ret)
1002 self.ret(self.new_expr("NEW_{ret.mclass.c_name}({arguments[1]}, (struct type*) &type_{ret_type.c_name})", ret_type))
1003 end
1004 end
1005
1006 redef class MClass
1007 # Return the name of the C structure associated to a Nit class
1008 fun c_name: String do
1009 var res = self.c_name_cache
1010 if res != null then return res
1011 res = "{intro_mmodule.name.to_cmangle}__{name.to_cmangle}"
1012 self.c_name_cache = res
1013 return res
1014 end
1015 private var c_name_cache: nullable String
1016 end