tools: add entrypoint information to the program
[nit.git] / src / compiling / compiling_global.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2008 Jean Privat <jean@pryen.org>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Compute and generate tables for classes and modules.
18 package compiling_global
19
20 import table_computation
21 private import compiling_icode
22
23 class GlobalCompilerVisitor
24 special CompilerVisitor
25 # The global analysis result
26 readable var _program: Program
27 init(m: MMModule, tc: ToolContext, prog: Program)
28 do
29 super(m, tc)
30 _program = prog
31 end
32 end
33
34 redef class Program
35 # Compile module and class tables
36 fun compile_tables_to_c(v: GlobalCompilerVisitor)
37 do
38 for m in module.mhe.greaters_and_self do
39 m.compile_local_table_to_c(v)
40 end
41
42 for c in module.local_classes do
43 c.compile_tables_to_c(v)
44 end
45 var s = new Buffer.from("classtable_t TAG2VFT[4] = \{NULL")
46 for t in ["Int","Char","Bool"] do
47 if module.has_global_class_named(t.to_symbol) then
48 s.append(", (const classtable_t)VFT_{t}")
49 else
50 s.append(", NULL")
51 end
52 end
53 s.append("};")
54 v.add_instr(s.to_s)
55 end
56
57 # Compile main part (for _table.c)
58 fun compile_main_part(v: GlobalCompilerVisitor)
59 do
60 v.add_instr("int main(int argc, char **argv) \{")
61 v.indent
62 v.add_instr("prepare_signals();")
63 v.add_instr("glob_argc = argc; glob_argv = argv;")
64 if v.program.main_method == null then
65 print("No main")
66 else
67 v.add_instr("G_sys = NEW_Sys();")
68 v.add_instr("register_static_object(&G_sys);")
69 v.add_instr("{v.program.main_method.cname}(G_sys);")
70 end
71 v.add_instr("return 0;")
72 v.unindent
73 v.add_instr("}")
74 end
75 end
76
77 redef class MMModule
78 # Declare class table (for _sep.h)
79 fun declare_class_tables_to_c(v: GlobalCompilerVisitor)
80 do
81 for c in local_classes do
82 if c.global.module == self then
83 c.declare_tables_to_c(v)
84 end
85 end
86 end
87
88 # Compile sep files
89 fun compile_mod_to_c(v: GlobalCompilerVisitor)
90 do
91 v.add_decl("extern const char *LOCATE_{name};")
92 if not v.tc.global then
93 v.add_decl("extern const int SFT_{name}[];")
94 end
95 var i = 0
96 for e in local_table do
97 var value: String
98 if v.tc.global then
99 value = "{e.value(v.program)}"
100 else
101 value = "SFT_{name}[{i}]"
102 i = i + 1
103 end
104 e.compile_macros(v, value)
105 end
106 for c in local_classes do
107 if not c isa MMConcreteClass then continue
108 for pg in c.global_properties do
109 var p = c[pg]
110 if p.local_class == c and p isa MMMethod then
111 p.compile_property_to_c(v)
112 end
113 if pg.is_init_for(c) then
114 # Declare constructors
115 var params = new Array[String]
116 for j in [0..p.signature.arity[ do
117 params.add("val_t p{j}")
118 end
119 v.add_decl("val_t NEW_{c}_{p.global.intro.cname}({params.join(", ")});")
120 end
121 end
122 end
123 end
124
125 # Compile module file for the current module
126 fun compile_local_table_to_c(v: GlobalCompilerVisitor)
127 do
128 v.add_instr("const char *LOCATE_{name} = \"{location.file}\";")
129
130 if v.tc.global or local_table.is_empty then
131 return
132 end
133
134 v.add_instr("const int SFT_{name}[{local_table.length}] = \{")
135 v.indent
136 for e in local_table do
137 v.add_instr(e.value(v.program) + ",")
138 end
139 v.unindent
140 v.add_instr("\};")
141 end
142 end
143
144 ###############################################################################
145
146 redef class AbsTableElt
147 # Compile the macro needed to use the element and other related elements
148 fun compile_macros(v: GlobalCompilerVisitor, value: String) is abstract
149 end
150
151 redef class TableElt
152 # Return the value of the element for a given class
153 fun compile_to_c(v: GlobalCompilerVisitor, c: MMLocalClass): String is abstract
154 end
155
156 redef class ModuleTableElt
157 # Return the value of the element once the global analisys is performed
158 fun value(prog: Program): String is abstract
159 end
160
161 redef class ModuleTableEltGroup
162 redef fun value(prog) do return "{prog.table_information.color(elements.first)} /* Group of ? */"
163 redef fun compile_macros(v, value)
164 do
165 var i = 0
166 for e in elements do
167 e.compile_macros(v, "{value} + {i}")
168 i += 1
169 end
170 end
171 end
172
173 redef class TableEltMeth
174 redef fun compile_macros(v, value)
175 do
176 var pg = property.global
177 v.add_decl("#define {pg.meth_call}(recv) (({pg.intro.cname}_t)CALL((recv), ({value})))")
178 end
179
180 redef fun compile_to_c(v, c)
181 do
182 var p = c[property.global]
183 return p.cname
184 end
185 end
186
187 redef class TableEltSuper
188 redef fun compile_macros(v, value)
189 do
190 var p = property
191 v.add_decl("#define {p.super_meth_call}(recv) (({p.cname}_t)CALL((recv), ({value})))")
192 end
193
194 redef fun compile_to_c(v, c)
195 do
196 var pc = property.local_class
197 var g = property.global
198 var lin = c.che.linear_extension
199 var found = false
200 for s in lin do
201 #print "{c.module}::{c} for {pc.module}::{pc}::{_property} try {s.module}:{s}"
202 if s == pc then
203 found = true
204 else if found and c.che < s then
205 if s.has_global_property(g) then
206 #print "found {s.module}::{s}::{p}"
207 return s[g].cname
208 end
209 end
210 end
211 abort
212 end
213 end
214
215 redef class TableEltAttr
216 redef fun compile_macros(v, value)
217 do
218 var pg = property.global
219 v.add_decl("#define {pg.attr_access}(recv) ATTR(recv, ({value}))")
220 end
221
222 redef fun compile_to_c(v, c)
223 do
224 var prog = v.program
225 var p = c[property.global]
226 return "/* {prog.table_information.color(self)}: Attribute {c}::{p} */"
227 end
228 end
229
230 redef class AbsTableEltClass
231 # The C macro name refering the value
232 fun symbol: String is abstract
233
234 redef fun compile_macros(v, value)
235 do
236 v.add_decl("#define {symbol} ({value})")
237 end
238 end
239
240 redef class TableEltClassId
241 redef fun symbol do return local_class.global.id_id
242
243 redef fun value(prog)
244 do
245 return "{prog.compiled_classes[local_class.global].id} /* Id of {local_class} */"
246 end
247 end
248
249 redef class TableEltClassInitTable
250 redef fun symbol do return local_class.global.init_table_pos_id
251
252 redef fun compile_to_c(v, c)
253 do
254 var prog = v.program
255 var cc = prog.compiled_classes[local_class.global]
256 var linext = c.cshe.reverse_linear_extension
257 var i = 0
258 while linext[i].global != local_class.global do
259 i += 1
260 end
261 return "{i} /* {prog.table_information.color(self)}: {c} < {cc.local_class}: superclass init_table position */"
262 end
263 end
264
265 redef class TableEltClassColor
266 redef fun symbol do return local_class.global.color_id
267
268 redef fun value(prog)
269 do
270 return "{prog.table_information.color(self)} /* Color of {local_class} */"
271 end
272
273 redef fun compile_to_c(v, c)
274 do
275 var prog = v.program
276 var cc = prog.compiled_classes[local_class.global]
277 return "{cc.id} /* {prog.table_information.color(self)}: {c} < {cc.local_class}: superclass typecheck marker */"
278 end
279 end
280
281 redef class TableEltComposite
282 redef fun compile_to_c(v, c) do abort
283 end
284
285 redef class TableEltClassSelfId
286 redef fun compile_to_c(v, c)
287 do
288 var prog = v.program
289 return "{prog.compiled_classes[c.global].id} /* {prog.table_information.color(self)}: Identity */"
290 end
291 end
292
293 redef class TableEltClassObjectSize
294 redef fun compile_to_c(v, c)
295 do
296 var nb = 0
297 var p = v.program
298 if c.name == "NativeArray".to_symbol then
299 nb = -1
300 else
301 var cc = p.compiled_classes[c.global]
302 var itab = cc.instance_table
303 for e in itab do
304 nb += 1
305 end
306 end
307 return "{nb} /* {p.table_information.color(self)}: Object size (-1 if a NativeArray)*/"
308 end
309 end
310
311 redef class TableEltObjectId
312 redef fun compile_to_c(v, c)
313 do
314 var p = v.program
315 return "/* {p.table_information.color(self)}: Object_id */"
316 end
317 end
318
319 redef class TableEltVftPointer
320 redef fun compile_to_c(v, c)
321 do
322 var prog = v.program
323 return "/* {prog.table_information.color(self)}: Pointer to the classtable */"
324 end
325 end
326
327 ###############################################################################
328
329 redef class MMLocalClass
330 # IRoutine for the initialization of the default attributes (called by IInitAttributes)
331 var _init_var_iroutine: nullable IRoutine = null
332 # IRoutine to validate the instance after initialization (called by ICheckInstance)
333 var _checknew_iroutine: nullable IRoutine = null
334 # IRoutines to call to create a new valid instance (memory allocated, object initialized and validated)
335 # These iroutines will call: IAllocateInstance, IInitAttributes, some init function and ICheckInstance
336 # These routines will be called by INew
337 var _new_instance_iroutine: HashMap[MMMethod, IRoutine] = new HashMap[MMMethod, IRoutine]
338
339 # Declaration and macros related to the class table
340 fun declare_tables_to_c(v: GlobalCompilerVisitor)
341 do
342 v.add_decl("")
343 var pi = primitive_info
344 v.add_decl("extern const classtable_elt_t VFT_{name}[];")
345 if name == "NativeArray".to_symbol then
346 v.add_decl("val_t NEW_NativeArray(size_t length, size_t size);")
347 else if pi == null then
348 # v.add_decl("val_t NEW_{name}(void);")
349 else if not pi.tagged then
350 var t = pi.cname
351 var tbox = "struct TBOX_{name}"
352 v.add_decl("{tbox} \{ const classtable_elt_t * vft; bigint object_id; {t} val;};")
353 v.add_decl("val_t BOX_{name}({t} val);")
354 v.add_decl("#define UNBOX_{name}(x) ((({tbox} *)(VAL2OBJ(x)))->val)")
355 end
356 end
357
358 # Generation of allocation function of this class
359 fun generate_allocation_iroutines(prog: Program)
360 do
361 var cc = prog.compiled_classes[self.global]
362
363 var pi = primitive_info
364 if pi == null then
365 do
366 # Generate INIT_ATTRIBUTES routine
367 var iself = new IRegister(get_type)
368 var iselfa = [iself]
369 var iroutine = new IRoutine(iselfa, null)
370 var icb = new ICodeBuilder(module, iroutine)
371
372 for g in global_properties do
373 var p = self[g]
374 var t = p.signature.return_type
375 if p isa MMAttribute and t != null then
376 var ir = p.iroutine
377 if ir == null then continue
378 # FIXME: Not compatible with sep compilation
379 var e = icb.inline_routine(ir, iselfa, null).as(not null)
380 icb.stmt(new IAttrWrite(p, iself, e))
381 end
382 end
383
384 _init_var_iroutine = iroutine
385 end
386 do
387 # Compile CHECKNAME
388 var iself = new IRegister(get_type)
389 var iselfa = [iself]
390 var iroutine = new IRoutine(iselfa, null)
391 var icb = new ICodeBuilder(module, iroutine)
392 for g in global_properties do
393 var p = self[g]
394 var t = p.signature.return_type
395 if p isa MMAttribute and t != null and not t.is_nullable then
396 icb.add_attr_check(p, iself)
397 end
398 end
399
400 _checknew_iroutine = iroutine
401 end
402
403 var init_table_size = cshe.greaters.length + 1
404
405 for g in global_properties do
406 var p = self[g]
407 # FIXME skip invisible constructors
408 if not p.global.is_init_for(self) then continue
409 assert p isa MMMethod
410
411 var iself = new IRegister(get_type)
412 var iparams = new Array[IRegister]
413 for i in [0..p.signature.arity[ do iparams.add(new IRegister(p.signature[i]))
414 var iroutine = new IRoutine(iparams, iself)
415 iroutine.location = p.iroutine.location
416 var icb = new ICodeBuilder(module, iroutine)
417
418 var inew = new IAllocateInstance(get_type)
419 inew.result = iself
420 icb.stmt(inew)
421 var iargs = [iself]
422 iargs.add_all(iparams)
423
424 icb.stmt(new IInitAttributes(get_type, iself))
425 icb.stmt(new IStaticCall(p, iargs))
426 icb.stmt(new ICheckInstance(get_type, iself))
427
428 _new_instance_iroutine[p] = iroutine
429 end
430 end
431 end
432
433 # Compilation of table and new (or box)
434 fun compile_tables_to_c(v: GlobalCompilerVisitor)
435 do
436 var cc = v.program.compiled_classes[self.global]
437 var ctab = cc.class_table
438 var clen = ctab.length
439 if v.program.table_information.max_class_table_length > ctab.length then
440 clen = v.program.table_information.max_class_table_length
441 end
442
443 v.add_instr("const classtable_elt_t VFT_{name}[{clen}] = \{")
444 v.indent
445 for e in ctab do
446 if e == null then
447 v.add_instr("\{0} /* Class Hole :( */,")
448 else
449 v.add_instr("\{(bigint) {e.compile_to_c(v, self)}},")
450 end
451 end
452 if clen > ctab.length then
453 v.add_instr("\{0},"*(clen-ctab.length))
454 end
455 v.unindent
456 v.add_instr("};")
457 var itab = cc.instance_table
458 for e in itab do
459 if e == null then
460 v.add_instr("/* Instance Hole :( */")
461 else
462 v.add_instr(e.compile_to_c(v, self))
463 end
464 end
465
466 var pi = primitive_info
467 if name == "NativeArray".to_symbol then
468 v.add_instr("val_t NEW_NativeArray(size_t length, size_t size) \{")
469 v.indent
470 v.add_instr("Nit_NativeArray array;")
471 v.add_instr("array = (Nit_NativeArray)alloc(sizeof(struct Nit_NativeArray) + ((length - 1) * size));")
472 v.add_instr("array->vft = (classtable_elt_t*)VFT_{name};")
473 v.add_instr("array->object_id = object_id_counter;")
474 v.add_instr("object_id_counter = object_id_counter + 1;")
475 v.add_instr("array->size = length;")
476 v.add_instr("return OBJ2VAL(array);")
477 v.unindent
478 v.add_instr("}")
479 else if pi == null then
480 do
481 # Generate INIT_ATTRIBUTES routine
482 var cname = "INIT_ATTRIBUTES__{name}"
483 var args = _init_var_iroutine.compile_signature_to_c(v, cname, "init var of {name}", null, null)
484 var ctx_old = v.ctx
485 v.ctx = new CContext
486 _init_var_iroutine.compile_to_c(v, cname, args)
487 ctx_old.append(v.ctx)
488 v.ctx = ctx_old
489 v.unindent
490 v.add_instr("}")
491 end
492 do
493 # Generate NEW routine
494 v.add_decl("val_t NEW_{name}(void);")
495 v.add_instr("val_t NEW_{name}(void)")
496 v.add_instr("\{")
497 v.indent
498 v.add_instr("obj_t obj;")
499 v.add_instr("obj = alloc(sizeof(val_t) * {itab.length});")
500 v.add_instr("obj->vft = (classtable_elt_t*)VFT_{name};")
501 v.add_instr("obj[1].object_id = object_id_counter;")
502 v.add_instr("object_id_counter = object_id_counter + 1;")
503 v.add_instr("return OBJ2VAL(obj);")
504 v.unindent
505 v.add_instr("}")
506 end
507 do
508 # Compile CHECKNAME
509 var cname = "CHECKNEW_{name}"
510 var args = _checknew_iroutine.compile_signature_to_c(v, cname, "check new {name}", null, null)
511 var ctx_old = v.ctx
512 v.ctx = new CContext
513 _checknew_iroutine.compile_to_c(v, cname, args)
514 ctx_old.append(v.ctx)
515 v.ctx = ctx_old
516 v.unindent
517 v.add_instr("}")
518 end
519
520 var init_table_size = cshe.greaters.length + 1
521 var init_table_decl = "int init_table[{init_table_size}] = \{0{", 0" * (init_table_size-1)}};"
522
523 for g in global_properties do
524 var p = self[g]
525 # FIXME skip invisible constructors
526 if not p.global.is_init_for(self) then continue
527 assert p isa MMMethod
528
529 var cname = "NEW_{self}_{p.global.intro.cname}"
530 var new_args = _new_instance_iroutine[p].compile_signature_to_c(v, cname, "new {self} {p.full_name}", null, null)
531 var ctx_old = v.ctx
532 v.ctx = new CContext
533 v.add_instr(init_table_decl)
534 var e = _new_instance_iroutine[p].compile_to_c(v, cname, new_args).as(not null)
535 v.add_instr("return {e};")
536 ctx_old.append(v.ctx)
537 v.ctx = ctx_old
538 v.unindent
539 v.add_instr("}")
540 end
541 else if not pi.tagged then
542 var t = pi.cname
543 var tbox = "struct TBOX_{name}"
544 v.add_instr("val_t BOX_{name}({t} val) \{")
545 v.indent
546 v.add_instr("{tbox} *box = ({tbox}*)alloc(sizeof({tbox}));")
547 v.add_instr("box->vft = VFT_{name};")
548 v.add_instr("box->val = val;")
549 v.add_instr("box->object_id = object_id_counter;")
550 v.add_instr("object_id_counter = object_id_counter + 1;")
551 v.add_instr("return OBJ2VAL(box);")
552 v.unindent
553 v.add_instr("}")
554 end
555 end
556 end
557
558 redef class MMMethod
559 fun compile_property_to_c(v: CompilerVisitor)
560 do
561 var ir = iroutine
562 assert ir != null
563
564 var more_params: nullable String = null
565 if global.is_init then more_params = "int* init_table"
566 var args = ir.compile_signature_to_c(v, cname, full_name, null, more_params)
567 var ctx_old = v.ctx
568 v.ctx = new CContext
569
570 v.out_contexts.clear
571
572 var itpos: nullable String = null
573 if global.is_init then
574 itpos = "itpos{v.new_number}"
575 v.add_decl("int {itpos} = VAL2OBJ({args.first})->vft[{local_class.global.init_table_pos_id}].i;")
576 v.add_instr("if (init_table[{itpos}]) return;")
577 end
578
579 var s = ir.compile_to_c(v, cname, args)
580
581 if itpos != null then
582 v.add_instr("init_table[{itpos}] = 1;")
583 end
584 if s == null then
585 v.add_instr("return;")
586 else
587 v.add_instr("return ", s, ";")
588 end
589
590 ctx_old.append(v.ctx)
591 v.ctx = ctx_old
592 v.unindent
593 v.add_instr("}")
594
595 for ctx in v.out_contexts do v.ctx.merge(ctx)
596 end
597 end
598