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