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
18 intrude import global_compiler
# TODO better separation of concerns
20 redef class ToolContext
22 var opt_separate
: OptionBool = new OptionBool("Use separate compilation", "--separate")
27 self.option_context
.add_option
(self.opt_separate
)
31 redef class ModelBuilder
32 redef fun run_global_compiler
(mainmodule
: MModule, runtime_type_analysis
: RapidTypeAnalysis)
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
)
42 fun run_separate_compiler
(mainmodule
: MModule, runtime_type_analysis
: RapidTypeAnalysis)
44 var compiler
= new SeparateCompiler(mainmodule
, runtime_type_analysis
, self)
45 var v
= new SeparateCompilerVisitor(compiler
)
47 v
.add_decl
("#include <stdlib.h>")
48 v
.add_decl
("#include <stdio.h>")
49 v
.add_decl
("#include <string.h>")
51 v
.add_decl
("typedef struct \{ void (**vft)(void); \} val; /* general C type representing a Nit instance. */")
53 # The main function of the C
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
])
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
])
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
)
83 write_and_make
(compiler
)
87 # Singleton that store the knowledge about the separate compilation process
88 class SeparateCompiler
89 super GlobalCompiler # TODO better separation of concerns
91 # Separately compile all the method definitions of the module
92 fun compile_module_to_c
(mmodule
: MModule)
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
)
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)
109 var mtype
= mclass
.mclassdefs
.first
.bound_mtype
110 var c_name
= mclass
.name
112 var v
= new SeparateCompilerVisitor(self)
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} */")
120 v
.add_decl
("struct {c_name} \{")
121 v
.add_decl
("void (**vft)(void); /* must be ??? */")
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;")
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} */")
142 if mtype
.ctype
!= "val*" then return
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
)
149 v
.add
("{res} = calloc(sizeof(struct {c_name}), 1);")
150 v
.add
("{res}->vft = NULL;") #TODO
152 for cd
in mtype
.collect_mclassdefs
(self.mainmodule
)
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
)
161 v
.add
("return {res};")
166 # The C function associated to a methoddef separately compiled
167 class SeparateRuntimeFunction
168 super RuntimeFunction
170 # The mangled c name of the runtime_function
171 redef fun c_name
: String
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
180 private var c_name_cache
: nullable String = null
182 redef fun to_s
do return self.mmethoddef
.to_s
184 redef fun compile_to_c
(compiler
)
186 var mmethoddef
= self.mmethoddef
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
)
196 var comment
= new Buffer
197 var ret
= mmethoddef
.msignature
.return_mtype
199 ret
= v
.resolve_for
(ret
, selfvar
)
200 sig
.append
("{ret.ctype} ")
201 else if mmethoddef
.mproperty
.is_new
then
203 sig
.append
("{ret.ctype} ")
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
])
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
)
225 comment
.append
(": {ret}")
227 compiler
.header
.add_decl
("{sig};")
229 v
.add_decl
("/* method {self} for {comment} */")
230 v
.add_decl
("{sig} \{")
232 frame
.returnvar
= v
.new_var
(ret
)
234 frame
.returnlabel
= v
.get_name
("RET_LABEL")
236 if recv
!= arguments
.first
.mtype
then
237 print
"{self} {recv} {arguments.first}"
239 mmethoddef
.compile_inside_to_c
(v
, arguments
)
241 v
.add
("{frame.returnlabel.as(not null)}:;")
243 v
.add
("return {frame.returnvar.as(not null)};")
248 redef fun call
(v
, arguments
)
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
259 redef fun autobox
(value
, mtype
)
265 redef fun send
(mmethod
, arguments
)
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
)
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
281 ret
= self.resolve_for
(ret
, arguments
.first
)
282 res
= self.new_var
(ret
)
287 for a
in arguments
do
288 if a
!= arguments
.first
then
292 s
.append
("{a.mtype.ctype}")
298 if ret
== null then r
= "void" else r
= ret
.ctype
299 var call
= "(({r} (*)({s}))({arguments.first}->vft[{color}]))({ss})"
302 self.add
("{res} = {call};")
310 redef fun call
(mmethoddef
, recvtype
, arguments
)
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
320 ret
= self.resolve_for
(ret
, arguments
.first
)
321 res
= self.new_var
(ret
)
325 self.add
("{mmethoddef.c_name}({arguments.join(",")});")
328 self.add
("{res} = {mmethoddef.c_name}({arguments.join(",")});")
334 redef fun read_attribute
(a
, recv
)
336 var ret
= a
.intro
.static_mtype
.as(not null)
337 ret
= self.resolve_for
(ret
, recv
)
338 var res
= self.new_var
(ret
)
343 redef fun write_attribute
(a
, recv
, value
)
348 redef fun init_instance
(mtype
)
350 mtype
= self.anchor
(mtype
).as(MClassType)
351 var res
= self.new_expr
("NEW_{mtype.mclass.name}()", mtype
)
355 redef fun type_test
(value
, mtype
)
357 var res
= self.new_var
(bool_type
)
362 redef fun equal_test
(value1
, value2
)
364 var res
= self.new_var
(bool_type
)