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