nitmetrics: refactor self usage metrics computation
[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 intrude import global_compiler # TODO better separation of concerns
19
20 redef class ToolContext
21 # --separate
22 var opt_separate: OptionBool = new OptionBool("Use separate compilation", "--separate")
23
24 redef init
25 do
26 super
27 self.option_context.add_option(self.opt_separate)
28 end
29 end
30
31 redef class ModelBuilder
32 redef fun run_global_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis)
33 do
34 # Hijack the run_global_compiler to run the separate one if requested.
35 if self.toolcontext.opt_separate.value then
36 run_separate_compiler(mainmodule, runtime_type_analysis)
37 else
38 super
39 end
40 end
41
42 fun run_separate_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis)
43 do
44 var compiler = new SeparateCompiler(mainmodule, runtime_type_analysis, self)
45 var v = new SeparateCompilerVisitor(compiler)
46 compiler.header = v
47 v.add_decl("#include <stdlib.h>")
48 v.add_decl("#include <stdio.h>")
49 v.add_decl("#include <string.h>")
50
51 v.add_decl("typedef struct \{ void (**vft)(void); \} val; /* general C type representing a Nit instance. */")
52
53 # The main function of the C
54
55 v = new SeparateCompilerVisitor(compiler)
56 v.add_decl("int glob_argc;")
57 v.add_decl("char **glob_argv;")
58 v.add_decl("val *glob_sys;")
59 v.add_decl("int main(int argc, char** argv) \{")
60 v.add("glob_argc = argc; glob_argv = argv;")
61 var main_type = mainmodule.sys_type
62 if main_type == null then return # Nothing to compile
63 var glob_sys = v.init_instance(main_type)
64 v.add("glob_sys = {glob_sys};")
65 var main_init = mainmodule.try_get_primitive_method("init", main_type)
66 if main_init != null then
67 v.send(main_init, [glob_sys])
68 end
69 var main_method = mainmodule.try_get_primitive_method("main", main_type)
70 if main_method != null then
71 v.send(main_method, [glob_sys])
72 end
73 v.add("\}")
74
75
76 for m in mainmodule.in_importation.greaters do
77 compiler.compile_module_to_c(m)
78 for mclass in m.intro_mclasses do
79 compiler.compile_class_to_c(mclass)
80 end
81 end
82
83 write_and_make(compiler)
84 end
85 end
86
87 # Singleton that store the knowledge about the separate compilation process
88 class SeparateCompiler
89 super GlobalCompiler # TODO better separation of concerns
90
91 # Separately compile all the method definitions of the module
92 fun compile_module_to_c(mmodule: MModule)
93 do
94 for cd in mmodule.mclassdefs do
95 for pd in cd.mpropdefs do
96 if not pd isa MMethodDef then continue
97 print "compile {pd} @ {cd} @ {mmodule}"
98 var r = new SeparateRuntimeFunction(pd)
99 r.compile_to_c(self)
100 end
101 end
102 end
103
104 # Globally compile the table of the class mclass
105 # In a link-time optimisation compiler, tables are globally computed
106 # In a true separate compiler (a with dynamic loading) you cannot do this unfortnally
107 fun compile_class_to_c(mclass: MClass)
108 do
109 var mtype = mclass.mclassdefs.first.bound_mtype
110 var c_name = mclass.name
111
112 var v = new SeparateCompilerVisitor(self)
113
114 v.add_decl("/* runtime class {mtype} */")
115 var idnum = classids.length
116 var idname = "ID_" + c_name
117 self.classids[mtype] = idname
118 v.add_decl("#define {idname} {idnum} /* {mtype} */")
119
120 v.add_decl("struct {c_name} \{")
121 v.add_decl("void (**vft)(void); /* must be ??? */")
122
123 if mtype.ctype != "val*" then
124 # Is the Nit type is native then the struct is a box with two fields:
125 # * the `vft` to be polymorph
126 # * the `value` that contains the native value.
127 v.add_decl("{mtype.ctype} value;")
128 end
129
130 # Collect all attributes and associate them a field in the structure.
131 # Note: we do not try to optimize the order and helps CC to optimize the client code.
132 for cd in mtype.collect_mclassdefs(self.mainmodule) do
133 for p in cd.intro_mproperties do
134 if not p isa MAttribute then continue
135 var t = p.intro.static_mtype.as(not null)
136 t = t.anchor_to(self.mainmodule, mtype)
137 v.add_decl("{t.ctype} {p.intro.c_name}; /* {p}: {t} */")
138 end
139 end
140 v.add_decl("\};")
141
142 if mtype.ctype != "val*" then return
143
144 self.header.add_decl("{mtype.ctype} NEW_{c_name}(void);")
145 v.add_decl("/* allocate {mtype} */")
146 v.add_decl("{mtype.ctype} NEW_{c_name}(void) \{")
147 var res = v.new_var(mtype)
148 res.is_exact = true
149 v.add("{res} = calloc(sizeof(struct {c_name}), 1);")
150 v.add("{res}->vft = NULL;") #TODO
151
152 for cd in mtype.collect_mclassdefs(self.mainmodule)
153 do
154 var n = self.modelbuilder.mclassdef2nclassdef[cd]
155 for npropdef in n.n_propdefs do
156 if npropdef isa AAttrPropdef then
157 npropdef.init_expr(v, res)
158 end
159 end
160 end
161 v.add("return {res};")
162 v.add("\}")
163 end
164 end
165
166 # The C function associated to a methoddef separately compiled
167 class SeparateRuntimeFunction
168 super RuntimeFunction
169
170 # The mangled c name of the runtime_function
171 redef fun c_name: String
172 do
173 var res = self.c_name_cache
174 if res != null then return res
175 res = mmethoddef.c_name
176 self.c_name_cache = res
177 return res
178 end
179
180 private var c_name_cache: nullable String = null
181
182 redef fun to_s do return self.mmethoddef.to_s
183
184 redef fun compile_to_c(compiler)
185 do
186 var mmethoddef = self.mmethoddef
187
188 var recv = self.mmethoddef.mclassdef.bound_mtype
189 var v = new SeparateCompilerVisitor(compiler)
190 var selfvar = new RuntimeVariable("self", recv, recv)
191 var arguments = new Array[RuntimeVariable]
192 var frame = new Frame(v, mmethoddef, recv, arguments)
193 v.frame = frame
194
195 var sig = new Buffer
196 var comment = new Buffer
197 var ret = mmethoddef.msignature.return_mtype
198 if ret != null then
199 ret = v.resolve_for(ret, selfvar)
200 sig.append("{ret.ctype} ")
201 else if mmethoddef.mproperty.is_new then
202 ret = recv
203 sig.append("{ret.ctype} ")
204 else
205 sig.append("void ")
206 end
207 sig.append(self.c_name)
208 sig.append("({recv.ctype} self")
209 comment.append("(self: {recv}")
210 arguments.add(selfvar)
211 for i in [0..mmethoddef.msignature.arity[ do
212 var mtype = mmethoddef.msignature.mparameters[i].mtype
213 if i == mmethoddef.msignature.vararg_rank then
214 mtype = v.get_class("Array").get_mtype([mtype])
215 end
216 mtype = v.resolve_for(mtype, selfvar)
217 comment.append(", {mtype}")
218 sig.append(", {mtype.ctype} p{i}")
219 var argvar = new RuntimeVariable("p{i}", mtype, mtype)
220 arguments.add(argvar)
221 end
222 sig.append(")")
223 comment.append(")")
224 if ret != null then
225 comment.append(": {ret}")
226 end
227 compiler.header.add_decl("{sig};")
228
229 v.add_decl("/* method {self} for {comment} */")
230 v.add_decl("{sig} \{")
231 if ret != null then
232 frame.returnvar = v.new_var(ret)
233 end
234 frame.returnlabel = v.get_name("RET_LABEL")
235
236 if recv != arguments.first.mtype then
237 print "{self} {recv} {arguments.first}"
238 end
239 mmethoddef.compile_inside_to_c(v, arguments)
240
241 v.add("{frame.returnlabel.as(not null)}:;")
242 if ret != null then
243 v.add("return {frame.returnvar.as(not null)};")
244 end
245 v.add("\}")
246 end
247
248 redef fun call(v, arguments)
249 do
250 abort
251 # TODO ?
252 end
253 end
254
255 # A visitor on the AST of property definition that generate the C code of a separate compilation process.
256 class SeparateCompilerVisitor
257 super GlobalCompilerVisitor # TODO better separation of concerns
258
259 redef fun autobox(value, mtype)
260 do
261 # TODO?
262 return value
263 end
264
265 redef fun send(mmethod, arguments)
266 do
267 if arguments.first.mtype.ctype != "val*" then
268 assert arguments.first.mtype == arguments.first.mcasttype
269 return self.monomorphic_send(mmethod, arguments.first.mtype, arguments)
270 end
271
272
273 var res: nullable RuntimeVariable
274 var ret = mmethod.intro.msignature.return_mtype
275 if mmethod.is_new then
276 ret = arguments.first.mtype
277 res = self.new_var(ret)
278 else if ret == null then
279 res = null
280 else
281 ret = self.resolve_for(ret, arguments.first)
282 res = self.new_var(ret)
283 end
284
285 var s = new Buffer
286 var ss = new Buffer
287 for a in arguments do
288 if a != arguments.first then
289 s.append(", ")
290 ss.append(", ")
291 end
292 s.append("{a.mtype.ctype}")
293 ss.append("{a}")
294 end
295
296 var color = 1 # TODO
297 var r
298 if ret == null then r = "void" else r = ret.ctype
299 var call = "(({r} (*)({s}))({arguments.first}->vft[{color}]))({ss})"
300
301 if res != null then
302 self.add("{res} = {call};")
303 else
304 self.add("{call};")
305 end
306
307 return res
308 end
309
310 redef fun call(mmethoddef, recvtype, arguments)
311 do
312 var res: nullable RuntimeVariable
313 var ret = mmethoddef.msignature.return_mtype
314 if mmethoddef.mproperty.is_new then
315 ret = arguments.first.mtype
316 res = self.new_var(ret)
317 else if ret == null then
318 res = null
319 else
320 ret = self.resolve_for(ret, arguments.first)
321 res = self.new_var(ret)
322 end
323
324 if res == null then
325 self.add("{mmethoddef.c_name}({arguments.join(",")});")
326 return null
327 else
328 self.add("{res} = {mmethoddef.c_name}({arguments.join(",")});")
329 end
330
331 return res
332 end
333
334 redef fun read_attribute(a, recv)
335 do
336 var ret = a.intro.static_mtype.as(not null)
337 ret = self.resolve_for(ret, recv)
338 var res = self.new_var(ret)
339 # TODO
340 return res
341 end
342
343 redef fun write_attribute(a, recv, value)
344 do
345 # TODO
346 end
347
348 redef fun init_instance(mtype)
349 do
350 mtype = self.anchor(mtype).as(MClassType)
351 var res = self.new_expr("NEW_{mtype.mclass.name}()", mtype)
352 return res
353 end
354
355 redef fun type_test(value, mtype)
356 do
357 var res = self.new_var(bool_type)
358 # TODO
359 return res
360 end
361
362 redef fun equal_test(value1, value2)
363 do
364 var res = self.new_var(bool_type)
365 # TODO
366 return res
367 end
368 end
369