nitgsep: use mtype.c_name instead of mclass.name as C symbols
[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.mclass_type.c_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 AbstractRuntimeFunction
207
208 redef fun build_c_name: String
209 do
210 return "{mmethoddef.c_name}"
211 end
212
213 redef fun to_s do return self.mmethoddef.to_s
214
215 redef fun compile_to_c(compiler)
216 do
217 var mmethoddef = self.mmethoddef
218
219 var recv = self.mmethoddef.mclassdef.bound_mtype
220 var v = new SeparateCompilerVisitor(compiler)
221 var selfvar = new RuntimeVariable("self", recv, recv)
222 var arguments = new Array[RuntimeVariable]
223 var frame = new Frame(v, mmethoddef, recv, arguments)
224 v.frame = frame
225
226 var sig = new Buffer
227 var comment = new Buffer
228 var ret = mmethoddef.msignature.return_mtype
229 if ret != null then
230 ret = v.resolve_for(ret, selfvar)
231 sig.append("{ret.ctype} ")
232 else if mmethoddef.mproperty.is_new then
233 ret = recv
234 sig.append("{ret.ctype} ")
235 else
236 sig.append("void ")
237 end
238 sig.append(self.c_name)
239 sig.append("({recv.ctype} self")
240 comment.append("(self: {recv}")
241 arguments.add(selfvar)
242 for i in [0..mmethoddef.msignature.arity[ do
243 var mtype = mmethoddef.msignature.mparameters[i].mtype
244 if i == mmethoddef.msignature.vararg_rank then
245 mtype = v.get_class("Array").get_mtype([mtype])
246 end
247 mtype = v.resolve_for(mtype, selfvar)
248 comment.append(", {mtype}")
249 sig.append(", {mtype.ctype} p{i}")
250 var argvar = new RuntimeVariable("p{i}", mtype, mtype)
251 arguments.add(argvar)
252 end
253 sig.append(")")
254 comment.append(")")
255 if ret != null then
256 comment.append(": {ret}")
257 end
258 compiler.header.add_decl("{sig};")
259
260 v.add_decl("/* method {self} for {comment} */")
261 v.add_decl("{sig} \{")
262 if ret != null then
263 frame.returnvar = v.new_var(ret)
264 end
265 frame.returnlabel = v.get_name("RET_LABEL")
266
267 if recv != arguments.first.mtype then
268 #print "{self} {recv} {arguments.first}"
269 end
270 mmethoddef.compile_inside_to_c(v, arguments)
271
272 v.add("{frame.returnlabel.as(not null)}:;")
273 if ret != null then
274 v.add("return {frame.returnvar.as(not null)};")
275 end
276 v.add("\}")
277 end
278
279 redef fun call(v, arguments)
280 do
281 abort
282 # TODO ?
283 end
284 end
285
286 # A visitor on the AST of property definition that generate the C code of a separate compilation process.
287 class SeparateCompilerVisitor
288 super GlobalCompilerVisitor # TODO better separation of concerns
289
290 redef fun adapt_signature(m: MMethodDef, args: Array[RuntimeVariable])
291 do
292 var recv = args.first
293 if recv.mtype.ctype != m.mclassdef.mclass.mclass_type.ctype then
294 args.first = self.autobox(args.first, m.mclassdef.mclass.mclass_type)
295 end
296 for i in [0..m.msignature.arity[ do
297 var t = m.msignature.mparameters[i].mtype
298 if i == m.msignature.vararg_rank then
299 t = args[i+1].mtype
300 end
301 t = self.resolve_for(t, recv)
302 args[i+1] = self.autobox(args[i+1], t)
303 end
304 end
305
306 # Box or unbox a value to another type iff a C type conversion is needed
307 # ENSURE: result.mtype.ctype == mtype.ctype
308 redef fun autobox(value: RuntimeVariable, mtype: MType): RuntimeVariable
309 do
310 if value.mtype.ctype == mtype.ctype then
311 return value
312 #else if value.mtype.ctype == "val*" then
313 #return self.new_expr("((struct {mtype.c_name}*){value})->value /* autounbox from {value.mtype} to {mtype} */", mtype)
314 else if mtype.ctype == "val*" then
315 var valtype = value.mtype.as(MClassType)
316 var res = self.new_var(mtype)
317 if not compiler.runtime_type_analysis.live_types.has(valtype) then
318 self.add("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */")
319 self.add("printf(\"Dead code executed!\\n\"); exit(1);")
320 return res
321 end
322 # Handles primitives C types
323 if value.mtype.ctype != "val*" then
324 self.add("{res} = (val*) (intptr_t) {value}; /* autobox from {value.mtype} to {mtype} */")
325 end
326 #self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
327 return res
328 else
329 # Bad things will appen!
330 var res = self.new_var(mtype)
331 self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */")
332 self.add("printf(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); exit(1);")
333 return res
334 end
335 end
336
337 redef fun send(mmethod, arguments)
338 do
339 if arguments.first.mtype.ctype != "val*" then
340 assert arguments.first.mtype == arguments.first.mcasttype
341 return self.monomorphic_send(mmethod, arguments.first.mtype, arguments)
342 end
343
344 var res: nullable RuntimeVariable
345 var ret = mmethod.intro.msignature.return_mtype
346 if mmethod.is_new then
347 ret = arguments.first.mtype
348 res = self.new_var(ret)
349 else if ret == null then
350 res = null
351 else
352 ret = self.resolve_for(ret, arguments.first)
353 res = self.new_var(ret)
354 end
355
356 var s = new Buffer
357 var ss = new Buffer
358 var first = true
359 for a in arguments do
360 if not first then
361 s.append(", ")
362 ss.append(", ")
363 else
364 first = false
365 end
366 s.append("{a.mtype.ctype}")
367 ss.append("{a}")
368 end
369
370 var color = mmethod.color.as(not null)
371 var r
372 if ret == null then r = "void" else r = ret.ctype
373 var call = "(({r} (*)({s}))({arguments.first}->class->vft[{color}]))({ss})"
374
375 if res != null then
376 self.add("{res} = {call};")
377 else
378 self.add("{call};")
379 end
380
381 return res
382 end
383
384 redef fun call(mmethoddef, recvtype, arguments)
385 do
386 var res: nullable RuntimeVariable
387 var ret = mmethoddef.msignature.return_mtype
388 if mmethoddef.mproperty.is_new then
389 ret = arguments.first.mtype
390 res = self.new_var(ret)
391 else if ret == null then
392 res = null
393 else
394 ret = self.resolve_for(ret, arguments.first)
395 res = self.new_var(ret)
396 end
397
398 # Autobox arguments
399 self.adapt_signature(mmethoddef, arguments)
400
401 if res == null then
402 self.add("{mmethoddef.c_name}({arguments.join(", ")});")
403 return null
404 else
405 self.add("{res} = {mmethoddef.c_name}({arguments.join(", ")});")
406 end
407
408 return res
409 end
410
411 redef fun read_attribute(a, recv)
412 do
413 var ret = a.intro.static_mtype.as(not null)
414 ret = self.resolve_for(ret, recv)
415 var res = self.new_var(ret)
416 # TODO
417 self.add("{res} = (val*) {recv}->attrs[{a.color.as(not null)}];")
418 return res
419 end
420
421 redef fun write_attribute(a, recv, value)
422 do
423 # TODO
424 self.add("{recv}->attrs[{a.color.as(not null)}] = {value};")
425 end
426
427 redef fun init_instance(mtype)
428 do
429 mtype = self.anchor(mtype).as(MClassType)
430 var res = self.new_expr("NEW_{mtype.c_name}()", mtype)
431 return res
432 end
433
434 redef fun type_test(value, mtype)
435 do
436 var res = self.new_var(bool_type)
437 # TODO
438 return res
439 end
440
441 redef fun equal_test(value1, value2)
442 do
443 var res = self.new_var(bool_type)
444 # TODO
445 return res
446 end
447 end
448