nitg sep: refactoring of coloring fonctionnalities
[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 intrude import global_compiler # TODO better separation of concerns
20 intrude import vft_computation
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 build_vft(mainmodule)
38 run_separate_compiler(mainmodule, runtime_type_analysis)
39 else
40 super
41 end
42 end
43
44 fun run_separate_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis)
45 do
46 var time0 = get_time
47 self.toolcontext.info("*** COMPILING TO C ***", 1)
48
49 var compiler = new SeparateCompiler(mainmodule, runtime_type_analysis, self)
50 var v = new SeparateCompilerVisitor(compiler)
51 compiler.header = v
52 v.add_decl("#include <stdlib.h>")
53 v.add_decl("#include <stdio.h>")
54 v.add_decl("#include <string.h>")
55 v.add_decl("#include <gc/gc.h>")
56 v.add_decl("typedef void(*nitmethod_t)(void); /* general C type representing a Nit method. */")
57 v.add_decl("typedef void* nitattribute_t; /* general C type representing a Nit attribute. */")
58 v.add_decl("struct class \{ nitmethod_t vft[1]; \}; /* general C type representing a Nit class. */")
59 v.add_decl("typedef struct \{ struct class *class; nitattribute_t attrs[1]; \} val; /* general C type representing a Nit instance. */")
60
61 # Class names (for the class_name and output_class_name methods)
62
63 v.add_decl("extern const char const * class_names[];")
64 v.add("const char const * class_names[] = \{")
65 for t in runtime_type_analysis.live_types do
66 v.add("\"{t}\",")
67 end
68 v.add("\};")
69
70 # The main function of the C
71
72 v = new SeparateCompilerVisitor(compiler)
73 v.add_decl("int glob_argc;")
74 v.add_decl("char **glob_argv;")
75 v.add_decl("val *glob_sys;")
76 v.add_decl("int main(int argc, char** argv) \{")
77 v.add("glob_argc = argc; glob_argv = argv;")
78 var main_type = mainmodule.sys_type
79 if main_type == null then return # Nothing to compile
80 var glob_sys = v.init_instance(main_type)
81 v.add("glob_sys = {glob_sys};")
82 var main_init = mainmodule.try_get_primitive_method("init", main_type)
83 if main_init != null then
84 v.send(main_init, [glob_sys])
85 end
86 var main_method = mainmodule.try_get_primitive_method("main", main_type)
87 if main_method != null then
88 v.send(main_method, [glob_sys])
89 end
90 v.add("\}")
91
92
93 for m in mainmodule.in_importation.greaters do
94 compiler.compile_module_to_c(m)
95 for mclass in m.intro_mclasses do
96 compiler.compile_class_to_c(mclass)
97 end
98 end
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 # Separately compile all the method definitions of the module
109 fun compile_module_to_c(mmodule: MModule)
110 do
111 for cd in mmodule.mclassdefs do
112 for pd in cd.mpropdefs do
113 if not pd isa MMethodDef then continue
114 #print "compile {pd} @ {cd} @ {mmodule}"
115 var r = new SeparateRuntimeFunction(pd)
116 r.compile_to_c(self)
117 end
118 end
119 end
120
121 # Globally compile the table of the class mclass
122 # In a link-time optimisation compiler, tables are globally computed
123 # In a true separate compiler (a with dynamic loading) you cannot do this unfortnally
124 fun compile_class_to_c(mclass: MClass)
125 do
126 var mtype = mclass.mclassdefs.first.bound_mtype
127 var c_name = mclass.name
128
129 var v = new SeparateCompilerVisitor(self)
130
131 v.add_decl("/* runtime class {mtype} */")
132 var idnum = classids.length
133 var idname = "ID_" + c_name
134 self.classids[mtype] = idname
135 v.add_decl("#define {idname} {idnum} /* {mtype} */")
136
137 v.add_decl("struct class_{c_name} \{")
138 v.add_decl("nitmethod_t vft[{mclass.vft.length}];")
139
140 if mtype.ctype != "val*" then
141 # Is the Nit type is native then the struct is a box with two fields:
142 # * the `vft` to be polymorph
143 # * the `value` that contains the native value.
144 v.add_decl("{mtype.ctype} value;")
145 end
146
147 # Collect all attributes and associate them a field in the structure.
148 # Note: we do not try to optimize the order and helps CC to optimize the client code.
149 for cd in mtype.collect_mclassdefs(self.mainmodule) do
150 for p in cd.intro_mproperties do
151 if not p isa MAttribute then continue
152 var t = p.intro.static_mtype.as(not null)
153 t = t.anchor_to(self.mainmodule, mtype)
154 v.add_decl("{t.ctype} {p.intro.c_name}; /* {p}: {t} */")
155 end
156 end
157 v.add_decl("\};")
158
159 # Build class vft
160 self.header.add_decl("extern const struct class_{c_name} class_{c_name};")
161 v.add_decl("const struct class_{c_name} class_{c_name} = \{")
162 v.add_decl("\{")
163 for i in [0 .. mclass.vft.length[ do
164 var mpropdef = mclass.vft[i]
165 if mpropdef == null then
166 v.add_decl("NULL, /* empty */")
167 else
168 v.add_decl("(nitmethod_t){mpropdef.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
169 end
170 end
171 v.add_decl("\}")
172 v.add_decl("\};")
173
174 #Build instance struct
175 v.add_decl("struct instance_{c_name} \{")
176 v.add_decl("struct class_{c_name} *vft;")
177 v.add_decl("nitattribute_t attrs[{mclass.attrs.length}];")
178 v.add_decl("\};")
179
180 if mtype.ctype != "val*" then return
181
182 self.header.add_decl("{mtype.ctype} NEW_{c_name}(void);")
183 v.add_decl("/* allocate {mtype} */")
184 v.add_decl("{mtype.ctype} NEW_{c_name}(void) \{")
185 var res = v.new_var(mtype)
186 res.is_exact = true
187 v.add("{res} = calloc(sizeof(struct instance_{c_name}), 1);")
188 v.add("{res}->class = (struct class*) &class_{c_name};")
189
190 for cd in mtype.collect_mclassdefs(self.mainmodule)
191 do
192 var n = self.modelbuilder.mclassdef2nclassdef[cd]
193 for npropdef in n.n_propdefs do
194 if npropdef isa AAttrPropdef then
195 npropdef.init_expr(v, res)
196 end
197 end
198 end
199 v.add("return {res};")
200 v.add("\}")
201 end
202 end
203
204 # The C function associated to a methoddef separately compiled
205 class SeparateRuntimeFunction
206 super RuntimeFunction
207
208 # The mangled c name of the runtime_function
209 redef fun c_name: String
210 do
211 var res = self.c_name_cache
212 if res != null then return res
213 res = mmethoddef.c_name
214 self.c_name_cache = res
215 return res
216 end
217
218 private var c_name_cache: nullable String = null
219
220 redef fun to_s do return self.mmethoddef.to_s
221
222 redef fun compile_to_c(compiler)
223 do
224 var mmethoddef = self.mmethoddef
225
226 var recv = self.mmethoddef.mclassdef.bound_mtype
227 var v = new SeparateCompilerVisitor(compiler)
228 var selfvar = new RuntimeVariable("self", recv, recv)
229 var arguments = new Array[RuntimeVariable]
230 var frame = new Frame(v, mmethoddef, recv, arguments)
231 v.frame = frame
232
233 var sig = new Buffer
234 var comment = new Buffer
235 var ret = mmethoddef.msignature.return_mtype
236 if ret != null then
237 ret = v.resolve_for(ret, selfvar)
238 sig.append("{ret.ctype} ")
239 else if mmethoddef.mproperty.is_new then
240 ret = recv
241 sig.append("{ret.ctype} ")
242 else
243 sig.append("void ")
244 end
245 sig.append(self.c_name)
246 sig.append("({recv.ctype} self")
247 comment.append("(self: {recv}")
248 arguments.add(selfvar)
249 for i in [0..mmethoddef.msignature.arity[ do
250 var mtype = mmethoddef.msignature.mparameters[i].mtype
251 if i == mmethoddef.msignature.vararg_rank then
252 mtype = v.get_class("Array").get_mtype([mtype])
253 end
254 mtype = v.resolve_for(mtype, selfvar)
255 comment.append(", {mtype}")
256 sig.append(", {mtype.ctype} p{i}")
257 var argvar = new RuntimeVariable("p{i}", mtype, mtype)
258 arguments.add(argvar)
259 end
260 sig.append(")")
261 comment.append(")")
262 if ret != null then
263 comment.append(": {ret}")
264 end
265 compiler.header.add_decl("{sig};")
266
267 v.add_decl("/* method {self} for {comment} */")
268 v.add_decl("{sig} \{")
269 if ret != null then
270 frame.returnvar = v.new_var(ret)
271 end
272 frame.returnlabel = v.get_name("RET_LABEL")
273
274 if recv != arguments.first.mtype then
275 #print "{self} {recv} {arguments.first}"
276 end
277 mmethoddef.compile_inside_to_c(v, arguments)
278
279 v.add("{frame.returnlabel.as(not null)}:;")
280 if ret != null then
281 v.add("return {frame.returnvar.as(not null)};")
282 end
283 v.add("\}")
284 end
285
286 redef fun call(v, arguments)
287 do
288 abort
289 # TODO ?
290 end
291 end
292
293 # A visitor on the AST of property definition that generate the C code of a separate compilation process.
294 class SeparateCompilerVisitor
295 super GlobalCompilerVisitor # TODO better separation of concerns
296
297 redef fun adapt_signature(m: MMethodDef, args: Array[RuntimeVariable])
298 do
299 var recv = args.first
300 if recv.mtype.ctype != m.mclassdef.mclass.mclass_type.ctype then
301 args.first = self.autobox(args.first, m.mclassdef.mclass.mclass_type)
302 end
303 for i in [0..m.msignature.arity[ do
304 var t = m.msignature.mparameters[i].mtype
305 if i == m.msignature.vararg_rank then
306 t = args[i+1].mtype
307 end
308 t = self.resolve_for(t, recv)
309 args[i+1] = self.autobox(args[i+1], t)
310 end
311 end
312
313 # Box or unbox a value to another type iff a C type conversion is needed
314 # ENSURE: result.mtype.ctype == mtype.ctype
315 redef fun autobox(value: RuntimeVariable, mtype: MType): RuntimeVariable
316 do
317 if value.mtype.ctype == mtype.ctype then
318 return value
319 #else if value.mtype.ctype == "val*" then
320 #return self.new_expr("((struct {mtype.c_name}*){value})->value /* autounbox from {value.mtype} to {mtype} */", mtype)
321 else if mtype.ctype == "val*" then
322 var valtype = value.mtype.as(MClassType)
323 var res = self.new_var(mtype)
324 if not compiler.runtime_type_analysis.live_types.has(valtype) then
325 self.add("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */")
326 self.add("printf(\"Dead code executed!\\n\"); exit(1);")
327 return res
328 end
329 # Handles primitives C types
330 if value.mtype.ctype != "val*" then
331 self.add("{res} = (val*) (intptr_t) {value}; /* autobox from {value.mtype} to {mtype} */")
332 end
333 #self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
334 return res
335 else
336 # Bad things will appen!
337 var res = self.new_var(mtype)
338 self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */")
339 self.add("printf(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); exit(1);")
340 return res
341 end
342 end
343
344 redef fun send(mmethod, arguments)
345 do
346 if arguments.first.mtype.ctype != "val*" then
347 assert arguments.first.mtype == arguments.first.mcasttype
348 return self.monomorphic_send(mmethod, arguments.first.mtype, arguments)
349 end
350
351 var res: nullable RuntimeVariable
352 var ret = mmethod.intro.msignature.return_mtype
353 if mmethod.is_new then
354 ret = arguments.first.mtype
355 res = self.new_var(ret)
356 else if ret == null then
357 res = null
358 else
359 ret = self.resolve_for(ret, arguments.first)
360 res = self.new_var(ret)
361 end
362
363 var s = new Buffer
364 var ss = new Buffer
365 var first = true
366 for a in arguments do
367 if not first then
368 s.append(", ")
369 ss.append(", ")
370 else
371 first = false
372 end
373 s.append("{a.mtype.ctype}")
374 ss.append("{a}")
375 end
376
377 var color = mmethod.color.as(not null)
378 var r
379 if ret == null then r = "void" else r = ret.ctype
380 var call = "(({r} (*)({s}))({arguments.first}->class->vft[{color}]))({ss})"
381
382 if res != null then
383 self.add("{res} = {call};")
384 else
385 self.add("{call};")
386 end
387
388 return res
389 end
390
391 redef fun call(mmethoddef, recvtype, arguments)
392 do
393 var res: nullable RuntimeVariable
394 var ret = mmethoddef.msignature.return_mtype
395 if mmethoddef.mproperty.is_new then
396 ret = arguments.first.mtype
397 res = self.new_var(ret)
398 else if ret == null then
399 res = null
400 else
401 ret = self.resolve_for(ret, arguments.first)
402 res = self.new_var(ret)
403 end
404
405 # Autobox arguments
406 self.adapt_signature(mmethoddef, arguments)
407
408 if res == null then
409 self.add("{mmethoddef.c_name}({arguments.join(", ")});")
410 return null
411 else
412 self.add("{res} = {mmethoddef.c_name}({arguments.join(", ")});")
413 end
414
415 return res
416 end
417
418 redef fun read_attribute(a, recv)
419 do
420 var ret = a.intro.static_mtype.as(not null)
421 ret = self.resolve_for(ret, recv)
422 var res = self.new_var(ret)
423 # TODO
424 self.add("{res} = (val*) {recv}->attrs[{a.color.as(not null)}];")
425 return res
426 end
427
428 redef fun write_attribute(a, recv, value)
429 do
430 # TODO
431 self.add("{recv}->attrs[{a.color.as(not null)}] = {value};")
432 end
433
434 redef fun init_instance(mtype)
435 do
436 mtype = self.anchor(mtype).as(MClassType)
437 var res = self.new_expr("NEW_{mtype.mclass.name}()", mtype)
438 return res
439 end
440
441 redef fun type_test(value, mtype)
442 do
443 var res = self.new_var(bool_type)
444 # TODO
445 return res
446 end
447
448 redef fun equal_test(value1, value2)
449 do
450 var res = self.new_var(bool_type)
451 # TODO
452 return res
453 end
454 end
455