nitg: type_test assert that the cast-type was detected by RTA
[nit.git] / src / global_compiler.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2012 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 # Global compilation of a Nit program
18 #
19 # Techniques used are:
20 # * heterogeneous generics
21 # * customization
22 # * switch dispatch
23 # * inlining
24 module global_compiler
25
26 import literal
27 import typing
28 import auto_super_init
29 import rapid_type_analysis
30
31 redef class ToolContext
32 # --output
33 var opt_output: OptionString = new OptionString("Output file", "-o", "--output")
34
35 # --no-cc
36 var opt_no_cc: OptionBool = new OptionBool("Do not invoke C compiler", "--no-cc")
37
38 # --hardening
39 var opt_hardening: OptionBool = new OptionBool("Generate contracts in the C code against bugs in the compiler", "--hardening")
40
41 redef init
42 do
43 super
44 self.option_context.add_option(self.opt_output, self.opt_no_cc, self.opt_hardening)
45 end
46 end
47
48 redef class ModelBuilder
49 # Entry point to performs a global compilation on the AST of a complete program.
50 # `mainmodule` is the main module of the program
51 # `runtime_type_analysis` is a already computer type analysis.
52 fun run_global_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis)
53 do
54 var time0 = get_time
55 self.toolcontext.info("*** COMPILING TO C ***", 1)
56
57 var compiler = new GlobalCompiler(mainmodule, runtime_type_analysis, self)
58 var v = new GlobalCompilerVisitor(compiler)
59
60 v.add_decl("#include <stdlib.h>")
61 v.add_decl("#include <stdio.h>")
62 v.add_decl("#include <string.h>")
63
64 # TODO: Better way to activate the GC
65 v.add_decl("#include <gc/gc.h>")
66 #v.add_decl("#define GC_MALLOC(x) calloc(1, (x))")
67
68 # Declaration of structures the live Nit types
69 # Each live type is generated as an independent C `struct' type.
70 # They only share a common first field `classid` used to implement the polymorphism.
71 # Usualy, all C variables that refers to a Nit object are typed on the abstract struct `val' that contains only the `classid` field.
72
73 v.add_decl("typedef struct \{int classid;\} val; /* general C type representing a Nit instance. */")
74 for t in runtime_type_analysis.live_types do
75 compiler.declare_runtimeclass(v, t)
76 end
77
78 # Global variable used by the legacy native interface
79
80 v.add_decl("extern int glob_argc;")
81 v.add_decl("extern char **glob_argv;")
82 v.add_decl("extern val *glob_sys;")
83
84 # Class names (for the class_name and output_class_name methods)
85
86 v.add_decl("extern const char const * class_names[];")
87 v.add("const char const * class_names[] = \{")
88 for t in runtime_type_analysis.live_types do
89 v.add("\"{t}\", /* {compiler.classid(t)} */")
90 end
91 v.add("\};")
92 compiler.header = v
93
94 # Init instance code (allocate and init-arguments)
95
96 for t in runtime_type_analysis.live_types do
97 if t.ctype == "val*" then
98 compiler.generate_init_instance(t)
99 else
100 compiler.generate_box_instance(t)
101 end
102 end
103
104 # The main function of the C
105
106 v = new GlobalCompilerVisitor(compiler)
107 v.add_decl("int glob_argc;")
108 v.add_decl("char **glob_argv;")
109 v.add_decl("val *glob_sys;")
110 v.add_decl("int main(int argc, char** argv) \{")
111 v.add("glob_argc = argc; glob_argv = argv;")
112 var main_type = mainmodule.sys_type
113 if main_type == null then return # Nothing to compile
114 var glob_sys = v.init_instance(main_type)
115 v.add("glob_sys = {glob_sys};")
116 var main_init = mainmodule.try_get_primitive_method("init", main_type)
117 if main_init != null then
118 v.send(main_init, [glob_sys])
119 end
120 var main_method = mainmodule.try_get_primitive_method("main", main_type)
121 if main_method != null then
122 v.send(main_method, [glob_sys])
123 end
124 v.add("return 0;")
125 v.add("\}")
126
127 # Compile until all runtime_functions are visited
128
129 while not compiler.todos.is_empty do
130 var m = compiler.todos.shift
131 self.toolcontext.info("Compile {m} ({compiler.seen.length-compiler.todos.length}/{compiler.seen.length})", 3)
132 m.compile_to_c(compiler)
133 end
134 self.toolcontext.info("Total methods to compile to C: {compiler.visitors.length}", 2)
135
136 var time1 = get_time
137 self.toolcontext.info("*** END VISITING: {time1-time0} ***", 2)
138 write_and_make(compiler)
139 end
140
141 protected fun write_and_make(compiler: GlobalCompiler)
142 do
143 var mainmodule = compiler.mainmodule
144
145 # Generate the .h and .c files
146 # A single C file regroups many compiled rumtime functions
147 # Note that we do not try to be clever an a small change in a Nit source file may change the content of all the generated .c files
148 var time0 = get_time
149
150 var outname = self.toolcontext.opt_output.value
151 if outname == null then
152 outname = "{mainmodule.name}.bin"
153 end
154
155 var hfilename = ".nit_compile/{mainmodule.name}.1.h"
156 var h = new OFStream.open(hfilename)
157 for l in compiler.header.decl_lines do
158 h.write l
159 h.write "\n"
160 end
161 h.close
162
163 var cfiles = new Array[String]
164
165 var file: nullable OFStream = null
166 var count = 0
167
168 ".nit_compile".mkdir
169 var i = 0
170 for vis in compiler.visitors do
171 count += vis.lines.length
172 if file == null or count > 10000 then
173 i += 1
174 if file != null then file.close
175 var cfilename = ".nit_compile/{mainmodule.name}.{i}.c"
176 cfiles.add(cfilename)
177 file = new OFStream.open(cfilename)
178 file.write "#include \"{mainmodule.name}.1.h\"\n"
179 count = vis.lines.length
180 end
181 if vis != compiler.header then
182 for l in vis.decl_lines do
183 file.write l
184 file.write "\n"
185 end
186 end
187 for l in vis.lines do
188 file.write l
189 file.write "\n"
190 end
191 end
192 if file != null then file.close
193
194 self.toolcontext.info("Total C source files to compile: {cfiles.length}", 2)
195
196 # Generate the Makefile
197
198 var makename = ".nit_compile/{mainmodule.name}.mk"
199 var makefile = new OFStream.open(makename)
200
201 makefile.write("CC = ccache cc\nCFLAGS = -g -O2\nLDFLAGS ?= \nLDLIBS ?= -lm -lgc\n\n")
202 makefile.write("all: {outname}\n\n")
203
204 var ofiles = new Array[String]
205 # Compile each generated file
206 for f in cfiles do
207 var o = f.strip_extension(".c") + ".o"
208 makefile.write("{o}: {f}\n\t$(CC) $(CFLAGS) -D NONITCNI -c -o {o} {f}\n\n")
209 ofiles.add(o)
210 end
211 # Compile each required extern body into a specific .o
212 for f in compiler.extern_bodies do
213 i += 1
214 var o = ".nit_compile/{mainmodule.name}.{i}.o"
215 makefile.write("{o}: {f}\n\t$(CC) $(CFLAGS) -D NONITCNI -c -o {o} {f}\n\n")
216 ofiles.add(o)
217 end
218 # Link edition
219 makefile.write("{outname}: {ofiles.join(" ")}\n\t$(CC) $(LDFLAGS) -o {outname} {ofiles.join(" ")} $(LDLIBS)\n\n")
220 # Clean
221 makefile.write("clean:\n\trm {ofiles.join(" ")} 2>/dev/null\n\n")
222 makefile.close
223 self.toolcontext.info("Generated makefile: {makename}", 2)
224
225 var time1 = get_time
226 self.toolcontext.info("*** END COMPILING TO C: {time1-time0} ***", 2)
227
228 # Execute the Makefile
229
230 if self.toolcontext.opt_no_cc.value then return
231
232 time0 = time1
233 self.toolcontext.info("*** COMPILING C ***", 1)
234 self.toolcontext.info("make -B -f {makename} -j 4", 2)
235
236 var res
237 if self.toolcontext.verbose_level >= 3 then
238 res = sys.system("make -B -f {makename} -j 4 2>&1")
239 else
240 res = sys.system("make -B -f {makename} -j 4 2>&1 >/dev/null")
241 end
242 if res != 0 then
243 toolcontext.error(null, "make failed! Error code: {res}.")
244 end
245
246 time1 = get_time
247 self.toolcontext.info("*** END COMPILING C: {time1-time0} ***", 2)
248 end
249 end
250
251 # Singleton that store the knowledge about the compilation process
252 class GlobalCompiler
253 # The main module of the program
254 var mainmodule: MModule
255
256 # The result of the RTA (used to know live types and methods)
257 var runtime_type_analysis: RapidTypeAnalysis
258
259 # The modeulbuilder used to know the model and the AST
260 var modelbuilder: ModelBuilder
261
262 # Is hardening asked? (see --hardening)
263 fun hardening: Bool do return self.modelbuilder.toolcontext.opt_hardening.value
264
265 init(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis, modelbuilder: ModelBuilder)
266 do
267 self.mainmodule = mainmodule
268 self.runtime_type_analysis = runtime_type_analysis
269 self.modelbuilder = modelbuilder
270 self.live_primitive_types = new Array[MClassType]
271 for t in runtime_type_analysis.live_types do
272 if t.ctype != "val*" then
273 self.live_primitive_types.add(t)
274 end
275 end
276 end
277
278 # Subset of runtime_type_analysis.live_types that contains only primitive types
279 # Used to implement the equal test
280 var live_primitive_types: Array[MClassType]
281
282 # runtime_functions that need to be compiled
283 private var todos: List[AbstractRuntimeFunction] = new List[AbstractRuntimeFunction]
284
285 # runtime_functions already seen (todo or done)
286 private var seen: HashSet[AbstractRuntimeFunction] = new HashSet[AbstractRuntimeFunction]
287 fun todo(m: AbstractRuntimeFunction)
288 do
289 if seen.has(m) then return
290 todos.add(m)
291 seen.add(m)
292 end
293
294 # Where global declaration are stored (the main .h)
295 #
296 # FIXME: should not be a vistor but just somewhere to store lines
297 # FIXME: should not have a global .h since it does not help recompilations
298 var header: nullable GlobalCompilerVisitor writable = null
299
300 # The list of all associated visitors
301 # Used to generate .c files
302 # FIXME: should not be vistors but just somewhere to store lines
303 private var visitors: List[GlobalCompilerVisitor] = new List[GlobalCompilerVisitor]
304
305 # List of additional .c files required to compile (native interface)
306 var extern_bodies = new ArraySet[String]
307
308 # Return the C symbol associated to a live type runtime
309 # REQUIRE: self.runtime_type_analysis.live_types.has(mtype)
310 fun classid(mtype: MClassType): String
311 do
312 if self.classids.has_key(mtype) then
313 return self.classids[mtype]
314 end
315 print "No classid for {mtype}"
316 abort
317 end
318
319 # Cache for classid (computed by declare_runtimeclass)
320 protected var classids: HashMap[MClassType, String] = new HashMap[MClassType, String]
321
322 # Declare C structures and identifiers for a runtime class
323 fun declare_runtimeclass(v: GlobalCompilerVisitor, mtype: MClassType)
324 do
325 assert self.runtime_type_analysis.live_types.has(mtype)
326 v.add_decl("/* runtime class {mtype} */")
327 var idnum = classids.length
328 var idname = "ID_" + mtype.c_name
329 self.classids[mtype] = idname
330 v.add_decl("#define {idname} {idnum} /* {mtype} */")
331
332 v.add_decl("struct {mtype.c_name} \{")
333 v.add_decl("int classid; /* must be {idname} */")
334
335 if mtype.mclass.name == "NativeArray" then
336 # NativeArrays are just a instance header followed by an array of values
337 v.add_decl("{mtype.arguments.first.ctype} values[1];")
338 end
339
340 if mtype.ctype != "val*" then
341 # Is the Nit type is native then the struct is a box with two fields:
342 # * the `classid` to be polymorph
343 # * the `value` that contains the native value.
344 v.add_decl("{mtype.ctype} value;")
345 end
346
347 # Collect all attributes and associate them a field in the structure.
348 # Note: we do not try to optimize the order and helps CC to optimize the client code.
349 for cd in mtype.collect_mclassdefs(self.mainmodule) do
350 for p in cd.intro_mproperties do
351 if not p isa MAttribute then continue
352 var t = p.intro.static_mtype.as(not null)
353 t = t.anchor_to(self.mainmodule, mtype)
354 v.add_decl("{t.ctype} {p.intro.c_name}; /* {p}: {t} */")
355 end
356 end
357 v.add_decl("\};")
358 end
359
360 # Generate the init-instance of a live type (allocate + init-instance)
361 fun generate_init_instance(mtype: MClassType)
362 do
363 assert self.runtime_type_analysis.live_types.has(mtype)
364 assert mtype.ctype == "val*"
365 var v = new GlobalCompilerVisitor(self)
366
367 var is_native_array = mtype.mclass.name == "NativeArray"
368
369 var sig
370 if is_native_array then
371 sig = "int length"
372 else
373 sig = "void"
374 end
375
376 self.header.add_decl("{mtype.ctype} NEW_{mtype.c_name}({sig});")
377 v.add_decl("/* allocate {mtype} */")
378 v.add_decl("{mtype.ctype} NEW_{mtype.c_name}({sig}) \{")
379 var res = v.new_var(mtype)
380 res.is_exact = true
381 if is_native_array then
382 var mtype_elt = mtype.arguments.first
383 v.add("{res} = GC_MALLOC(sizeof(struct {mtype.c_name}) + length*sizeof({mtype_elt.ctype}));")
384 else
385 v.add("{res} = GC_MALLOC(sizeof(struct {mtype.c_name}));")
386 end
387 v.add("{res}->classid = {self.classid(mtype)};")
388
389 for cd in mtype.collect_mclassdefs(self.mainmodule)
390 do
391 var n = self.modelbuilder.mclassdef2nclassdef[cd]
392 for npropdef in n.n_propdefs do
393 if npropdef isa AAttrPropdef then
394 npropdef.init_expr(v, res)
395 end
396 end
397 end
398 v.add("return {res};")
399 v.add("\}")
400 end
401
402 fun generate_box_instance(mtype: MClassType)
403 do
404 assert self.runtime_type_analysis.live_types.has(mtype)
405 assert mtype.ctype != "val*"
406 var v = new GlobalCompilerVisitor(self)
407
408 self.header.add_decl("val* BOX_{mtype.c_name}({mtype.ctype});")
409 v.add_decl("/* allocate {mtype} */")
410 v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value) \{")
411 v.add("struct {mtype.c_name}*res = GC_MALLOC(sizeof(struct {mtype.c_name}));")
412 v.add("res->classid = {self.classid(mtype)};")
413 v.add("res->value = value;")
414 v.add("return (val*)res;")
415 v.add("\}")
416
417 end
418
419 # look for a needed .h and .c file for a given .nit source-file
420 # FIXME: bad API, parameter should be a MModule, not its source-file
421 fun add_extern(file: String)
422 do
423 file = file.strip_extension(".nit")
424 var tryfile = file + ".nit.h"
425 if tryfile.file_exists then
426 self.header.add_decl("#include \"{"..".join_path(tryfile)}\"")
427 end
428 tryfile = file + "_nit.h"
429 if tryfile.file_exists then
430 self.header.add_decl("#include \"{"..".join_path(tryfile)}\"")
431 end
432 tryfile = file + ".nit.c"
433 if tryfile.file_exists then
434 self.extern_bodies.add(tryfile)
435 end
436 tryfile = file + "_nit.c"
437 if tryfile.file_exists then
438 self.extern_bodies.add(tryfile)
439 end
440 end
441
442 private var collect_types_cache: HashMap[MType, Array[MClassType]] = new HashMap[MType, Array[MClassType]]
443 end
444
445 redef class String
446 # Mangle a string to be a unique valid C identifier
447 fun to_cmangle: String
448 do
449 var res = new Buffer
450 var underscore = false
451 for c in self do
452 if (c >= 'a' and c <= 'z') or (c >='A' and c <= 'Z') then
453 res.add(c)
454 underscore = false
455 continue
456 end
457 if underscore then
458 res.append('_'.ascii.to_s)
459 res.add('d')
460 end
461 if c >= '0' and c <= '9' then
462 res.add(c)
463 underscore = false
464 else if c == '_' then
465 res.add(c)
466 underscore = true
467 else
468 res.add('_')
469 res.append(c.ascii.to_s)
470 res.add('d')
471 underscore = false
472 end
473 end
474 return res.to_s
475 end
476
477 # Escape " \ ' and non printable characters for literal C strings or characters
478 fun escape_to_c: String
479 do
480 var b = new Buffer
481 for c in self do
482 if c == '\n' then
483 b.append("\\n")
484 else if c == '\0' then
485 b.append("\\0")
486 else if c == '"' then
487 b.append("\\\"")
488 else if c == '\'' then
489 b.append("\\\'")
490 else if c == '\\' then
491 b.append("\\\\")
492 else if c.ascii < 32 then
493 b.append("\\{c.ascii.to_base(8, false)}")
494 else
495 b.add(c)
496 end
497 end
498 return b.to_s
499 end
500 end
501
502 redef class MType
503 # Return the C type associated to a given Nit static type
504 fun ctype: String
505 do
506 return "val*"
507 end
508
509 # Return the name of the C structure associated to a Nit live type
510 # FIXME: move to GlobalCompiler so we can check that self is a live type
511 fun c_name: String is abstract
512 protected var c_name_cache: nullable String protected writable
513 end
514
515 redef class MClassType
516 redef fun c_name
517 do
518 var res = self.c_name_cache
519 if res != null then return res
520 res = "{mclass.intro_mmodule.name.to_cmangle}__{mclass.name.to_cmangle}"
521 self.c_name_cache = res
522 return res
523 end
524
525 redef fun ctype: String
526 do
527 if mclass.name == "Int" then
528 return "long"
529 else if mclass.name == "Bool" then
530 return "short int"
531 else if mclass.name == "Char" then
532 return "char"
533 else if mclass.name == "Float" then
534 return "double"
535 else if mclass.name == "NativeString" then
536 return "char*"
537 else if mclass.name == "NativeArray" then
538 #return "{self.arguments.first.ctype}*"
539 return "val*"
540 else if mclass.kind == extern_kind then
541 return "void*"
542 else
543 return "val*"
544 end
545 end
546 end
547
548 redef class MGenericType
549 redef fun c_name
550 do
551 var res = self.c_name_cache
552 if res != null then return res
553 res = super
554 for t in self.arguments do
555 res = res + t.c_name
556 end
557 self.c_name_cache = res
558 return res
559 end
560 end
561
562 redef class MParameterType
563 redef fun c_name
564 do
565 var res = self.c_name_cache
566 if res != null then return res
567 res = "FT{self.rank}"
568 self.c_name_cache = res
569 return res
570 end
571 end
572
573 redef class MNullableType
574 redef fun c_name
575 do
576 var res = self.c_name_cache
577 if res != null then return res
578 res = "nullable_{self.mtype.c_name}"
579 self.c_name_cache = res
580 return res
581 end
582 end
583
584 # A C function associated to a Nit method
585 # Because of customization, a given Nit method can be compiler more that once
586 abstract class AbstractRuntimeFunction
587 # The associated Nit method
588 var mmethoddef: MMethodDef
589
590 # The mangled c name of the runtime_function
591 # Subclasses should redefine `build_c_name` instead
592 fun c_name: String
593 do
594 var res = self.c_name_cache
595 if res != null then return res
596 res = self.build_c_name
597 self.c_name_cache = res
598 return res
599 end
600
601 # Non cached version of `c_name`
602 protected fun build_c_name: String is abstract
603
604 private var c_name_cache: nullable String = null
605
606 # Implements a call of the runtime_function
607 # May inline the body or generate a C function call
608 fun call(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable is abstract
609
610 # Generate the code for the RuntimeFunction
611 # Warning: compile more than once compilation makes CC unhappy
612 fun compile_to_c(compiler: GlobalCompiler) is abstract
613 end
614
615 # A runtime function customized on a specific monomrph receiver type
616 private class CustomizedRuntimeFunction
617 super AbstractRuntimeFunction
618
619 # The considered reciever
620 # (usually is a live type but no strong guarantee)
621 var recv: MClassType
622
623 init(mmethoddef: MMethodDef, recv: MClassType)
624 do
625 super(mmethoddef)
626 self.recv = recv
627 end
628
629 redef fun build_c_name: String
630 do
631 var res = self.c_name_cache
632 if res != null then return res
633 if self.mmethoddef.mclassdef.bound_mtype == self.recv then
634 res = self.mmethoddef.c_name
635 else
636 res = "{mmethoddef.c_name}__{recv.c_name}"
637 end
638 self.c_name_cache = res
639 return res
640 end
641
642 redef fun ==(o)
643 # used in the compiler worklist
644 do
645 if not o isa CustomizedRuntimeFunction then return false
646 if self.mmethoddef != o.mmethoddef then return false
647 if self.recv != o.recv then return false
648 return true
649 end
650
651 redef fun hash
652 # used in the compiler work-list
653 do
654 var res = self.mmethoddef.hash + self.recv.hash
655 return res
656 end
657
658 redef fun to_s
659 do
660 if self.mmethoddef.mclassdef.bound_mtype == self.recv then
661 return self.mmethoddef.to_s
662 else
663 return "{self.mmethoddef}@{self.recv}"
664 end
665 end
666
667 # compile the code customized for the reciever
668 redef fun compile_to_c(compiler)
669 do
670 var recv = self.recv
671 var mmethoddef = self.mmethoddef
672 if not recv.is_subtype(compiler.mainmodule, null, mmethoddef.mclassdef.bound_mtype) then
673 print("problem: why do we compile {self} for {recv}?")
674 abort
675 end
676
677 var v = new GlobalCompilerVisitor(compiler)
678 var selfvar = new RuntimeVariable("self", recv, recv)
679 if compiler.runtime_type_analysis.live_types.has(recv) then
680 selfvar.is_exact = true
681 end
682 var arguments = new Array[RuntimeVariable]
683 var frame = new Frame(v, mmethoddef, recv, arguments)
684 v.frame = frame
685
686 var sig = new Buffer
687 var comment = new Buffer
688 var ret = mmethoddef.msignature.return_mtype
689 if ret != null then
690 ret = v.resolve_for(ret, selfvar)
691 sig.append("{ret.ctype} ")
692 else if mmethoddef.mproperty.is_new then
693 ret = recv
694 sig.append("{ret.ctype} ")
695 else
696 sig.append("void ")
697 end
698 sig.append(self.c_name)
699 sig.append("({recv.ctype} {selfvar}")
700 comment.append("(self: {selfvar}")
701 arguments.add(selfvar)
702 for i in [0..mmethoddef.msignature.arity[ do
703 var mtype = mmethoddef.msignature.mparameters[i].mtype
704 if i == mmethoddef.msignature.vararg_rank then
705 mtype = v.get_class("Array").get_mtype([mtype])
706 end
707 mtype = v.resolve_for(mtype, selfvar)
708 comment.append(", {mtype}")
709 sig.append(", {mtype.ctype} p{i}")
710 var argvar = new RuntimeVariable("p{i}", mtype, mtype)
711 arguments.add(argvar)
712 end
713 sig.append(")")
714 comment.append(")")
715 if ret != null then
716 comment.append(": {ret}")
717 end
718 compiler.header.add_decl("{sig};")
719
720 v.add_decl("/* method {self} for {comment} */")
721 v.add_decl("{sig} \{")
722 #v.add("printf(\"method {self} for {comment}\\n\");")
723 if ret != null then
724 frame.returnvar = v.new_var(ret)
725 end
726 frame.returnlabel = v.get_name("RET_LABEL")
727
728 mmethoddef.compile_inside_to_c(v, arguments)
729
730 v.add("{frame.returnlabel.as(not null)}:;")
731 if ret != null then
732 v.add("return {frame.returnvar.as(not null)};")
733 end
734 v.add("\}")
735 end
736
737 redef fun call(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
738 do
739 var ret = self.mmethoddef.msignature.return_mtype
740 if self.mmethoddef.mproperty.is_new then
741 ret = recv
742 end
743 if ret != null then
744 ret = v.resolve_for(ret, arguments.first)
745 end
746 if self.mmethoddef.can_inline(v) then
747 var frame = new Frame(v, self.mmethoddef, self.recv, arguments)
748 frame.returnlabel = v.get_name("RET_LABEL")
749 if ret != null then
750 frame.returnvar = v.new_var(ret)
751 end
752 var old_frame = v.frame
753 v.frame = frame
754 v.add("\{ /* Inline {self} ({arguments.join(",")}) */")
755 self.mmethoddef.compile_inside_to_c(v, arguments)
756 v.add("{frame.returnlabel.as(not null)}:(void)0;")
757 v.add("\}")
758 v.frame = old_frame
759 return frame.returnvar
760 end
761 v.adapt_signature(self.mmethoddef, arguments)
762 v.compiler.todo(self)
763 if ret == null then
764 v.add("{self.c_name}({arguments.join(",")});")
765 return null
766 else
767 var res = v.new_var(ret)
768 v.add("{res} = {self.c_name}({arguments.join(",")});")
769 return res
770 end
771 end
772 end
773
774 # A runtime variable hold a runtime value in C.
775 # Runtime variables are associated to Nit local variables and intermediate results in Nit expressions.
776 #
777 # The tricky point is that a single C variable can be associated to more than one RuntimeVariable because the static knowledge of the type of an expression can vary in the C code.
778 class RuntimeVariable
779 # The name of the variable in the C code
780 var name: String
781
782 # The static type of the variable (as declard in C)
783 var mtype: MType
784
785 # The current casted type of the variable (as known in Nit)
786 var mcasttype: MType writable
787
788 # If the variable exaclty a mcasttype?
789 # false (usual value) means that the variable is a mcasttype or a subtype.
790 var is_exact: Bool writable = false
791
792 init(name: String, mtype: MType, mcasttype: MType)
793 do
794 self.name = name
795 self.mtype = mtype
796 self.mcasttype = mcasttype
797 assert not mtype.need_anchor
798 assert not mcasttype.need_anchor
799 end
800
801 redef fun to_s do return name
802
803 redef fun inspect
804 do
805 var exact_str
806 if self.is_exact then
807 exact_str = " exact"
808 else
809 exact_str = ""
810 end
811 var type_str
812 if self.mtype == self.mcasttype then
813 type_str = "{mtype}{exact_str}"
814 else
815 type_str = "{mtype}({mcasttype}{exact_str})"
816 end
817 return "<{name}:{type_str}>"
818 end
819 end
820
821 # A visitor on the AST of property definition that generate the C code.
822 # Because of inlining, a visitor can visit more than one property.
823 class GlobalCompilerVisitor
824 # The associated compiler
825 var compiler: GlobalCompiler
826
827 init(compiler: GlobalCompiler)
828 do
829 self.compiler = compiler
830 compiler.visitors.add(self)
831 end
832
833 # Alias for self.compiler.mainmodule.object_type
834 fun object_type: MClassType do return self.compiler.mainmodule.object_type
835
836 # Alias for self.compiler.mainmodule.bool_type
837 fun bool_type: MClassType do return self.compiler.mainmodule.bool_type
838
839 # Force to get the primitive class named `name' or abort
840 fun get_class(name: String): MClass
841 do
842 return self.compiler.mainmodule.get_primitive_class(name)
843 end
844
845 # Force to get the primitive property named `name' in the instance `recv' or abort
846 fun get_property(name: String, recv: MType): MMethod
847 do
848 return self.compiler.modelbuilder.force_get_primitive_method(self.current_node.as(not null), name, recv, self.compiler.mainmodule)
849 end
850
851 # The current Frame
852 var frame: nullable Frame writable
853
854 # Anchor a type to the main module and the current receiver
855 fun anchor(mtype: MType): MType
856 do
857 if not mtype.need_anchor then return mtype
858 #debug("anchor {mtype} to {self.reciever.as(not null)}:{self.reciever.mtype}")
859 return mtype.anchor_to(self.compiler.mainmodule, self.frame.receiver)
860 end
861
862 # Add a line in the main part of the generated C
863 fun add(s: String)
864 do
865 self.lines.add(s)
866 end
867
868 # Add a line in the
869 # (used for local or global declaration)
870 fun add_decl(s: String)
871 do
872 self.decl_lines.add(s)
873 end
874
875 private var lines: List[String] = new List[String]
876 private var decl_lines: List[String] = new List[String]
877
878 # The current visited AST node
879 var current_node: nullable ANode = null
880
881 # Compile an expression an return its result
882 # `mtype` is the expected return type, pass null if no specific type is expected.
883 fun expr(nexpr: AExpr, mtype: nullable MType): RuntimeVariable
884 do
885 var old = self.current_node
886 self.current_node = nexpr
887 var res = nexpr.expr(self).as(not null)
888 if mtype != null then
889 mtype = self.anchor(mtype)
890 res = self.autobox(res, mtype)
891 end
892 self.current_node = old
893 return res
894 end
895
896 # Unsafely cast a value to a new type
897 # ie the result share the same C variable but my have a different mcasttype
898 # NOTE: if the adaptation is useless then `value' is returned as it.
899 # ENSURE: return.name == value.name
900 fun autoadapt(value: RuntimeVariable, mtype: MType): RuntimeVariable
901 do
902 mtype = self.anchor(mtype)
903 var valmtype = value.mcasttype
904 if valmtype.is_subtype(self.compiler.mainmodule, null, mtype) then
905 return value
906 end
907
908 if valmtype isa MNullableType and valmtype.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then
909 var res = new RuntimeVariable(value.name, valmtype, valmtype.mtype)
910 return res
911 else
912 var res = new RuntimeVariable(value.name, valmtype, mtype)
913 return res
914 end
915 end
916
917 # Box or unbox a value to another type iff a C type conversion is needed
918 # ENSURE: result.mtype.ctype == mtype.ctype
919 fun autobox(value: RuntimeVariable, mtype: MType): RuntimeVariable
920 do
921 if value.mtype.ctype == mtype.ctype then
922 return value
923 else if value.mtype.ctype == "val*" then
924 return self.new_expr("((struct {mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
925 else if mtype.ctype == "val*" then
926 var valtype = value.mtype.as(MClassType)
927 var res = self.new_var(mtype)
928 if not compiler.runtime_type_analysis.live_types.has(valtype) then
929 self.add("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */")
930 self.add("printf(\"Dead code executed!\\n\"); exit(1);")
931 return res
932 end
933 self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
934 return res
935 else
936 # Bad things will appen!
937 var res = self.new_var(mtype)
938 self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */")
939 self.add("printf(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); exit(1);")
940 return res
941 end
942 end
943
944 # Correctly assign a left and a right value
945 # Boxing and unboxing is performed if required
946 fun assign(left, right: RuntimeVariable)
947 do
948 right = self.autobox(right, left.mtype)
949 self.add("{left} = {right};")
950 end
951
952
953 # Alias for `self.expr(nexpr, self.bool_type)'
954 fun expr_bool(nexpr: AExpr): RuntimeVariable
955 do
956 return expr(nexpr, bool_type)
957 end
958
959 # Compile a statement (if any)
960 fun stmt(nexpr: nullable AExpr)
961 do
962 if nexpr == null then return
963 var old = self.current_node
964 self.current_node = nexpr
965 nexpr.stmt(self)
966 self.current_node = old
967 end
968
969 # Safely show a debug message on the current node and repeat the message in the C code as a comment
970 fun debug(message: String)
971 do
972 var node = self.current_node
973 if node == null then
974 print "?: {message}"
975 else
976 node.debug(message)
977 end
978 self.add("/* DEBUG: {message} */")
979 end
980
981 # Return a new uninitialized local runtime_variable
982 fun new_var(mtype: MType): RuntimeVariable
983 do
984 mtype = self.anchor(mtype)
985 var name = self.get_name("var")
986 var res = new RuntimeVariable(name, mtype, mtype)
987 self.add_decl("{mtype.ctype} {name} /* : {mtype} */;")
988 return res
989 end
990
991 # Return a new uninitialized named runtime_variable
992 fun new_named_var(mtype: MType, name: String): RuntimeVariable
993 do
994 mtype = self.anchor(mtype)
995 var res = new RuntimeVariable(name, mtype, mtype)
996 self.add_decl("{mtype.ctype} {name} /* : {mtype} */;")
997 return res
998 end
999
1000 # Return a new local runtime_variable initialized with the C expression `cexpr'.
1001 fun new_expr(cexpr: String, mtype: MType): RuntimeVariable
1002 do
1003 var res = new_var(mtype)
1004 self.add("{res} = {cexpr};")
1005 return res
1006 end
1007
1008 # Return the local runtime_variable associated to a Nit local variable
1009 fun variable(variable: Variable): RuntimeVariable
1010 do
1011 if self.variables.has_key(variable) then
1012 return self.variables[variable]
1013 else
1014 var name = self.get_name("var_{variable.name}")
1015 var mtype = variable.declared_type.as(not null)
1016 mtype = self.anchor(mtype)
1017 var res = new RuntimeVariable(name, mtype, mtype)
1018 self.add_decl("{mtype.ctype} {name} /* var {variable}: {mtype} */;")
1019 self.variables[variable] = res
1020 return res
1021 end
1022 end
1023
1024 private var variables: HashMap[Variable, RuntimeVariable] = new HashMap[Variable, RuntimeVariable]
1025
1026 # Return an unique and stable identifier associated with an escapemark
1027 fun escapemark_name(e: nullable EscapeMark): String
1028 do
1029 assert e != null
1030 if escapemark_names.has_key(e) then return escapemark_names[e]
1031 var name = e.name
1032 if name == null then name = "label"
1033 name = get_name(name)
1034 escapemark_names[e] = name
1035 return name
1036 end
1037
1038 private var escapemark_names = new HashMap[EscapeMark, String]
1039
1040 # Return a new name based on `s' and unique in the visitor
1041 fun get_name(s: String): String
1042 do
1043 if not self.names.has(s) then
1044 self.names.add(s)
1045 return s
1046 end
1047 var i = self.last + 1
1048 loop
1049 var s2 = s + i.to_s
1050 if not self.names.has(s2) then
1051 self.last = i
1052 self.names.add(s2)
1053 return s2
1054 end
1055 i = i + 1
1056 end
1057 end
1058
1059 private var last: Int = 0
1060
1061 private var names: HashSet[String] = new HashSet[String]
1062
1063 # Generate a return with the value `s'
1064 fun ret(s: RuntimeVariable)
1065 do
1066 self.assign(self.frame.returnvar.as(not null), s)
1067 self.add("goto {self.frame.returnlabel.as(not null)};")
1068 end
1069
1070 # The runtime types that are acceptable for a given receiver.
1071 fun collect_types(recv: RuntimeVariable): Array[MClassType]
1072 do
1073 var mtype = recv.mcasttype
1074 if recv.is_exact then
1075 assert mtype isa MClassType
1076 assert self.compiler.runtime_type_analysis.live_types.has(mtype)
1077 var types = [mtype]
1078 return types
1079 end
1080 var cache = self.compiler.collect_types_cache
1081 if cache.has_key(mtype) then
1082 return cache[mtype]
1083 end
1084 var types = new Array[MClassType]
1085 var mainmodule = self.compiler.mainmodule
1086 for t in self.compiler.runtime_type_analysis.live_types do
1087 if not t.is_subtype(mainmodule, null, mtype) then continue
1088 types.add(t)
1089 end
1090 cache[mtype] = types
1091 return types
1092 end
1093
1094 fun resolve_for(mtype: MType, recv: RuntimeVariable): MType
1095 do
1096 if not mtype.need_anchor then return mtype
1097 #debug("resolve for {mtype} to {recv}:{recv.mcasttype}(declared as {recv.mtype}) (in {self.reciever.to_s}:{self.reciever.mtype})")
1098 var res = mtype.resolve_for(recv.mcasttype, self.frame.receiver, self.compiler.mainmodule, true)
1099 return res
1100 end
1101
1102 fun native_array_def(pname: String, ret_type: nullable MType, arguments: Array[RuntimeVariable])
1103 do
1104 var elttype = arguments.first.mtype
1105 var recv = "((struct {arguments[0].mcasttype.c_name}*){arguments[0]})->values"
1106 if pname == "[]" then
1107 self.ret(self.new_expr("{recv}[{arguments[1]}]", ret_type.as(not null)))
1108 return
1109 else if pname == "[]=" then
1110 self.add("{recv}[{arguments[1]}]={arguments[2]};")
1111 return
1112 else if pname == "copy_to" then
1113 var recv1 = "((struct {arguments[1].mcasttype.c_name}*){arguments[1]})->values"
1114 self.add("memcpy({recv1},{recv},{arguments[2]}*sizeof({elttype.ctype}));")
1115 return
1116 end
1117 end
1118
1119 fun calloc_array(ret_type: MType, arguments: Array[RuntimeVariable])
1120 do
1121 self.ret(self.new_expr("NEW_{ret_type.c_name}({arguments[1]})", ret_type))
1122 end
1123
1124 # Generate a polymorphic send for the method `m' and the arguments `args'
1125 fun send(m: MMethod, args: Array[RuntimeVariable]): nullable RuntimeVariable
1126 do
1127 var types = self.collect_types(args.first)
1128
1129 var res: nullable RuntimeVariable
1130 var ret = m.intro.msignature.return_mtype
1131 if m.is_new then
1132 ret = args.first.mtype
1133 res = self.new_var(ret)
1134 else if ret == null then
1135 res = null
1136 else
1137 ret = self.resolve_for(ret, args.first)
1138 res = self.new_var(ret)
1139 end
1140
1141 if types.is_empty then
1142 self.add("/*BUG: no live types for {args.first.inspect} . {m}*/")
1143 return res
1144 end
1145 self.add("/* send {m} on {args.first.inspect} */")
1146 if args.first.mtype.ctype != "val*" then
1147 var propdefs = m.lookup_definitions(self.compiler.mainmodule, args.first.mtype)
1148 if propdefs.length == 0 then
1149 self.add("/* skip, no method {m} */")
1150 return res
1151 end
1152 assert propdefs.length == 1
1153 var propdef = propdefs.first
1154 var res2 = self.call(propdef, args.first.mtype.as(MClassType), args)
1155 if res != null then self.assign(res, res2.as(not null))
1156 return res
1157 end
1158 if args.first.mcasttype isa MNullableType then
1159 # The reciever is potentially null, so we have to 3 cases: ==, != or NullPointerException
1160 self.add("if ({args.first} == NULL) \{ /* Special null case */")
1161 if m.name == "==" then
1162 assert res != null
1163 if args[1].mcasttype isa MNullableType then
1164 self.add("{res} = ({args[1]} == NULL);")
1165 else if args[1].mcasttype isa MNullType then
1166 self.add("{res} = 1; /* is null */")
1167 else
1168 self.add("{res} = 0; /* {args[1].inspect} cannot be null */")
1169 end
1170 else if m.name == "!=" then
1171 assert res != null
1172 if args[1].mcasttype isa MNullableType then
1173 self.add("{res} = ({args[1]} != NULL);")
1174 else if args[1].mcasttype isa MNullType then
1175 self.add("{res} = 0; /* is null */")
1176 else
1177 self.add("{res} = 1; /* {args[1].inspect} cannot be null */")
1178 end
1179 else
1180 self.add_abort("Reciever is null")
1181 end
1182 self.add "\} else"
1183 end
1184 self.add("switch({args.first}->classid) \{")
1185 var last = types.last
1186 var defaultpropdef: nullable MMethodDef = null
1187 for t in types do
1188 var propdefs = m.lookup_definitions(self.compiler.mainmodule, t)
1189 if propdefs.length == 0 then
1190 self.add("/* skip {t}, no method {m} */")
1191 continue
1192 end
1193 if propdefs.length > 1 then
1194 self.debug("NOT YET IMPLEMENTED conflict for {t}.{m}: {propdefs.join(" ")}. choose the first")
1195 end
1196 var propdef = propdefs.first
1197 if propdef.mclassdef.mclass.name == "Object" and t.ctype == "val*" then
1198 defaultpropdef = propdef
1199 continue
1200 end
1201 if not self.compiler.hardening and t == last and defaultpropdef == null then
1202 self.add("default: /* test {t} */")
1203 else
1204 self.add("case {self.compiler.classid(t)}: /* test {t} */")
1205 end
1206 var res2 = self.call(propdef, t, args)
1207 if res != null then self.assign(res, res2.as(not null))
1208 self.add "break;"
1209 end
1210 if defaultpropdef != null then
1211 self.add("default: /* default is Object */")
1212 var res2 = self.call(defaultpropdef, defaultpropdef.mclassdef.bound_mtype, args)
1213 if res != null then self.assign(res, res2.as(not null))
1214 else if self.compiler.hardening then
1215 self.add("default: /* bug */")
1216 self.bugtype(args.first)
1217 end
1218 self.add("\}")
1219 return res
1220 end
1221
1222 # Generate a monomorphic send for the method `m', the type `t' and the arguments `args'
1223 fun monomorphic_send(m: MMethod, t: MType, args: Array[RuntimeVariable]): nullable RuntimeVariable
1224 do
1225 assert t isa MClassType
1226 var propdefs = m.lookup_definitions(self.compiler.mainmodule, t)
1227 if propdefs.length == 0 then
1228 abort
1229 end
1230 if propdefs.length > 1 then
1231 self.debug("NOT YET IMPLEMENTED conflict for {t}.{m}: {propdefs.join(" ")}. choose the first")
1232 end
1233 var propdef = propdefs.first
1234 return self.call(propdef, t, args)
1235 end
1236
1237 fun check_valid_reciever(recvtype: MClassType)
1238 do
1239 if self.compiler.runtime_type_analysis.live_types.has(recvtype) or recvtype.mclass.name == "Object" then return
1240 print "{recvtype} is not a live type"
1241 abort
1242 end
1243
1244 # Generate a static call on a method definition
1245 fun call(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable
1246 do
1247 check_valid_reciever(recvtype)
1248 #debug("call {m} on {recvtype} on {args.first}:{args.first.mtype}")
1249 if m.mclassdef.mclass.name == "Object" and recvtype.ctype == "val*" then
1250 recvtype = m.mclassdef.bound_mtype
1251 end
1252 var recv = self.autobox(args.first, recvtype)
1253 recv = self.autoadapt(recv, recvtype)
1254
1255 args = args.to_a
1256 self.varargize(m.msignature.as(not null), args)
1257 if args.length != m.msignature.arity + 1 then # because of self
1258 add("printf(\"NOT YET IMPLEMENTED: Invalid arity for {m}. {args.length} arguments given.\\n\"); exit(1);")
1259 debug("NOT YET IMPLEMENTED: Invalid arity for {m}. {args.length} arguments given.")
1260 return null
1261 end
1262
1263 args.first = recv
1264 var rm = new CustomizedRuntimeFunction(m, recvtype)
1265 return rm.call(self, args)
1266 end
1267
1268 fun adapt_signature(m: MMethodDef, args: Array[RuntimeVariable])
1269 do
1270 var recv = args.first
1271 for i in [0..m.msignature.arity[ do
1272 var t = m.msignature.mparameters[i].mtype
1273 if i == m.msignature.vararg_rank then
1274 t = args[i+1].mtype
1275 end
1276 t = self.resolve_for(t, recv)
1277 args[i+1] = self.autobox(args[i+1], t)
1278 end
1279 end
1280
1281 # Transform varargs, in raw arguments, into a single argument of type Array
1282 # Note: this method modify the given `args`
1283 # If there is no vararg, then `args` is not modified.
1284 fun varargize(msignature: MSignature, args: Array[RuntimeVariable])
1285 do
1286 var recv = args.first
1287 var vararg_rank = msignature.vararg_rank
1288 if vararg_rank >= 0 then
1289 assert args.length >= msignature.arity + 1 # because of self
1290 var rawargs = args
1291 args = new Array[RuntimeVariable]
1292
1293 args.add(rawargs.first) # recv
1294
1295 for i in [0..vararg_rank[ do
1296 args.add(rawargs[i+1])
1297 end
1298
1299 var vararg_lastrank = vararg_rank + rawargs.length-1-msignature.arity
1300 var vararg = new Array[RuntimeVariable]
1301 for i in [vararg_rank..vararg_lastrank] do
1302 vararg.add(rawargs[i+1])
1303 end
1304 # FIXME: its it to late to determine the vararg type, this should have been done during a previous analysis
1305 var elttype = msignature.mparameters[vararg_rank].mtype
1306 elttype = self.resolve_for(elttype, recv)
1307 args.add(self.array_instance(vararg, elttype))
1308
1309 for i in [vararg_lastrank+1..rawargs.length-1[ do
1310 args.add(rawargs[i+1])
1311 end
1312 rawargs.clear
1313 rawargs.add_all(args)
1314 end
1315 end
1316
1317 fun bugtype(recv: RuntimeVariable)
1318 do
1319 if recv.mtype.ctype != "val*" then return
1320 self.add("fprintf(stderr, \"BTD BUG: Dynamic type is %s, static type is %s\\n\", class_names[{recv}->classid], \"{recv.mcasttype}\");")
1321 end
1322
1323 # Generate a polymorphic attribute is_set test
1324 fun isset_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable
1325 do
1326 var types = self.collect_types(recv)
1327
1328 var res = self.new_var(bool_type)
1329
1330 if types.is_empty then
1331 self.add("/*BUG: no live types for {recv.inspect} . {a}*/")
1332 return res
1333 end
1334 self.add("/* isset {a} on {recv.inspect} */")
1335 self.add("switch({recv}->classid) \{")
1336 var last = types.last
1337 for t in types do
1338 if not self.compiler.hardening and t == last then
1339 self.add("default: /*{self.compiler.classid(t)}*/")
1340 else
1341 self.add("case {self.compiler.classid(t)}:")
1342 end
1343 var recv2 = self.autoadapt(recv, t)
1344 var ta = a.intro.static_mtype.as(not null)
1345 ta = self.resolve_for(ta, recv2)
1346 var attr = self.new_expr("((struct {t.c_name}*){recv})->{a.intro.c_name}", ta)
1347 if not ta isa MNullableType then
1348 if ta.ctype == "val*" then
1349 self.add("{res} = ({attr} != NULL);")
1350 else
1351 self.add("{res} = 1; /*NOTYET isset on primitive attributes*/")
1352 end
1353 end
1354 self.add("break;")
1355 end
1356 if self.compiler.hardening then
1357 self.add("default: /* Bug */")
1358 self.bugtype(recv)
1359 end
1360 self.add("\}")
1361
1362 return res
1363 end
1364
1365 # Generate a polymorphic attribute read
1366 fun read_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable
1367 do
1368 var types = self.collect_types(recv)
1369
1370 var ret = a.intro.static_mtype.as(not null)
1371 ret = self.resolve_for(ret, recv)
1372 var res = self.new_var(ret)
1373
1374 if types.is_empty then
1375 self.add("/*BUG: no live types for {recv.inspect} . {a}*/")
1376 return res
1377 end
1378 self.add("/* read {a} on {recv.inspect} */")
1379 self.add("switch({recv}->classid) \{")
1380 var last = types.last
1381 for t in types do
1382 if not self.compiler.hardening and t == last then
1383 self.add("default: /*{self.compiler.classid(t)}*/")
1384 else
1385 self.add("case {self.compiler.classid(t)}:")
1386 end
1387 var recv2 = self.autoadapt(recv, t)
1388 var ta = a.intro.static_mtype.as(not null)
1389 ta = self.resolve_for(ta, recv2)
1390 var res2 = self.new_expr("((struct {t.c_name}*){recv})->{a.intro.c_name}", ta)
1391 if not ta isa MNullableType then
1392 if ta.ctype == "val*" then
1393 self.add("if ({res2} == NULL) \{")
1394 self.add_abort("Uninitialized attribute {a.name}")
1395 self.add("\}")
1396 else
1397 self.add("/*NOTYET isset on primitive attributes*/")
1398 end
1399 end
1400 self.assign(res, res2)
1401 self.add("break;")
1402 end
1403 if self.compiler.hardening then
1404 self.add("default: /* Bug */")
1405 self.bugtype(recv)
1406 end
1407 self.add("\}")
1408
1409 return res
1410 end
1411
1412 # Generate a polymorphic attribute write
1413 fun write_attribute(a: MAttribute, recv: RuntimeVariable, value: RuntimeVariable)
1414 do
1415 var types = self.collect_types(recv)
1416
1417 if types.is_empty then
1418 self.add("/*BUG: no live types for {recv.inspect} . {a}*/")
1419 return
1420 end
1421 self.add("/* write {a} on {recv.inspect} */")
1422 self.add("switch({recv}->classid) \{")
1423 var last = types.last
1424 for t in types do
1425 if not self.compiler.hardening and t == last then
1426 self.add("default: /*{self.compiler.classid(t)}*/")
1427 else
1428 self.add("case {self.compiler.classid(t)}:")
1429 end
1430 var recv2 = self.autoadapt(recv, t)
1431 var ta = a.intro.static_mtype.as(not null)
1432 ta = self.resolve_for(ta, recv2)
1433 self.add("((struct {t.c_name}*){recv})->{a.intro.c_name} = {self.autobox(value, ta)};")
1434 self.add("break;")
1435 end
1436 if self.compiler.hardening then
1437 self.add("default: /* Bug*/")
1438 self.bugtype(recv)
1439 end
1440 self.add("\}")
1441 end
1442
1443 # Generate a alloc-instance + init-attributes
1444 fun init_instance(mtype: MClassType): RuntimeVariable
1445 do
1446 mtype = self.anchor(mtype).as(MClassType)
1447 if not self.compiler.runtime_type_analysis.live_types.has(mtype) then
1448 debug "problem: {mtype} was detected dead"
1449 end
1450 var res = self.new_expr("NEW_{mtype.c_name}()", mtype)
1451 res.is_exact = true
1452 return res
1453 end
1454
1455 # Generate a polymorphic subtype test
1456 fun type_test(value: RuntimeVariable, mtype: MType): RuntimeVariable
1457 do
1458 mtype = self.anchor(mtype)
1459 var mclasstype = mtype
1460 if mtype isa MNullableType then mclasstype = mtype.mtype
1461 assert mclasstype isa MClassType
1462 if not self.compiler.runtime_type_analysis.live_cast_types.has(mclasstype) then
1463 debug "problem: {mtype} was detected cast-dead"
1464 abort
1465 end
1466
1467 var types = self.collect_types(value)
1468
1469 var res = self.new_var(bool_type)
1470
1471 self.add("/* isa {mtype} on {value.inspect} */")
1472 if value.mtype.ctype != "val*" then
1473 if value.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then
1474 self.add("{res} = 1;")
1475 else
1476 self.add("{res} = 0;")
1477 end
1478 return res
1479 end
1480 if value.mcasttype isa MNullableType then
1481 self.add("if ({value} == NULL) \{")
1482 if mtype isa MNullableType then
1483 self.add("{res} = 1; /* isa {mtype} */")
1484 else
1485 self.add("{res} = 0; /* not isa {mtype} */")
1486 end
1487 self.add("\} else ")
1488 end
1489 self.add("switch({value}->classid) \{")
1490 for t in types do
1491 if t.is_subtype(self.compiler.mainmodule, null, mtype) then
1492 self.add("case {self.compiler.classid(t)}: /* {t} */")
1493 end
1494 end
1495 self.add("{res} = 1;")
1496 self.add("break;")
1497 self.add("default:")
1498 self.add("{res} = 0;")
1499 self.add("\}")
1500
1501 return res
1502 end
1503
1504 # Generate the code required to dynamically check if 2 objects share the same runtime type
1505 fun is_same_type_test(value1, value2: RuntimeVariable): RuntimeVariable
1506 do
1507 var res = self.new_var(bool_type)
1508 if value2.mtype.ctype == "val*" then
1509 if value1.mtype.ctype == "val*" then
1510 self.add "{res} = {value1}->classid == {value2}->classid;"
1511 else
1512 self.add "{res} = {self.compiler.classid(value1.mtype.as(MClassType))} == {value2}->classid;"
1513 end
1514 else
1515 if value1.mtype.ctype == "val*" then
1516 self.add "{res} = {value1}->classid == {self.compiler.classid(value2.mtype.as(MClassType))};"
1517 else if value1.mcasttype == value2.mcasttype then
1518 self.add "{res} = 1;"
1519 else
1520 self.add "{res} = 0;"
1521 end
1522 end
1523 return res
1524 end
1525
1526 # Return a "const char*" variable associated to the classname of the dynamic type of an object
1527 # NOTE: we do not return a RuntimeVariable "NativeString" as the class may not exist in the module/program
1528 fun class_name_string(value: RuntimeVariable): String
1529 do
1530 var res = self.get_name("var_class_name")
1531 self.add_decl("const char* {res};")
1532 if value.mtype.ctype == "val*" then
1533 self.add "{res} = class_names[{value}->classid];"
1534 else
1535 self.add "{res} = class_names[{self.compiler.classid(value.mtype.as(MClassType))}];"
1536 end
1537 return res
1538 end
1539
1540 # Generate a Nit "is" for two runtime_variables
1541 fun equal_test(value1, value2: RuntimeVariable): RuntimeVariable
1542 do
1543 var res = self.new_var(bool_type)
1544 if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
1545 var tmp = value1
1546 value1 = value2
1547 value2 = tmp
1548 end
1549 if value1.mtype.ctype != "val*" then
1550 if value2.mtype.ctype == value1.mtype.ctype then
1551 self.add("{res} = {value1} == {value2};")
1552 else if value2.mtype.ctype != "val*" then
1553 self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
1554 else
1555 var mtype1 = value1.mtype.as(MClassType)
1556 self.add("{res} = ({value2} != NULL) && ({value2}->classid == {self.compiler.classid(mtype1)});")
1557 self.add("if ({res}) \{")
1558 self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
1559 self.add("\}")
1560 end
1561 else
1562 var s = new Array[String]
1563 for t in self.compiler.live_primitive_types do
1564 if not t.is_subtype(self.compiler.mainmodule, null, value1.mcasttype) then continue
1565 if not t.is_subtype(self.compiler.mainmodule, null, value2.mcasttype) then continue
1566 s.add "({value1}->classid == {self.compiler.classid(t)} && ((struct {t.c_name}*){value1})->value == ((struct {t.c_name}*){value2})->value)"
1567 end
1568 if s.is_empty then
1569 self.add("{res} = {value1} == {value2};")
1570 else
1571 self.add("{res} = {value1} == {value2} || ({value1} != NULL && {value2} != NULL && {value1}->classid == {value2}->classid && ({s.join(" || ")}));")
1572 end
1573 end
1574 return res
1575 end
1576
1577 # Generate a check-init-instance
1578 fun check_init_instance(recv: RuntimeVariable)
1579 do
1580 var mtype = self.anchor(recv.mcasttype)
1581 for cd in mtype.collect_mclassdefs(self.compiler.mainmodule)
1582 do
1583 var n = self.compiler.modelbuilder.mclassdef2nclassdef[cd]
1584 for npropdef in n.n_propdefs do
1585 if npropdef isa AAttrPropdef then
1586 # Force read to check the initialization
1587 self.read_attribute(npropdef.mpropdef.mproperty, recv)
1588 end
1589 end
1590 end
1591 end
1592
1593 # Generate an integer value
1594 fun int_instance(value: Int): RuntimeVariable
1595 do
1596 var res = self.new_var(self.get_class("Int").mclass_type)
1597 self.add("{res} = {value};")
1598 return res
1599 end
1600
1601 # Generate an array value
1602 fun array_instance(array: Array[RuntimeVariable], elttype: MType): RuntimeVariable
1603 do
1604 elttype = self.anchor(elttype)
1605 var arraytype = self.get_class("Array").get_mtype([elttype])
1606 var res = self.init_instance(arraytype)
1607 self.add("\{ /* {res} = array_instance Array[{elttype}] */")
1608 var nat = self.new_var(self.get_class("NativeArray").get_mtype([elttype]))
1609 nat.is_exact = true
1610 self.add("{nat} = NEW_{nat.mtype.c_name}({array.length});")
1611 for i in [0..array.length[ do
1612 var r = self.autobox(array[i], elttype)
1613 self.add("((struct {nat.mtype.c_name}*) {nat})->values[{i}] = {r};")
1614 end
1615 var length = self.int_instance(array.length)
1616 self.send(self.get_property("with_native", arraytype), [res, nat, length])
1617 self.check_init_instance(res)
1618 self.add("\}")
1619 return res
1620 end
1621
1622 # Generate a string value
1623 fun string_instance(string: String): RuntimeVariable
1624 do
1625 var mtype = self.get_class("String").mclass_type
1626 var name = self.get_name("varonce")
1627 self.add_decl("static {mtype.ctype} {name};")
1628 var res = self.new_var(mtype)
1629 self.add("if ({name}) \{")
1630 self.add("{res} = {name};")
1631 self.add("\} else \{")
1632 var nat = self.new_var(self.get_class("NativeString").mclass_type)
1633 self.add("{nat} = \"{string.escape_to_c}\";")
1634 var res2 = self.init_instance(mtype)
1635 self.add("{res} = {res2};")
1636 var length = self.int_instance(string.length)
1637 self.send(self.get_property("with_native", mtype), [res, nat, length])
1638 self.check_init_instance(res)
1639 self.add("{name} = {res};")
1640 self.add("\}")
1641 return res
1642 end
1643
1644 # Generate generic abort
1645 # used by aborts, asserts, casts, etc.
1646 fun add_abort(message: String)
1647 do
1648 if self.current_node != null and self.current_node.location.file != null then
1649 self.add("fprintf(stderr, \"Runtime error: %s (%s:%d)\\n\", \"{message.escape_to_c}\", \"{self.current_node.location.file.filename.escape_to_c}\", {current_node.location.line_start});")
1650 else
1651 self.add("fprintf(stderr, \"Runtime error: %s\\n\", \"{message.escape_to_c}\");")
1652 end
1653 self.add("exit(1);")
1654 end
1655 end
1656
1657 # A frame correspond to a visited property in a GlobalCompilerVisitor
1658 class Frame
1659 # The associated visitor
1660
1661 var visitor: GlobalCompilerVisitor
1662
1663 # The executed property.
1664 # A Method in case of a call, an attribute in case of a default initialization.
1665 var mpropdef: MPropDef
1666
1667 # The static type of the receiver
1668 var receiver: MClassType
1669
1670 # Arguments of the method (the first is the receiver)
1671 var arguments: Array[RuntimeVariable]
1672
1673 # The runtime_variable associated to the return (in a function)
1674 var returnvar: nullable RuntimeVariable writable = null
1675
1676 # The label at the end of the property
1677 var returnlabel: nullable String writable = null
1678 end
1679
1680 redef class MPropDef
1681 private var c_name_cache: nullable String
1682
1683 # The mangled name associated to the property
1684 fun c_name: String
1685 do
1686 var res = self.c_name_cache
1687 if res != null then return res
1688 res = "{self.mclassdef.mmodule.name.to_cmangle}__{self.mclassdef.mclass.name.to_cmangle}__{self.mproperty.name.to_cmangle}"
1689 self.c_name_cache = res
1690 return res
1691 end
1692 end
1693
1694 redef class MMethodDef
1695 # Can the body be inlined?
1696 fun can_inline(v: GlobalCompilerVisitor): Bool
1697 do
1698 var modelbuilder = v.compiler.modelbuilder
1699 if modelbuilder.mpropdef2npropdef.has_key(self) then
1700 var npropdef = modelbuilder.mpropdef2npropdef[self]
1701 return npropdef.can_inline
1702 else if self.mproperty.name == "init" then
1703 # Automatic free init is always inlined since it is empty or contains only attribtes assigments
1704 return true
1705 else
1706 abort
1707 end
1708 end
1709
1710 # Inline the body in another visitor
1711 fun compile_inside_to_c(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
1712 do
1713 var modelbuilder = v.compiler.modelbuilder
1714 if modelbuilder.mpropdef2npropdef.has_key(self) then
1715 var npropdef = modelbuilder.mpropdef2npropdef[self]
1716 var oldnode = v.current_node
1717 v.current_node = npropdef
1718 npropdef.compile_to_c(v, self, arguments)
1719 v.current_node = oldnode
1720 else if self.mproperty.name == "init" then
1721 var nclassdef = modelbuilder.mclassdef2nclassdef[self.mclassdef]
1722 var oldnode = v.current_node
1723 v.current_node = nclassdef
1724 nclassdef.compile_to_c(v, self, arguments)
1725 v.current_node = oldnode
1726 else
1727 abort
1728 end
1729 return null
1730 end
1731 end
1732
1733 redef class APropdef
1734 fun compile_to_c(v: GlobalCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
1735 do
1736 v.add("printf(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");")
1737 debug("Not yet implemented")
1738 end
1739
1740 fun can_inline: Bool do return true
1741 end
1742
1743 redef class AConcreteMethPropdef
1744 redef fun compile_to_c(v, mpropdef, arguments)
1745 do
1746 for i in [0..mpropdef.msignature.arity[ do
1747 var variable = self.n_signature.n_params[i].variable.as(not null)
1748 v.assign(v.variable(variable), arguments[i+1])
1749 end
1750 # Call the implicit super-init
1751 var auto_super_inits = self.auto_super_inits
1752 if auto_super_inits != null then
1753 var selfarg = [arguments.first]
1754 for auto_super_init in auto_super_inits do
1755 if auto_super_init.intro.msignature.arity == 0 then
1756 v.send(auto_super_init, selfarg)
1757 else
1758 v.send(auto_super_init, arguments)
1759 end
1760 end
1761 end
1762 v.stmt(self.n_block)
1763 end
1764
1765 redef fun can_inline
1766 do
1767 if self.auto_super_inits != null then return false
1768 var nblock = self.n_block
1769 if nblock == null then return true
1770 if (mpropdef.mproperty.name == "==" or mpropdef.mproperty.name == "!=") and mpropdef.mclassdef.mclass.name == "Object" then return true
1771 if nblock isa ABlockExpr and nblock.n_expr.length == 0 then return true
1772 return false
1773 end
1774 end
1775
1776 redef class AInternMethPropdef
1777 redef fun compile_to_c(v, mpropdef, arguments)
1778 do
1779 var pname = mpropdef.mproperty.name
1780 var cname = mpropdef.mclassdef.mclass.name
1781 var ret = mpropdef.msignature.return_mtype
1782 if ret != null then
1783 ret = v.resolve_for(ret, arguments.first)
1784 end
1785 if pname != "==" and pname != "!=" then
1786 v.adapt_signature(mpropdef, arguments)
1787 end
1788 if cname == "Int" then
1789 if pname == "output" then
1790 v.add("printf(\"%ld\\n\", {arguments.first});")
1791 return
1792 else if pname == "object_id" then
1793 v.ret(arguments.first)
1794 return
1795 else if pname == "+" then
1796 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1797 return
1798 else if pname == "-" then
1799 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1800 return
1801 else if pname == "unary -" then
1802 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
1803 return
1804 else if pname == "succ" then
1805 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
1806 return
1807 else if pname == "prec" then
1808 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
1809 return
1810 else if pname == "*" then
1811 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
1812 return
1813 else if pname == "/" then
1814 v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
1815 return
1816 else if pname == "%" then
1817 v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null)))
1818 return
1819 else if pname == "lshift" then
1820 v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null)))
1821 return
1822 else if pname == "rshift" then
1823 v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null)))
1824 return
1825 else if pname == "==" then
1826 v.ret(v.equal_test(arguments[0], arguments[1]))
1827 return
1828 else if pname == "!=" then
1829 var res = v.equal_test(arguments[0], arguments[1])
1830 v.ret(v.new_expr("!{res}", ret.as(not null)))
1831 return
1832 else if pname == "<" then
1833 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1834 return
1835 else if pname == ">" then
1836 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1837 return
1838 else if pname == "<=" then
1839 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1840 return
1841 else if pname == ">=" then
1842 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1843 return
1844 else if pname == "to_f" then
1845 v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
1846 return
1847 else if pname == "ascii" then
1848 v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
1849 return
1850 end
1851 else if cname == "Char" then
1852 if pname == "output" then
1853 v.add("printf(\"%c\", {arguments.first});")
1854 return
1855 else if pname == "object_id" then
1856 v.ret(arguments.first)
1857 return
1858 else if pname == "+" then
1859 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1860 return
1861 else if pname == "-" then
1862 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1863 return
1864 else if pname == "==" then
1865 v.ret(v.equal_test(arguments[0], arguments[1]))
1866 return
1867 else if pname == "!=" then
1868 var res = v.equal_test(arguments[0], arguments[1])
1869 v.ret(v.new_expr("!{res}", ret.as(not null)))
1870 return
1871 else if pname == "succ" then
1872 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
1873 return
1874 else if pname == "prec" then
1875 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
1876 return
1877 else if pname == "<" then
1878 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1879 return
1880 else if pname == ">" then
1881 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1882 return
1883 else if pname == "<=" then
1884 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1885 return
1886 else if pname == ">=" then
1887 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1888 return
1889 else if pname == "to_i" then
1890 v.ret(v.new_expr("{arguments[0]}-'0'", ret.as(not null)))
1891 return
1892 else if pname == "ascii" then
1893 v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
1894 return
1895 end
1896 else if cname == "Bool" then
1897 if pname == "output" then
1898 v.add("printf({arguments.first}?\"true\\n\":\"false\\n\");")
1899 return
1900 else if pname == "object_id" then
1901 v.ret(arguments.first)
1902 return
1903 else if pname == "==" then
1904 v.ret(v.equal_test(arguments[0], arguments[1]))
1905 return
1906 else if pname == "!=" then
1907 var res = v.equal_test(arguments[0], arguments[1])
1908 v.ret(v.new_expr("!{res}", ret.as(not null)))
1909 return
1910 end
1911 else if cname == "Float" then
1912 if pname == "output" then
1913 v.add("printf(\"%f\\n\", {arguments.first});")
1914 return
1915 else if pname == "object_id" then
1916 v.ret(v.new_expr("(double){arguments.first}", ret.as(not null)))
1917 return
1918 else if pname == "+" then
1919 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1920 return
1921 else if pname == "-" then
1922 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1923 return
1924 else if pname == "unary -" then
1925 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
1926 return
1927 else if pname == "succ" then
1928 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
1929 return
1930 else if pname == "prec" then
1931 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
1932 return
1933 else if pname == "*" then
1934 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
1935 return
1936 else if pname == "/" then
1937 v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
1938 return
1939 else if pname == "==" then
1940 v.ret(v.equal_test(arguments[0], arguments[1]))
1941 return
1942 else if pname == "!=" then
1943 var res = v.equal_test(arguments[0], arguments[1])
1944 v.ret(v.new_expr("!{res}", ret.as(not null)))
1945 return
1946 else if pname == "<" then
1947 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1948 return
1949 else if pname == ">" then
1950 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1951 return
1952 else if pname == "<=" then
1953 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1954 return
1955 else if pname == ">=" then
1956 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1957 return
1958 else if pname == "to_i" then
1959 v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
1960 return
1961 end
1962 else if cname == "Char" then
1963 if pname == "output" then
1964 v.add("printf(\"%c\", {arguments.first});")
1965 return
1966 else if pname == "object_id" then
1967 v.ret(arguments.first)
1968 return
1969 else if pname == "==" then
1970 v.ret(v.equal_test(arguments[0], arguments[1]))
1971 return
1972 else if pname == "!=" then
1973 var res = v.equal_test(arguments[0], arguments[1])
1974 v.ret(v.new_expr("!{res}", ret.as(not null)))
1975 return
1976 else if pname == "ascii" then
1977 v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
1978 return
1979 end
1980 else if cname == "NativeString" then
1981 if pname == "[]" then
1982 v.ret(v.new_expr("{arguments[0]}[{arguments[1]}]", ret.as(not null)))
1983 return
1984 else if pname == "[]=" then
1985 v.add("{arguments[0]}[{arguments[1]}]={arguments[2]};")
1986 return
1987 else if pname == "copy_to" then
1988 v.add("memcpy({arguments[1]}+{arguments[4]},{arguments[0]}+{arguments[3]},{arguments[2]});")
1989 return
1990 else if pname == "atoi" then
1991 v.ret(v.new_expr("atoi({arguments[0]});", ret.as(not null)))
1992 return
1993 end
1994 else if cname == "NativeArray" then
1995 v.native_array_def(pname, ret, arguments)
1996 return
1997 end
1998 if pname == "exit" then
1999 v.add("exit({arguments[1]});")
2000 return
2001 else if pname == "sys" then
2002 v.ret(v.new_expr("glob_sys", ret.as(not null)))
2003 return
2004 else if pname == "calloc_string" then
2005 v.ret(v.new_expr("(char*)GC_MALLOC({arguments[1]})", ret.as(not null)))
2006 return
2007 else if pname == "calloc_array" then
2008 v.calloc_array(ret.as(not null), arguments)
2009 return
2010 else if pname == "object_id" then
2011 v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
2012 return
2013 else if pname == "is_same_type" then
2014 v.ret(v.is_same_type_test(arguments[0], arguments[1]))
2015 return
2016 else if pname == "output_class_name" then
2017 var nat = v.class_name_string(arguments.first)
2018 v.add("printf(\"%s\\n\", {nat});")
2019 return
2020 else if pname == "native_class_name" then
2021 var nat = v.class_name_string(arguments.first)
2022 v.ret(v.new_expr("(char*){nat}", ret.as(not null)))
2023 return
2024 end
2025 v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{mpropdef} at {location.to_s}\\n\");")
2026 debug("Not implemented {mpropdef}")
2027 end
2028 end
2029
2030 redef class AExternMethPropdef
2031 redef fun compile_to_c(v, mpropdef, arguments)
2032 do
2033 var externname
2034 var nextern = self.n_extern
2035 if nextern == null then
2036 debug("{mpropdef} need extern name")
2037 return
2038 end
2039 externname = nextern.text.substring(1, nextern.text.length-2)
2040 if location.file != null then
2041 var file = location.file.filename
2042 v.compiler.add_extern(file)
2043 end
2044 var res: nullable RuntimeVariable = null
2045 var ret = mpropdef.msignature.return_mtype
2046 if ret != null then
2047 ret = v.resolve_for(ret, arguments.first)
2048 res = v.new_var(ret)
2049 end
2050 v.adapt_signature(mpropdef, arguments)
2051
2052 if res == null then
2053 v.add("{externname}({arguments.join(", ")});")
2054 else
2055 v.add("{res} = {externname}({arguments.join(", ")});")
2056 v.ret(res)
2057 end
2058 end
2059 end
2060
2061 redef class AExternInitPropdef
2062 redef fun compile_to_c(v, mpropdef, arguments)
2063 do
2064 var externname
2065 var nextern = self.n_extern
2066 if nextern == null then
2067 debug("{mpropdef} need extern name")
2068 return
2069 end
2070 externname = nextern.text.substring(1, nextern.text.length-2)
2071 if location.file != null then
2072 var file = location.file.filename
2073 v.compiler.add_extern(file)
2074 end
2075 v.adapt_signature(mpropdef, arguments)
2076 var ret = arguments.first.mtype
2077 var res = v.new_var(ret)
2078
2079 arguments.shift
2080
2081 v.add("{res} = {externname}({arguments.join(", ")});")
2082 v.ret(res)
2083 end
2084 end
2085
2086 redef class AAttrPropdef
2087 redef fun compile_to_c(v, mpropdef, arguments)
2088 do
2089 if arguments.length == 1 then
2090 var res = v.read_attribute(self.mpropdef.mproperty, arguments.first)
2091 v.assign(v.frame.returnvar.as(not null), res)
2092 else
2093 v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1])
2094 end
2095 end
2096
2097 fun init_expr(v: GlobalCompilerVisitor, recv: RuntimeVariable)
2098 do
2099 var nexpr = self.n_expr
2100 if nexpr != null then
2101 var old_frame = v.frame
2102 var frame = new Frame(v, self.mpropdef.as(not null), recv.mtype.as(MClassType), [recv])
2103 v.frame = frame
2104 var value = v.expr(nexpr, self.mpropdef.static_mtype)
2105 v.write_attribute(self.mpropdef.mproperty, recv, value)
2106 v.frame = old_frame
2107 end
2108 end
2109 end
2110
2111 redef class AClassdef
2112 private fun compile_to_c(v: GlobalCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
2113 do
2114 if mpropdef == self.mfree_init then
2115 var super_inits = self.super_inits
2116 if super_inits != null then
2117 assert arguments.length == 1
2118 for su in super_inits do
2119 v.send(su, arguments)
2120 end
2121 return
2122 end
2123 var recv = arguments.first
2124 var i = 1
2125 # Collect undefined attributes
2126 for npropdef in self.n_propdefs do
2127 if npropdef isa AAttrPropdef and npropdef.n_expr == null then
2128 v.write_attribute(npropdef.mpropdef.mproperty, recv, arguments[i])
2129 i += 1
2130 end
2131 end
2132 else
2133 abort
2134 end
2135 end
2136 end
2137
2138 redef class ADeferredMethPropdef
2139 redef fun compile_to_c(v, mpropdef, arguments)
2140 do
2141 v.add("printf(\"Not implemented {class_name} {mpropdef} at {location.to_s}\\n\");")
2142 v.add("exit(1);")
2143 end
2144
2145 redef fun can_inline do return true
2146 end
2147
2148 redef class AExpr
2149 # Try to compile self as an expression
2150 # Do not call this method directly, use `v.expr' instead
2151 private fun expr(v: GlobalCompilerVisitor): nullable RuntimeVariable
2152 do
2153 debug("Unimplemented expr {class_name}")
2154 v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{location.to_s}\\n\");")
2155 var mtype = self.mtype
2156 if mtype == null then
2157 return null
2158 else
2159 var res = v.new_var(mtype)
2160 v.add("/* {res} = NOT YET {class_name} */")
2161 return res
2162 end
2163 end
2164
2165 # Try to compile self as a statement
2166 # Do not call this method directly, use `v.stmt' instead
2167 private fun stmt(v: GlobalCompilerVisitor)
2168 do
2169 var res = expr(v)
2170 if res != null then v.add("{res};")
2171 end
2172
2173 end
2174
2175 redef class ABlockExpr
2176 redef fun stmt(v)
2177 do
2178 for e in self.n_expr do
2179 v.stmt(e)
2180 end
2181 end
2182 end
2183
2184 redef class AVardeclExpr
2185 redef fun stmt(v)
2186 do
2187 var variable = self.variable.as(not null)
2188 var ne = self.n_expr
2189 if ne != null then
2190 var i = v.expr(ne, variable.declared_type)
2191 v.assign(v.variable(variable), i)
2192 end
2193 end
2194 end
2195
2196 redef class AVarExpr
2197 redef fun expr(v)
2198 do
2199 var res = v.variable(self.variable.as(not null))
2200 var mtype = self.mtype.as(not null)
2201 return v.autoadapt(res, mtype)
2202 end
2203 end
2204
2205 redef class AVarAssignExpr
2206 redef fun stmt(v)
2207 do
2208 var variable = self.variable.as(not null)
2209 var i = v.expr(self.n_value, variable.declared_type)
2210 v.assign(v.variable(variable), i)
2211 end
2212 end
2213
2214 redef class AVarReassignExpr
2215 redef fun stmt(v)
2216 do
2217 var variable = self.variable.as(not null)
2218 var vari = v.variable(variable)
2219 var value = v.expr(self.n_value, variable.declared_type)
2220 var res = v.send(reassign_property.mproperty, [vari, value])
2221 assert res != null
2222 v.assign(v.variable(variable), res)
2223 end
2224 end
2225
2226 redef class ASelfExpr
2227 redef fun expr(v)
2228 do
2229 return v.frame.arguments.first
2230 end
2231 end
2232
2233 redef class AContinueExpr
2234 redef fun stmt(v)
2235 do
2236 v.add("goto CONTINUE_{v.escapemark_name(self.escapemark)};")
2237 end
2238 end
2239
2240 redef class ABreakExpr
2241 redef fun stmt(v)
2242 do
2243 v.add("goto BREAK_{v.escapemark_name(self.escapemark)};")
2244 end
2245 end
2246
2247 redef class AReturnExpr
2248 redef fun stmt(v)
2249 do
2250 var nexpr = self.n_expr
2251 if nexpr != null then
2252 var returnvar = v.frame.returnvar.as(not null)
2253 var i = v.expr(nexpr, returnvar.mtype)
2254 v.assign(returnvar, i)
2255 end
2256 v.add("goto {v.frame.returnlabel.as(not null)};")
2257 end
2258 end
2259
2260 redef class AAbortExpr
2261 redef fun stmt(v)
2262 do
2263 v.add_abort("Aborted")
2264 end
2265 end
2266
2267 redef class AIfExpr
2268 redef fun stmt(v)
2269 do
2270 var cond = v.expr_bool(self.n_expr)
2271 v.add("if ({cond})\{")
2272 v.stmt(self.n_then)
2273 v.add("\} else \{")
2274 v.stmt(self.n_else)
2275 v.add("\}")
2276 end
2277 end
2278
2279 redef class AIfexprExpr
2280 redef fun expr(v)
2281 do
2282 var res = v.new_var(self.mtype.as(not null))
2283 var cond = v.expr_bool(self.n_expr)
2284 v.add("if ({cond})\{")
2285 v.assign(res, v.expr(self.n_then, null))
2286 v.add("\} else \{")
2287 v.assign(res, v.expr(self.n_else, null))
2288 v.add("\}")
2289 return res
2290 end
2291 end
2292
2293 redef class ADoExpr
2294 redef fun stmt(v)
2295 do
2296 v.stmt(self.n_block)
2297 var escapemark = self.escapemark
2298 if escapemark != null then
2299 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2300 end
2301 end
2302 end
2303
2304 redef class AWhileExpr
2305 redef fun stmt(v)
2306 do
2307 v.add("for(;;) \{")
2308 var cond = v.expr_bool(self.n_expr)
2309 v.add("if (!{cond}) break;")
2310 v.stmt(self.n_block)
2311 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2312 v.add("\}")
2313 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2314 end
2315 end
2316
2317 redef class ALoopExpr
2318 redef fun stmt(v)
2319 do
2320 v.add("for(;;) \{")
2321 v.stmt(self.n_block)
2322 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2323 v.add("\}")
2324 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2325 end
2326 end
2327
2328 redef class AForExpr
2329 redef fun stmt(v)
2330 do
2331 var cl = v.expr(self.n_expr, null)
2332 var it_meth = self.method_iterator
2333 assert it_meth != null
2334 var it = v.send(it_meth, [cl])
2335 assert it != null
2336 v.add("for(;;) \{")
2337 var isok_meth = self.method_is_ok
2338 assert isok_meth != null
2339 var ok = v.send(isok_meth, [it])
2340 assert ok != null
2341 v.add("if(!{ok}) break;")
2342 if self.variables.length == 1 then
2343 var item_meth = self.method_item
2344 assert item_meth != null
2345 var i = v.send(item_meth, [it])
2346 assert i != null
2347 v.assign(v.variable(variables.first), i)
2348 else if self.variables.length == 2 then
2349 var key_meth = self.method_key
2350 assert key_meth != null
2351 var i = v.send(key_meth, [it])
2352 assert i != null
2353 v.assign(v.variable(variables[0]), i)
2354 var item_meth = self.method_item
2355 assert item_meth != null
2356 i = v.send(item_meth, [it])
2357 assert i != null
2358 v.assign(v.variable(variables[1]), i)
2359 else
2360 abort
2361 end
2362 v.stmt(self.n_block)
2363 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2364 var next_meth = self.method_next
2365 assert next_meth != null
2366 v.send(next_meth, [it])
2367 v.add("\}")
2368 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2369 end
2370 end
2371
2372 redef class AAssertExpr
2373 redef fun stmt(v)
2374 do
2375 var cond = v.expr_bool(self.n_expr)
2376 v.add("if (!{cond}) \{")
2377 v.stmt(self.n_else)
2378 var nid = self.n_id
2379 if nid != null then
2380 v.add_abort("Assert '{nid.text}' failed")
2381 else
2382 v.add_abort("Assert failed")
2383 end
2384 v.add("\}")
2385 end
2386 end
2387
2388 redef class AOrExpr
2389 redef fun expr(v)
2390 do
2391 var res = v.new_var(self.mtype.as(not null))
2392 var i1 = v.expr_bool(self.n_expr)
2393 v.add("if ({i1}) \{")
2394 v.add("{res} = 1;")
2395 v.add("\} else \{")
2396 var i2 = v.expr_bool(self.n_expr2)
2397 v.add("{res} = {i2};")
2398 v.add("\}")
2399 return res
2400 end
2401 end
2402
2403 redef class AAndExpr
2404 redef fun expr(v)
2405 do
2406 var res = v.new_var(self.mtype.as(not null))
2407 var i1 = v.expr_bool(self.n_expr)
2408 v.add("if (!{i1}) \{")
2409 v.add("{res} = 0;")
2410 v.add("\} else \{")
2411 var i2 = v.expr_bool(self.n_expr2)
2412 v.add("{res} = {i2};")
2413 v.add("\}")
2414 return res
2415 end
2416 end
2417
2418 redef class ANotExpr
2419 redef fun expr(v)
2420 do
2421 var cond = v.expr_bool(self.n_expr)
2422 return v.new_expr("!{cond}", self.mtype.as(not null))
2423 end
2424 end
2425
2426 redef class AOrElseExpr
2427 redef fun expr(v)
2428 do
2429 var res = v.new_var(self.mtype.as(not null))
2430 var i1 = v.expr(self.n_expr, null)
2431 v.add("if ({i1}!=NULL) \{")
2432 v.assign(res, i1)
2433 v.add("\} else \{")
2434 var i2 = v.expr(self.n_expr2, null)
2435 v.assign(res, i2)
2436 v.add("\}")
2437 return res
2438 end
2439 end
2440
2441 redef class AEeExpr
2442 redef fun expr(v)
2443 do
2444 var value1 = v.expr(self.n_expr, null)
2445 var value2 = v.expr(self.n_expr2, null)
2446 return v.equal_test(value1, value2)
2447 end
2448 end
2449
2450 redef class AIntExpr
2451 redef fun expr(v)
2452 do
2453 return v.new_expr("{self.n_number.text}", self.mtype.as(not null))
2454 end
2455 end
2456
2457 redef class AFloatExpr
2458 redef fun expr(v)
2459 do
2460 return v.new_expr("{self.n_float.text}", self.mtype.as(not null))
2461 end
2462 end
2463
2464 redef class ACharExpr
2465 redef fun expr(v)
2466 do
2467 return v.new_expr("{self.n_char.text}", self.mtype.as(not null))
2468 end
2469 end
2470
2471 redef class AArrayExpr
2472 redef fun expr(v)
2473 do
2474 var mtype = self.mtype.as(MClassType).arguments.first
2475 var array = new Array[RuntimeVariable]
2476 for nexpr in self.n_exprs.n_exprs do
2477 var i = v.expr(nexpr, mtype)
2478 array.add(i)
2479 end
2480 return v.array_instance(array, mtype)
2481 end
2482 end
2483
2484 redef class AStringFormExpr
2485 redef fun expr(v)
2486 do
2487 return v.string_instance(self.value.as(not null))
2488 end
2489 end
2490
2491 redef class ASuperstringExpr
2492 redef fun expr(v)
2493 do
2494 var array = new Array[RuntimeVariable]
2495 for ne in self.n_exprs do
2496 if ne isa AStringFormExpr and ne.value == "" then continue # skip empty sub-strings
2497 var i = v.expr(ne, null)
2498 array.add(i)
2499 end
2500 var a = v.array_instance(array, v.object_type)
2501 var res = v.send(v.get_property("to_s", a.mtype), [a])
2502 return res
2503 end
2504 end
2505
2506 redef class ACrangeExpr
2507 redef fun expr(v)
2508 do
2509 var i1 = v.expr(self.n_expr, null)
2510 var i2 = v.expr(self.n_expr2, null)
2511 var res = v.init_instance(self.mtype.as(MClassType))
2512 var it = v.send(v.get_property("init", res.mtype), [res, i1, i2])
2513 v.check_init_instance(res)
2514 return res
2515 end
2516 end
2517
2518 redef class AOrangeExpr
2519 redef fun expr(v)
2520 do
2521 var i1 = v.expr(self.n_expr, null)
2522 var i2 = v.expr(self.n_expr2, null)
2523 var res = v.init_instance(self.mtype.as(MClassType))
2524 var it = v.send(v.get_property("without_last", res.mtype), [res, i1, i2])
2525 v.check_init_instance(res)
2526 return res
2527 end
2528 end
2529
2530 redef class ATrueExpr
2531 redef fun expr(v)
2532 do
2533 return v.new_expr("1", self.mtype.as(not null))
2534 end
2535 end
2536
2537 redef class AFalseExpr
2538 redef fun expr(v)
2539 do
2540 return v.new_expr("0", self.mtype.as(not null))
2541 end
2542 end
2543
2544 redef class ANullExpr
2545 redef fun expr(v)
2546 do
2547 var res = v.new_expr("NULL", self.mtype.as(not null))
2548 return res
2549 end
2550 end
2551
2552 redef class AIsaExpr
2553 redef fun expr(v)
2554 do
2555 var i = v.expr(self.n_expr, null)
2556 return v.type_test(i, self.cast_type.as(not null))
2557 end
2558 end
2559
2560 redef class AAsCastExpr
2561 redef fun expr(v)
2562 do
2563 var i = v.expr(self.n_expr, null)
2564 var cond = v.type_test(i, self.mtype.as(not null))
2565 v.add("if (!{cond}) \{")
2566 v.add_abort("Cast failed")
2567 v.add("\}")
2568 return i
2569 end
2570 end
2571
2572 redef class AAsNotnullExpr
2573 redef fun expr(v)
2574 do
2575 var i = v.expr(self.n_expr, null)
2576 v.add("if ({i} == NULL) \{")
2577 v.add_abort("Cast failed")
2578 v.add("\}")
2579 return i
2580 end
2581 end
2582
2583 redef class AParExpr
2584 redef fun expr(v)
2585 do
2586 return v.expr(self.n_expr, null)
2587 end
2588 end
2589
2590 redef class AOnceExpr
2591 redef fun expr(v)
2592 do
2593 var mtype = self.mtype.as(not null)
2594 var name = v.get_name("varonce")
2595 var guard = v.get_name(name + "_guard")
2596 v.add_decl("static {mtype.ctype} {name};")
2597 v.add_decl("static int {guard};")
2598 var res = v.new_var(mtype)
2599 v.add("if ({guard}) \{")
2600 v.add("{res} = {name};")
2601 v.add("\} else \{")
2602 var i = v.expr(self.n_expr, mtype)
2603 v.add("{res} = {i};")
2604 v.add("{name} = {res};")
2605 v.add("{guard} = 1;")
2606 v.add("\}")
2607 return res
2608 end
2609 end
2610
2611 redef class ASendExpr
2612 redef fun expr(v)
2613 do
2614 var recv = v.expr(self.n_expr, null)
2615 var args = [recv]
2616 for a in self.raw_arguments.as(not null) do
2617 args.add(v.expr(a, null))
2618 end
2619 var mproperty = self.mproperty.as(not null)
2620 return v.send(mproperty, args)
2621 end
2622 end
2623
2624 redef class ASendReassignFormExpr
2625 redef fun stmt(v)
2626 do
2627 var recv = v.expr(self.n_expr, null)
2628 var args = [recv]
2629 for a in self.raw_arguments.as(not null) do
2630 args.add(v.expr(a, null))
2631 end
2632 var value = v.expr(self.n_value, null)
2633
2634 var mproperty = self.mproperty.as(not null)
2635 var left = v.send(mproperty, args)
2636 assert left != null
2637
2638 var res = v.send(reassign_property.mproperty, [left, value])
2639 assert res != null
2640
2641 args.add(res)
2642 v.send(self.write_mproperty.as(not null), args)
2643 end
2644 end
2645
2646 redef class ASuperExpr
2647 redef fun expr(v)
2648 do
2649 var recv = v.frame.arguments.first
2650 var args = [recv]
2651 for a in self.n_args.n_exprs do
2652 args.add(v.expr(a, null))
2653 end
2654 if args.length == 1 then
2655 args = v.frame.arguments
2656 end
2657
2658 var mproperty = self.mproperty
2659 if mproperty != null then
2660 if mproperty.intro.msignature.arity == 0 then
2661 args = [recv]
2662 end
2663 # Super init call
2664 var res = v.send(mproperty, args)
2665 return res
2666 end
2667
2668 # stantard call-next-method
2669 var mpropdef = v.frame.mpropdef
2670 # FIXME: we do not want an ugly static call!
2671 var mpropdefs = mpropdef.mproperty.lookup_super_definitions(mpropdef.mclassdef.mmodule, mpropdef.mclassdef.bound_mtype)
2672 if mpropdefs.length != 1 then
2673 v.add("printf(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");")
2674 debug("MPRODFEFS for super {mpropdef} for {recv}: {mpropdefs.join(", ")}")
2675 end
2676 mpropdef = mpropdefs.first
2677 assert mpropdef isa MMethodDef
2678 var res = v.call(mpropdef, recv.mtype.as(MClassType), args)
2679 return res
2680 end
2681 end
2682
2683 redef class ANewExpr
2684 redef fun expr(v)
2685 do
2686 var mproperty = self.mproperty.as(not null)
2687 var mtype = self.mtype.as(MClassType)
2688 var recv
2689 var ctype = mtype.ctype
2690 if ctype == "val*" then
2691 recv = v.init_instance(mtype)
2692 else if ctype == "void*" then
2693 recv = v.new_expr("NULL/*special!*/", mtype)
2694 else
2695 debug("cannot new {mtype}")
2696 abort
2697 end
2698 var args = [recv]
2699 for a in self.n_args.n_exprs do
2700 args.add(v.expr(a, null))
2701 end
2702 var res2 = v.send(mproperty, args)
2703 if res2 != null then
2704 #self.debug("got {res2} from {mproperty}. drop {recv}")
2705 return res2
2706 end
2707 v.check_init_instance(recv)
2708 return recv
2709 end
2710 end
2711
2712 redef class AAttrExpr
2713 redef fun expr(v)
2714 do
2715 var recv = v.expr(self.n_expr, null)
2716 var mproperty = self.mproperty.as(not null)
2717 return v.read_attribute(mproperty, recv)
2718 end
2719 end
2720
2721 redef class AAttrAssignExpr
2722 redef fun stmt(v)
2723 do
2724 var recv = v.expr(self.n_expr, null)
2725 var i = v.expr(self.n_value, null)
2726 var mproperty = self.mproperty.as(not null)
2727 v.write_attribute(mproperty, recv, i)
2728 end
2729 end
2730
2731 redef class AAttrReassignExpr
2732 redef fun stmt(v)
2733 do
2734 var recv = v.expr(self.n_expr, null)
2735 var value = v.expr(self.n_value, null)
2736 var mproperty = self.mproperty.as(not null)
2737 var attr = v.read_attribute(mproperty, recv)
2738 var res = v.send(reassign_property.mproperty, [attr, value])
2739 assert res != null
2740 v.write_attribute(mproperty, recv, res)
2741 end
2742 end
2743
2744 redef class AIssetAttrExpr
2745 redef fun expr(v)
2746 do
2747 var recv = v.expr(self.n_expr, null)
2748 var mproperty = self.mproperty.as(not null)
2749 return v.isset_attribute(mproperty, recv)
2750 end
2751 end
2752
2753 redef class ADebugTypeExpr
2754 redef fun stmt(v)
2755 do
2756 # do nothing
2757 end
2758 end