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