1 # This file is part of NIT ( http://www.nitlanguage.org ).
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
15 # Separate compilation of a Nit program
16 module separate_compiler
19 intrude import global_compiler
# TODO better separation of concerns
20 intrude import vft_computation
21 redef class ToolContext
23 var opt_separate
: OptionBool = new OptionBool("Use separate compilation", "--separate")
28 self.option_context
.add_option
(self.opt_separate
)
32 redef class ModelBuilder
33 redef fun run_global_compiler
(mainmodule
: MModule, runtime_type_analysis
: RapidTypeAnalysis)
35 # Hijack the run_global_compiler to run the separate one if requested.
36 if self.toolcontext
.opt_separate
.value
then
38 run_separate_compiler
(mainmodule
, runtime_type_analysis
)
44 fun run_separate_compiler
(mainmodule
: MModule, runtime_type_analysis
: RapidTypeAnalysis)
47 self.toolcontext
.info
("*** COMPILING TO C ***", 1)
49 var compiler
= new SeparateCompiler(mainmodule
, runtime_type_analysis
, self)
50 var v
= new SeparateCompilerVisitor(compiler
)
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. */")
61 # Class names (for the class_name and output_class_name methods)
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
70 # The main function of the C
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
])
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
])
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
)
100 write_and_make
(compiler
)
104 # Singleton that store the knowledge about the separate compilation process
105 class SeparateCompiler
106 super GlobalCompiler # TODO better separation of concerns
108 # Separately compile all the method definitions of the module
109 fun compile_module_to_c
(mmodule
: MModule)
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
)
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)
126 var mtype
= mclass
.mclassdefs
.first
.bound_mtype
127 var c_name
= mclass
.mclass_type
.c_name
129 var v
= new SeparateCompilerVisitor(self)
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} */")
137 v
.add_decl
("struct class_{c_name} \{")
138 v
.add_decl
("nitmethod_t vft[{mclass.vft.length}];")
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;")
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} */")
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} = \{")
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 */")
168 v
.add_decl
("(nitmethod_t){mpropdef.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
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}];")
180 if mtype
.ctype
!= "val*" then return
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
)
187 v
.add
("{res} = calloc(sizeof(struct instance_{c_name}), 1);")
188 v
.add
("{res}->class = (struct class*) &class_{c_name};")
190 for cd
in mtype
.collect_mclassdefs
(self.mainmodule
)
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
)
199 v
.add
("return {res};")
204 # The C function associated to a methoddef separately compiled
205 class SeparateRuntimeFunction
206 super AbstractRuntimeFunction
208 redef fun build_c_name
: String
210 return "{mmethoddef.c_name}"
213 redef fun to_s
do return self.mmethoddef
.to_s
215 redef fun compile_to_c
(compiler
)
217 var mmethoddef
= self.mmethoddef
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
)
227 var comment
= new Buffer
228 var ret
= mmethoddef
.msignature
.return_mtype
230 ret
= v
.resolve_for
(ret
, selfvar
)
231 sig
.append
("{ret.ctype} ")
232 else if mmethoddef
.mproperty
.is_new
then
234 sig
.append
("{ret.ctype} ")
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
])
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
)
256 comment
.append
(": {ret}")
258 compiler
.header
.add_decl
("{sig};")
260 v
.add_decl
("/* method {self} for {comment} */")
261 v
.add_decl
("{sig} \{")
263 frame
.returnvar
= v
.new_var
(ret
)
265 frame
.returnlabel
= v
.get_name
("RET_LABEL")
267 if recv
!= arguments
.first
.mtype
then
268 #print "{self} {recv} {arguments.first}"
270 mmethoddef
.compile_inside_to_c
(v
, arguments
)
272 v
.add
("{frame.returnlabel.as(not null)}:;")
274 v
.add
("return {frame.returnvar.as(not null)};")
279 redef fun call
(v
, arguments
)
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
290 redef fun adapt_signature
(m
: MMethodDef, args
: Array[RuntimeVariable])
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
)
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
301 t
= self.resolve_for
(t
, recv
)
302 args
[i
+1] = self.autobox
(args
[i
+1], t
)
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
310 if value
.mtype
.ctype
== mtype
.ctype
then
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);")
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} */")
326 #self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
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);")
337 redef fun send
(mmethod
, arguments
)
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
)
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
352 ret
= self.resolve_for
(ret
, arguments
.first
)
353 res
= self.new_var
(ret
)
359 for a
in arguments
do
366 s
.append
("{a.mtype.ctype}")
370 var color
= mmethod
.color
.as(not null)
372 if ret
== null then r
= "void" else r
= ret
.ctype
373 var call
= "(({r} (*)({s}))({arguments.first}->class->vft[{color}]))({ss})"
376 self.add
("{res} = {call};")
384 redef fun call
(mmethoddef
, recvtype
, arguments
)
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
394 ret
= self.resolve_for
(ret
, arguments
.first
)
395 res
= self.new_var
(ret
)
399 self.adapt_signature
(mmethoddef
, arguments
)
402 self.add
("{mmethoddef.c_name}({arguments.join(", ")});")
405 self.add
("{res} = {mmethoddef.c_name}({arguments.join(", ")});")
411 redef fun read_attribute
(a
, recv
)
413 var ret
= a
.intro
.static_mtype
.as(not null)
414 ret
= self.resolve_for
(ret
, recv
)
415 var res
= self.new_var
(ret
)
417 self.add
("{res} = (val*) {recv}->attrs[{a.color.as(not null)}];")
421 redef fun write_attribute
(a
, recv
, value
)
424 self.add
("{recv}->attrs[{a.color.as(not null)}] = {value};")
427 redef fun init_instance
(mtype
)
429 mtype
= self.anchor
(mtype
).as(MClassType)
430 var res
= self.new_expr
("NEW_{mtype.c_name}()", mtype
)
434 redef fun type_test
(value
, mtype
)
436 var res
= self.new_var
(bool_type
)
441 redef fun equal_test
(value1
, value2
)
443 var res
= self.new_var
(bool_type
)