468fc04b4578d8007be73377e5f81f404216c8b5
[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 propdefs = m.lookup_definitions(self.compiler.mainmodule, mclasstype)
1375 if propdefs.length == 0 then
1376 self.add("/* skip, no method {m} */")
1377 return res
1378 end
1379 assert propdefs.length == 1
1380 var propdef = propdefs.first
1381 var res2 = self.call(propdef, mclasstype, args)
1382 if res != null then self.assign(res, res2.as(not null))
1383 return res
1384 end
1385 var consider_null = not self.compiler.modelbuilder.toolcontext.opt_no_check_other.value or m.name == "==" or m.name == "!="
1386 if args.first.mcasttype isa MNullableType or args.first.mcasttype isa MNullType and consider_null then
1387 # The reciever is potentially null, so we have to 3 cases: ==, != or NullPointerException
1388 self.add("if ({args.first} == NULL) \{ /* Special null case */")
1389 if m.name == "==" then
1390 assert res != null
1391 if args[1].mcasttype isa MNullableType then
1392 self.add("{res} = ({args[1]} == NULL);")
1393 else if args[1].mcasttype isa MNullType then
1394 self.add("{res} = 1; /* is null */")
1395 else
1396 self.add("{res} = 0; /* {args[1].inspect} cannot be null */")
1397 end
1398 else if m.name == "!=" then
1399 assert res != null
1400 if args[1].mcasttype isa MNullableType then
1401 self.add("{res} = ({args[1]} != NULL);")
1402 else if args[1].mcasttype isa MNullType then
1403 self.add("{res} = 0; /* is null */")
1404 else
1405 self.add("{res} = 1; /* {args[1].inspect} cannot be null */")
1406 end
1407 else
1408 self.add_abort("Reciever is null")
1409 end
1410 self.add "\} else"
1411 end
1412 if types.is_empty then
1413 self.add("\{")
1414 self.add("/*BUG: no live types for {args.first.inspect} . {m}*/")
1415 self.bugtype(args.first)
1416 self.add("\}")
1417 return res
1418 end
1419
1420 self.add("switch({args.first}->classid) \{")
1421 var last = types.last
1422 var defaultpropdef: nullable MMethodDef = null
1423 for t in types do
1424 var propdefs = m.lookup_definitions(self.compiler.mainmodule, t)
1425 if propdefs.length == 0 then
1426 self.add("/* skip {t}, no method {m} */")
1427 continue
1428 end
1429 if propdefs.length > 1 then
1430 self.debug("NOT YET IMPLEMENTED conflict for {t}.{m}: {propdefs.join(" ")}. choose the first")
1431 end
1432 var propdef = propdefs.first
1433 if propdef.mclassdef.mclass.name == "Object" and t.ctype == "val*" then
1434 defaultpropdef = propdef
1435 continue
1436 end
1437 if not self.compiler.hardening and t == last and defaultpropdef == null then
1438 self.add("default: /* test {t} */")
1439 else
1440 self.add("case {self.compiler.classid(t)}: /* test {t} */")
1441 end
1442 var res2 = self.call(propdef, t, args)
1443 if res != null then self.assign(res, res2.as(not null))
1444 self.add "break;"
1445 end
1446 if defaultpropdef != null then
1447 self.add("default: /* default is Object */")
1448 var res2 = self.call(defaultpropdef, defaultpropdef.mclassdef.bound_mtype, args)
1449 if res != null then self.assign(res, res2.as(not null))
1450 else if self.compiler.hardening then
1451 self.add("default: /* bug */")
1452 self.bugtype(args.first)
1453 end
1454 self.add("\}")
1455 return res
1456 end
1457
1458 # Generate a monomorphic send for the method `m', the type `t' and the arguments `args'
1459 fun monomorphic_send(m: MMethod, t: MType, args: Array[RuntimeVariable]): nullable RuntimeVariable
1460 do
1461 assert t isa MClassType
1462 var propdefs = m.lookup_definitions(self.compiler.mainmodule, t)
1463 if propdefs.length == 0 then
1464 abort
1465 end
1466 if propdefs.length > 1 then
1467 self.debug("NOT YET IMPLEMENTED conflict for {t}.{m}: {propdefs.join(" ")}. choose the first")
1468 end
1469 var propdef = propdefs.first
1470 return self.call(propdef, t, args)
1471 end
1472
1473 fun check_valid_reciever(recvtype: MClassType)
1474 do
1475 if self.compiler.runtime_type_analysis.live_types.has(recvtype) or recvtype.mclass.name == "Object" then return
1476 print "{recvtype} is not a live type"
1477 abort
1478 end
1479
1480 # Generate a static call on a method definition
1481 fun call(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable
1482 do
1483 check_valid_reciever(recvtype)
1484 #debug("call {m} on {recvtype} on {args.first}:{args.first.mtype}")
1485 if m.mclassdef.mclass.name == "Object" and recvtype.ctype == "val*" then
1486 recvtype = m.mclassdef.bound_mtype
1487 end
1488 var recv = self.autobox(args.first, recvtype)
1489 recv = self.autoadapt(recv, recvtype)
1490
1491 args = args.to_a
1492 self.varargize(m, m.msignature.as(not null), args)
1493 if args.length != m.msignature.arity + 1 then # because of self
1494 add("printf(\"NOT YET IMPLEMENTED: Invalid arity for {m}. {args.length} arguments given.\\n\"); exit(1);")
1495 debug("NOT YET IMPLEMENTED: Invalid arity for {m}. {args.length} arguments given.")
1496 return null
1497 end
1498
1499 args.first = recv
1500 var rm = new CustomizedRuntimeFunction(m, recvtype)
1501 return rm.call(self, args)
1502 end
1503
1504 fun adapt_signature(m: MMethodDef, args: Array[RuntimeVariable])
1505 do
1506 var recv = args.first
1507 for i in [0..m.msignature.arity[ do
1508 var t = m.msignature.mparameters[i].mtype
1509 if i == m.msignature.vararg_rank then
1510 t = args[i+1].mtype
1511 end
1512 t = self.resolve_for(t, recv)
1513 args[i+1] = self.autobox(args[i+1], t)
1514 end
1515 end
1516
1517 # Transform varargs, in raw arguments, into a single argument of type Array
1518 # Note: this method modify the given `args`
1519 # If there is no vararg, then `args` is not modified.
1520 fun varargize(mpropdef: MPropDef, msignature: MSignature, args: Array[RuntimeVariable])
1521 do
1522 var recv = args.first
1523 var vararg_rank = msignature.vararg_rank
1524 if vararg_rank >= 0 then
1525 assert args.length >= msignature.arity + 1 # because of self
1526 var rawargs = args
1527 args = new Array[RuntimeVariable]
1528
1529 args.add(rawargs.first) # recv
1530
1531 for i in [0..vararg_rank[ do
1532 args.add(rawargs[i+1])
1533 end
1534
1535 var vararg_lastrank = vararg_rank + rawargs.length-1-msignature.arity
1536 var vararg = new Array[RuntimeVariable]
1537 for i in [vararg_rank..vararg_lastrank] do
1538 vararg.add(rawargs[i+1])
1539 end
1540
1541 var elttype = msignature.mparameters[vararg_rank].mtype
1542 args.add(self.vararg_instance(mpropdef, recv, vararg, elttype))
1543
1544 for i in [vararg_lastrank+1..rawargs.length-1[ do
1545 args.add(rawargs[i+1])
1546 end
1547 rawargs.clear
1548 rawargs.add_all(args)
1549 end
1550 end
1551
1552 # Get an instance of a anny for a vararg
1553 fun vararg_instance(mpropdef: MPropDef, recv: RuntimeVariable, varargs: Array[RuntimeVariable], elttype: MType): RuntimeVariable
1554 do
1555 # FIXME: this is currently buggy since recv is not exact
1556
1557 elttype = self.resolve_for(elttype, recv)
1558 return self.array_instance(varargs, elttype)
1559 end
1560
1561
1562 fun bugtype(recv: RuntimeVariable)
1563 do
1564 if recv.mtype.ctype != "val*" then return
1565 self.add("fprintf(stderr, \"BTD BUG: Dynamic type is %s, static type is %s\\n\", class_names[{recv}->classid], \"{recv.mcasttype}\");")
1566 self.add("exit(1);")
1567 end
1568
1569 # Generate a polymorphic attribute is_set test
1570 fun isset_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable
1571 do
1572 check_recv_notnull(recv)
1573
1574 var types = self.collect_types(recv)
1575
1576 var res = self.new_var(bool_type)
1577
1578 if types.is_empty then
1579 self.add("/*BUG: no live types for {recv.inspect} . {a}*/")
1580 self.bugtype(recv)
1581 return res
1582 end
1583 self.add("/* isset {a} on {recv.inspect} */")
1584 self.add("switch({recv}->classid) \{")
1585 var last = types.last
1586 for t in types do
1587 if not self.compiler.hardening and t == last then
1588 self.add("default: /*{self.compiler.classid(t)}*/")
1589 else
1590 self.add("case {self.compiler.classid(t)}:")
1591 end
1592 var recv2 = self.autoadapt(recv, t)
1593 var ta = a.intro.static_mtype.as(not null)
1594 ta = self.resolve_for(ta, recv2)
1595 var attr = self.new_expr("((struct {t.c_name}*){recv})->{a.intro.c_name}", ta)
1596 if not ta isa MNullableType then
1597 if ta.ctype == "val*" then
1598 self.add("{res} = ({attr} != NULL);")
1599 else
1600 self.add("{res} = 1; /*NOTYET isset on primitive attributes*/")
1601 end
1602 end
1603 self.add("break;")
1604 end
1605 if self.compiler.hardening then
1606 self.add("default: /* Bug */")
1607 self.bugtype(recv)
1608 end
1609 self.add("\}")
1610
1611 return res
1612 end
1613
1614 # Generate a polymorphic attribute read
1615 fun read_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable
1616 do
1617 check_recv_notnull(recv)
1618
1619 var types = self.collect_types(recv)
1620
1621 var ret = a.intro.static_mtype.as(not null)
1622 ret = self.resolve_for(ret, recv)
1623 var res = self.new_var(ret)
1624
1625 if types.is_empty then
1626 self.add("/*BUG: no live types for {recv.inspect} . {a}*/")
1627 self.bugtype(recv)
1628 return res
1629 end
1630 self.add("/* read {a} on {recv.inspect} */")
1631 self.add("switch({recv}->classid) \{")
1632 var last = types.last
1633 for t in types do
1634 if not self.compiler.hardening and t == last then
1635 self.add("default: /*{self.compiler.classid(t)}*/")
1636 else
1637 self.add("case {self.compiler.classid(t)}:")
1638 end
1639 var recv2 = self.autoadapt(recv, t)
1640 var ta = a.intro.static_mtype.as(not null)
1641 ta = self.resolve_for(ta, recv2)
1642 var res2 = self.new_expr("((struct {t.c_name}*){recv})->{a.intro.c_name}", ta)
1643 if not ta isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_other.value then
1644 if ta.ctype == "val*" then
1645 self.add("if ({res2} == NULL) \{")
1646 self.add_abort("Uninitialized attribute {a.name}")
1647 self.add("\}")
1648 else
1649 self.add("/*NOTYET isset on primitive attributes*/")
1650 end
1651 end
1652 self.assign(res, res2)
1653 self.add("break;")
1654 end
1655 if self.compiler.hardening then
1656 self.add("default: /* Bug */")
1657 self.bugtype(recv)
1658 end
1659 self.add("\}")
1660
1661 return res
1662 end
1663
1664 # Generate a polymorphic attribute write
1665 fun write_attribute(a: MAttribute, recv: RuntimeVariable, value: RuntimeVariable)
1666 do
1667 check_recv_notnull(recv)
1668
1669 var types = self.collect_types(recv)
1670
1671 if types.is_empty then
1672 self.add("/*BUG: no live types for {recv.inspect} . {a}*/")
1673 self.bugtype(recv)
1674 return
1675 end
1676 self.add("/* write {a} on {recv.inspect} */")
1677 self.add("switch({recv}->classid) \{")
1678 var last = types.last
1679 for t in types do
1680 if not self.compiler.hardening and t == last then
1681 self.add("default: /*{self.compiler.classid(t)}*/")
1682 else
1683 self.add("case {self.compiler.classid(t)}:")
1684 end
1685 var recv2 = self.autoadapt(recv, t)
1686 var ta = a.intro.static_mtype.as(not null)
1687 ta = self.resolve_for(ta, recv2)
1688 self.add("((struct {t.c_name}*){recv})->{a.intro.c_name} = {self.autobox(value, ta)};")
1689 self.add("break;")
1690 end
1691 if self.compiler.hardening then
1692 self.add("default: /* Bug*/")
1693 self.bugtype(recv)
1694 end
1695 self.add("\}")
1696 end
1697
1698 # Generate a alloc-instance + init-attributes
1699 fun init_instance(mtype: MClassType): RuntimeVariable
1700 do
1701 mtype = self.anchor(mtype).as(MClassType)
1702 if not self.compiler.runtime_type_analysis.live_types.has(mtype) then
1703 debug "problem: {mtype} was detected dead"
1704 end
1705 var res = self.new_expr("NEW_{mtype.c_name}()", mtype)
1706 res.is_exact = true
1707 return res
1708 end
1709
1710 # Generate a polymorphic subtype test
1711 fun type_test(value: RuntimeVariable, mtype: MType, tag: String): RuntimeVariable
1712 do
1713 mtype = self.anchor(mtype)
1714 var mclasstype = mtype
1715 if mtype isa MNullableType then mclasstype = mtype.mtype
1716 assert mclasstype isa MClassType
1717 if not self.compiler.runtime_type_analysis.live_cast_types.has(mclasstype) then
1718 debug "problem: {mtype} was detected cast-dead"
1719 abort
1720 end
1721
1722 var types = self.collect_types(value)
1723
1724 var res = self.new_var(bool_type)
1725
1726 self.add("/* isa {mtype} on {value.inspect} */")
1727 if value.mtype.ctype != "val*" then
1728 if value.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then
1729 self.add("{res} = 1;")
1730 else
1731 self.add("{res} = 0;")
1732 end
1733 return res
1734 end
1735 if value.mcasttype isa MNullableType or value.mcasttype isa MNullType then
1736 self.add("if ({value} == NULL) \{")
1737 if mtype isa MNullableType then
1738 self.add("{res} = 1; /* isa {mtype} */")
1739 else
1740 self.add("{res} = 0; /* not isa {mtype} */")
1741 end
1742 self.add("\} else ")
1743 end
1744 self.add("switch({value}->classid) \{")
1745 for t in types do
1746 if t.is_subtype(self.compiler.mainmodule, null, mtype) then
1747 self.add("case {self.compiler.classid(t)}: /* {t} */")
1748 end
1749 end
1750 self.add("{res} = 1;")
1751 self.add("break;")
1752 self.add("default:")
1753 self.add("{res} = 0;")
1754 self.add("\}")
1755
1756 return res
1757 end
1758
1759 # Generate the code required to dynamically check if 2 objects share the same runtime type
1760 fun is_same_type_test(value1, value2: RuntimeVariable): RuntimeVariable
1761 do
1762 var res = self.new_var(bool_type)
1763 if value2.mtype.ctype == "val*" then
1764 if value1.mtype.ctype == "val*" then
1765 self.add "{res} = {value1}->classid == {value2}->classid;"
1766 else
1767 self.add "{res} = {self.compiler.classid(value1.mtype.as(MClassType))} == {value2}->classid;"
1768 end
1769 else
1770 if value1.mtype.ctype == "val*" then
1771 self.add "{res} = {value1}->classid == {self.compiler.classid(value2.mtype.as(MClassType))};"
1772 else if value1.mcasttype == value2.mcasttype then
1773 self.add "{res} = 1;"
1774 else
1775 self.add "{res} = 0;"
1776 end
1777 end
1778 return res
1779 end
1780
1781 # Return a "const char*" variable associated to the classname of the dynamic type of an object
1782 # NOTE: we do not return a RuntimeVariable "NativeString" as the class may not exist in the module/program
1783 fun class_name_string(value: RuntimeVariable): String
1784 do
1785 var res = self.get_name("var_class_name")
1786 self.add_decl("const char* {res};")
1787 if value.mtype.ctype == "val*" then
1788 self.add "{res} = class_names[{value}->classid];"
1789 else
1790 self.add "{res} = class_names[{self.compiler.classid(value.mtype.as(MClassType))}];"
1791 end
1792 return res
1793 end
1794
1795 # Generate a Nit "is" for two runtime_variables
1796 fun equal_test(value1, value2: RuntimeVariable): RuntimeVariable
1797 do
1798 var res = self.new_var(bool_type)
1799 if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
1800 var tmp = value1
1801 value1 = value2
1802 value2 = tmp
1803 end
1804 if value1.mtype.ctype != "val*" then
1805 if value2.mtype == value1.mtype then
1806 self.add("{res} = {value1} == {value2};")
1807 else if value2.mtype.ctype != "val*" then
1808 self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
1809 else
1810 var mtype1 = value1.mtype.as(MClassType)
1811 self.add("{res} = ({value2} != NULL) && ({value2}->classid == {self.compiler.classid(mtype1)});")
1812 self.add("if ({res}) \{")
1813 self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
1814 self.add("\}")
1815 end
1816 else
1817 var s = new Array[String]
1818 for t in self.compiler.live_primitive_types do
1819 if not t.is_subtype(self.compiler.mainmodule, null, value1.mcasttype) then continue
1820 if not t.is_subtype(self.compiler.mainmodule, null, value2.mcasttype) then continue
1821 s.add "({value1}->classid == {self.compiler.classid(t)} && ((struct {t.c_name}*){value1})->value == ((struct {t.c_name}*){value2})->value)"
1822 end
1823 if s.is_empty then
1824 self.add("{res} = {value1} == {value2};")
1825 else
1826 self.add("{res} = {value1} == {value2} || ({value1} != NULL && {value2} != NULL && {value1}->classid == {value2}->classid && ({s.join(" || ")}));")
1827 end
1828 end
1829 return res
1830 end
1831
1832 # Generate a check-init-instance
1833 fun check_init_instance(recv: RuntimeVariable, mtype: MClassType)
1834 do
1835 if self.compiler.modelbuilder.toolcontext.opt_no_check_initialization.value then return
1836
1837 mtype = self.anchor(mtype).as(MClassType)
1838 if not self.compiler.runtime_type_analysis.live_types.has(mtype) then
1839 debug "problem: {mtype} was detected dead"
1840 end
1841
1842 self.add("CHECK_NEW_{mtype.c_name}({recv});")
1843 end
1844
1845 # Generate an integer value
1846 fun int_instance(value: Int): RuntimeVariable
1847 do
1848 var res = self.new_var(self.get_class("Int").mclass_type)
1849 self.add("{res} = {value};")
1850 return res
1851 end
1852
1853 # Generate an array value
1854 fun array_instance(array: Array[RuntimeVariable], elttype: MType): RuntimeVariable
1855 do
1856 elttype = self.anchor(elttype)
1857 var arraytype = self.get_class("Array").get_mtype([elttype])
1858 var res = self.init_instance(arraytype)
1859 self.add("\{ /* {res} = array_instance Array[{elttype}] */")
1860 var nat = self.new_var(self.get_class("NativeArray").get_mtype([elttype]))
1861 nat.is_exact = true
1862 self.add("{nat} = NEW_{nat.mtype.c_name}({array.length});")
1863 for i in [0..array.length[ do
1864 var r = self.autobox(array[i], elttype)
1865 self.add("((struct {nat.mtype.c_name}*) {nat})->values[{i}] = {r};")
1866 end
1867 var length = self.int_instance(array.length)
1868 self.send(self.get_property("with_native", arraytype), [res, nat, length])
1869 self.check_init_instance(res, arraytype)
1870 self.add("\}")
1871 return res
1872 end
1873
1874 # Generate a string value
1875 fun string_instance(string: String): RuntimeVariable
1876 do
1877 var mtype = self.get_class("String").mclass_type
1878 var name = self.get_name("varonce")
1879 self.add_decl("static {mtype.ctype} {name};")
1880 var res = self.new_var(mtype)
1881 self.add("if ({name}) \{")
1882 self.add("{res} = {name};")
1883 self.add("\} else \{")
1884 var nat = self.new_var(self.get_class("NativeString").mclass_type)
1885 self.add("{nat} = \"{string.escape_to_c}\";")
1886 var res2 = self.init_instance(mtype)
1887 self.add("{res} = {res2};")
1888 var length = self.int_instance(string.length)
1889 self.send(self.get_property("with_native", mtype), [res, nat, length])
1890 self.check_init_instance(res, mtype)
1891 self.add("{name} = {res};")
1892 self.add("\}")
1893 return res
1894 end
1895
1896 # Generate generic abort
1897 # used by aborts, asserts, casts, etc.
1898 fun add_abort(message: String)
1899 do
1900 if self.current_node != null and self.current_node.location.file != null then
1901 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});")
1902 else
1903 self.add("fprintf(stderr, \"Runtime error: %s\\n\", \"{message.escape_to_c}\");")
1904 end
1905 self.add("exit(1);")
1906 end
1907 end
1908
1909 # A frame correspond to a visited property in a GlobalCompilerVisitor
1910 class Frame
1911 # The associated visitor
1912
1913 var visitor: GlobalCompilerVisitor
1914
1915 # The executed property.
1916 # A Method in case of a call, an attribute in case of a default initialization.
1917 var mpropdef: MPropDef
1918
1919 # The static type of the receiver
1920 var receiver: MClassType
1921
1922 # Arguments of the method (the first is the receiver)
1923 var arguments: Array[RuntimeVariable]
1924
1925 # The runtime_variable associated to the return (in a function)
1926 var returnvar: nullable RuntimeVariable writable = null
1927
1928 # The label at the end of the property
1929 var returnlabel: nullable String writable = null
1930 end
1931
1932 redef class MPropDef
1933 private var c_name_cache: nullable String
1934
1935 # The mangled name associated to the property
1936 fun c_name: String
1937 do
1938 var res = self.c_name_cache
1939 if res != null then return res
1940 res = "{self.mclassdef.mmodule.name.to_cmangle}__{self.mclassdef.mclass.name.to_cmangle}__{self.mproperty.name.to_cmangle}"
1941 self.c_name_cache = res
1942 return res
1943 end
1944 end
1945
1946 redef class MMethodDef
1947 # Can the body be inlined?
1948 fun can_inline(v: GlobalCompilerVisitor): Bool
1949 do
1950 var modelbuilder = v.compiler.modelbuilder
1951 if modelbuilder.mpropdef2npropdef.has_key(self) then
1952 var npropdef = modelbuilder.mpropdef2npropdef[self]
1953 return npropdef.can_inline
1954 else if self.mproperty.name == "init" then
1955 # Automatic free init is always inlined since it is empty or contains only attribtes assigments
1956 return true
1957 else
1958 abort
1959 end
1960 end
1961
1962 # Inline the body in another visitor
1963 fun compile_inside_to_c(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
1964 do
1965 var modelbuilder = v.compiler.modelbuilder
1966 if modelbuilder.mpropdef2npropdef.has_key(self) then
1967 var npropdef = modelbuilder.mpropdef2npropdef[self]
1968 var oldnode = v.current_node
1969 v.current_node = npropdef
1970 self.compile_parameter_check(v, arguments)
1971 npropdef.compile_to_c(v, self, arguments)
1972 v.current_node = oldnode
1973 else if self.mproperty.name == "init" then
1974 var nclassdef = modelbuilder.mclassdef2nclassdef[self.mclassdef]
1975 var oldnode = v.current_node
1976 v.current_node = nclassdef
1977 self.compile_parameter_check(v, arguments)
1978 nclassdef.compile_to_c(v, self, arguments)
1979 v.current_node = oldnode
1980 else
1981 abort
1982 end
1983 return null
1984 end
1985
1986 # Generate type checks in the C code to check covariant parameters
1987 fun compile_parameter_check(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable])
1988 do
1989 if v.compiler.modelbuilder.toolcontext.opt_no_check_covariance.value then return
1990
1991 for i in [0..msignature.arity[ do
1992 # skip test for vararg since the array is instantiated with the correct polymorphic type
1993 if msignature.vararg_rank == i then continue
1994
1995 # skip if the cast is not required
1996 var origmtype = self.mproperty.intro.msignature.mparameters[i].mtype
1997 if not origmtype.need_anchor then continue
1998
1999 # get the parameter type
2000 var mtype = self.msignature.mparameters[i].mtype
2001
2002 # generate the cast
2003 # note that v decides if and how to implements the cast
2004 v.add("/* Covariant cast for argument {i} ({self.msignature.mparameters[i].name}) {arguments[i+1].inspect} isa {mtype} */")
2005 var cond = v.type_test(arguments[i+1], mtype, "covariance")
2006 v.add("if (!{cond}) \{")
2007 #var x = v.class_name_string(arguments[i+1])
2008 #var y = v.class_name_string(arguments.first)
2009 #v.add("fprintf(stderr, \"expected {mtype} (self is %s), got %s for {arguments[i+1].inspect}\\n\", {y}, {x});")
2010 v.add_abort("Cast failed")
2011 v.add("\}")
2012 end
2013 end
2014 end
2015
2016 redef class APropdef
2017 fun compile_to_c(v: GlobalCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
2018 do
2019 v.add("printf(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");")
2020 debug("Not yet implemented")
2021 end
2022
2023 fun can_inline: Bool do return true
2024 end
2025
2026 redef class AConcreteMethPropdef
2027 redef fun compile_to_c(v, mpropdef, arguments)
2028 do
2029 for i in [0..mpropdef.msignature.arity[ do
2030 var variable = self.n_signature.n_params[i].variable.as(not null)
2031 v.assign(v.variable(variable), arguments[i+1])
2032 end
2033 # Call the implicit super-init
2034 var auto_super_inits = self.auto_super_inits
2035 if auto_super_inits != null then
2036 var selfarg = [arguments.first]
2037 for auto_super_init in auto_super_inits do
2038 if auto_super_init.intro.msignature.arity == 0 then
2039 v.send(auto_super_init, selfarg)
2040 else
2041 v.send(auto_super_init, arguments)
2042 end
2043 end
2044 end
2045 v.stmt(self.n_block)
2046 end
2047
2048 redef fun can_inline
2049 do
2050 if self.auto_super_inits != null then return false
2051 var nblock = self.n_block
2052 if nblock == null then return true
2053 if (mpropdef.mproperty.name == "==" or mpropdef.mproperty.name == "!=") and mpropdef.mclassdef.mclass.name == "Object" then return true
2054 if nblock isa ABlockExpr and nblock.n_expr.length == 0 then return true
2055 return false
2056 end
2057 end
2058
2059 redef class AInternMethPropdef
2060 redef fun compile_to_c(v, mpropdef, arguments)
2061 do
2062 var pname = mpropdef.mproperty.name
2063 var cname = mpropdef.mclassdef.mclass.name
2064 var ret = mpropdef.msignature.return_mtype
2065 if ret != null then
2066 ret = v.resolve_for(ret, arguments.first)
2067 end
2068 if pname != "==" and pname != "!=" then
2069 v.adapt_signature(mpropdef, arguments)
2070 end
2071 if cname == "Int" then
2072 if pname == "output" then
2073 v.add("printf(\"%ld\\n\", {arguments.first});")
2074 return
2075 else if pname == "object_id" then
2076 v.ret(arguments.first)
2077 return
2078 else if pname == "+" then
2079 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
2080 return
2081 else if pname == "-" then
2082 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
2083 return
2084 else if pname == "unary -" then
2085 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
2086 return
2087 else if pname == "succ" then
2088 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
2089 return
2090 else if pname == "prec" then
2091 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
2092 return
2093 else if pname == "*" then
2094 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
2095 return
2096 else if pname == "/" then
2097 v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
2098 return
2099 else if pname == "%" then
2100 v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null)))
2101 return
2102 else if pname == "lshift" then
2103 v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null)))
2104 return
2105 else if pname == "rshift" then
2106 v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null)))
2107 return
2108 else if pname == "==" then
2109 v.ret(v.equal_test(arguments[0], arguments[1]))
2110 return
2111 else if pname == "!=" then
2112 var res = v.equal_test(arguments[0], arguments[1])
2113 v.ret(v.new_expr("!{res}", ret.as(not null)))
2114 return
2115 else if pname == "<" then
2116 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
2117 return
2118 else if pname == ">" then
2119 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
2120 return
2121 else if pname == "<=" then
2122 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
2123 return
2124 else if pname == ">=" then
2125 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
2126 return
2127 else if pname == "to_f" then
2128 v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
2129 return
2130 else if pname == "ascii" then
2131 v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
2132 return
2133 end
2134 else if cname == "Char" then
2135 if pname == "output" then
2136 v.add("printf(\"%c\", {arguments.first});")
2137 return
2138 else if pname == "object_id" then
2139 v.ret(arguments.first)
2140 return
2141 else if pname == "+" then
2142 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
2143 return
2144 else if pname == "-" then
2145 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
2146 return
2147 else if pname == "==" then
2148 v.ret(v.equal_test(arguments[0], arguments[1]))
2149 return
2150 else if pname == "!=" then
2151 var res = v.equal_test(arguments[0], arguments[1])
2152 v.ret(v.new_expr("!{res}", ret.as(not null)))
2153 return
2154 else if pname == "succ" then
2155 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
2156 return
2157 else if pname == "prec" then
2158 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
2159 return
2160 else if pname == "<" then
2161 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
2162 return
2163 else if pname == ">" then
2164 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
2165 return
2166 else if pname == "<=" then
2167 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
2168 return
2169 else if pname == ">=" then
2170 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
2171 return
2172 else if pname == "to_i" then
2173 v.ret(v.new_expr("{arguments[0]}-'0'", ret.as(not null)))
2174 return
2175 else if pname == "ascii" then
2176 v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
2177 return
2178 end
2179 else if cname == "Bool" then
2180 if pname == "output" then
2181 v.add("printf({arguments.first}?\"true\\n\":\"false\\n\");")
2182 return
2183 else if pname == "object_id" then
2184 v.ret(arguments.first)
2185 return
2186 else if pname == "==" then
2187 v.ret(v.equal_test(arguments[0], arguments[1]))
2188 return
2189 else if pname == "!=" then
2190 var res = v.equal_test(arguments[0], arguments[1])
2191 v.ret(v.new_expr("!{res}", ret.as(not null)))
2192 return
2193 end
2194 else if cname == "Float" then
2195 if pname == "output" then
2196 v.add("printf(\"%f\\n\", {arguments.first});")
2197 return
2198 else if pname == "object_id" then
2199 v.ret(v.new_expr("(double){arguments.first}", 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 == "unary -" then
2208 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
2209 return
2210 else if pname == "succ" then
2211 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
2212 return
2213 else if pname == "prec" then
2214 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
2215 return
2216 else if pname == "*" then
2217 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
2218 return
2219 else if pname == "/" then
2220 v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
2221 return
2222 else if pname == "==" then
2223 v.ret(v.equal_test(arguments[0], arguments[1]))
2224 return
2225 else if pname == "!=" then
2226 var res = v.equal_test(arguments[0], arguments[1])
2227 v.ret(v.new_expr("!{res}", ret.as(not null)))
2228 return
2229 else if pname == "<" then
2230 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
2231 return
2232 else if pname == ">" then
2233 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
2234 return
2235 else if pname == "<=" then
2236 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
2237 return
2238 else if pname == ">=" then
2239 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
2240 return
2241 else if pname == "to_i" then
2242 v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
2243 return
2244 end
2245 else if cname == "Char" then
2246 if pname == "output" then
2247 v.add("printf(\"%c\", {arguments.first});")
2248 return
2249 else if pname == "object_id" then
2250 v.ret(arguments.first)
2251 return
2252 else if pname == "==" then
2253 v.ret(v.equal_test(arguments[0], arguments[1]))
2254 return
2255 else if pname == "!=" then
2256 var res = v.equal_test(arguments[0], arguments[1])
2257 v.ret(v.new_expr("!{res}", ret.as(not null)))
2258 return
2259 else if pname == "ascii" then
2260 v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
2261 return
2262 end
2263 else if cname == "NativeString" then
2264 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.add("{arguments[0]}[{arguments[1]}]={arguments[2]};")
2269 return
2270 else if pname == "copy_to" then
2271 v.add("memcpy({arguments[1]}+{arguments[4]},{arguments[0]}+{arguments[3]},{arguments[2]});")
2272 return
2273 else if pname == "atoi" then
2274 v.ret(v.new_expr("atoi({arguments[0]});", ret.as(not null)))
2275 return
2276 end
2277 else if cname == "NativeArray" then
2278 v.native_array_def(pname, ret, arguments)
2279 return
2280 end
2281 if pname == "exit" then
2282 v.add("exit({arguments[1]});")
2283 return
2284 else if pname == "sys" then
2285 v.ret(v.new_expr("glob_sys", ret.as(not null)))
2286 return
2287 else if pname == "calloc_string" then
2288 v.ret(v.new_expr("(char*)GC_MALLOC_ATOMIC({arguments[1]})", ret.as(not null)))
2289 return
2290 else if pname == "calloc_array" then
2291 v.calloc_array(ret.as(not null), arguments)
2292 return
2293 else if pname == "object_id" then
2294 v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
2295 return
2296 else if pname == "is_same_type" then
2297 v.ret(v.is_same_type_test(arguments[0], arguments[1]))
2298 return
2299 else if pname == "output_class_name" then
2300 var nat = v.class_name_string(arguments.first)
2301 v.add("printf(\"%s\\n\", {nat});")
2302 return
2303 else if pname == "native_class_name" then
2304 var nat = v.class_name_string(arguments.first)
2305 v.ret(v.new_expr("(char*){nat}", ret.as(not null)))
2306 return
2307 else if pname == "force_garbage_collection" then
2308 v.add("GC_gcollect();")
2309 return
2310 end
2311 v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{mpropdef} at {location.to_s}\\n\");")
2312 debug("Not implemented {mpropdef}")
2313 end
2314 end
2315
2316 redef class AExternMethPropdef
2317 redef fun compile_to_c(v, mpropdef, arguments)
2318 do
2319 var externname
2320 var nextern = self.n_extern
2321 if nextern == null then
2322 v.add("fprintf(stderr, \"NOT YET IMPLEMENTED nitni for {mpropdef} at {location.to_s}\\n\");")
2323 v.add("exit(1);")
2324 return
2325 end
2326 externname = nextern.text.substring(1, nextern.text.length-2)
2327 if location.file != null then
2328 var file = location.file.filename
2329 v.compiler.add_extern(file)
2330 end
2331 var res: nullable RuntimeVariable = null
2332 var ret = mpropdef.msignature.return_mtype
2333 if ret != null then
2334 ret = v.resolve_for(ret, arguments.first)
2335 res = v.new_var(ret)
2336 end
2337 v.adapt_signature(mpropdef, arguments)
2338
2339 if res == null then
2340 v.add("{externname}({arguments.join(", ")});")
2341 else
2342 v.add("{res} = {externname}({arguments.join(", ")});")
2343 v.ret(res)
2344 end
2345 end
2346 end
2347
2348 redef class AExternInitPropdef
2349 redef fun compile_to_c(v, mpropdef, arguments)
2350 do
2351 var externname
2352 var nextern = self.n_extern
2353 if nextern == null then
2354 debug("{mpropdef} need extern name")
2355 return
2356 end
2357 externname = nextern.text.substring(1, nextern.text.length-2)
2358 if location.file != null then
2359 var file = location.file.filename
2360 v.compiler.add_extern(file)
2361 end
2362 v.adapt_signature(mpropdef, arguments)
2363 var ret = arguments.first.mtype
2364 var res = v.new_var(ret)
2365
2366 arguments.shift
2367
2368 v.add("{res} = {externname}({arguments.join(", ")});")
2369 v.ret(res)
2370 end
2371 end
2372
2373 redef class AAttrPropdef
2374 redef fun compile_to_c(v, mpropdef, arguments)
2375 do
2376 if arguments.length == 1 then
2377 var res = v.read_attribute(self.mpropdef.mproperty, arguments.first)
2378 v.assign(v.frame.returnvar.as(not null), res)
2379 else
2380 v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1])
2381 end
2382 end
2383
2384 fun init_expr(v: GlobalCompilerVisitor, recv: RuntimeVariable)
2385 do
2386 var nexpr = self.n_expr
2387 if nexpr != null then
2388 var oldnode = v.current_node
2389 v.current_node = self
2390 var old_frame = v.frame
2391 var frame = new Frame(v, self.mpropdef.as(not null), recv.mtype.as(MClassType), [recv])
2392 v.frame = frame
2393 var value = v.expr(nexpr, self.mpropdef.static_mtype)
2394 v.write_attribute(self.mpropdef.mproperty, recv, value)
2395 v.frame = old_frame
2396 v.current_node = oldnode
2397 end
2398 end
2399
2400 fun check_expr(v: GlobalCompilerVisitor, recv: RuntimeVariable)
2401 do
2402 var nexpr = self.n_expr
2403 if nexpr != null then return
2404
2405 var oldnode = v.current_node
2406 v.current_node = self
2407 var old_frame = v.frame
2408 var frame = new Frame(v, self.mpropdef.as(not null), recv.mtype.as(MClassType), [recv])
2409 v.frame = frame
2410 # Force read to check the initialization
2411 v.read_attribute(self.mpropdef.mproperty, recv)
2412 v.frame = old_frame
2413 v.current_node = oldnode
2414 end
2415 end
2416
2417 redef class AClassdef
2418 private fun compile_to_c(v: GlobalCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
2419 do
2420 if mpropdef == self.mfree_init then
2421 var super_inits = self.super_inits
2422 if super_inits != null then
2423 assert arguments.length == 1
2424 for su in super_inits do
2425 v.send(su, arguments)
2426 end
2427 return
2428 end
2429 var recv = arguments.first
2430 var i = 1
2431 # Collect undefined attributes
2432 for npropdef in self.n_propdefs do
2433 if npropdef isa AAttrPropdef and npropdef.n_expr == null then
2434 v.write_attribute(npropdef.mpropdef.mproperty, recv, arguments[i])
2435 i += 1
2436 end
2437 end
2438 else
2439 abort
2440 end
2441 end
2442 end
2443
2444 redef class ADeferredMethPropdef
2445 redef fun compile_to_c(v, mpropdef, arguments)
2446 do
2447 v.add_abort("Deferred method called")
2448 end
2449
2450 redef fun can_inline do return true
2451 end
2452
2453 redef class AExpr
2454 # Try to compile self as an expression
2455 # Do not call this method directly, use `v.expr' instead
2456 private fun expr(v: GlobalCompilerVisitor): nullable RuntimeVariable
2457 do
2458 v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{location.to_s}\\n\");")
2459 var mtype = self.mtype
2460 if mtype == null then
2461 return null
2462 else
2463 var res = v.new_var(mtype)
2464 v.add("/* {res} = NOT YET {class_name} */")
2465 return res
2466 end
2467 end
2468
2469 # Try to compile self as a statement
2470 # Do not call this method directly, use `v.stmt' instead
2471 private fun stmt(v: GlobalCompilerVisitor)
2472 do
2473 var res = expr(v)
2474 if res != null then v.add("{res};")
2475 end
2476
2477 end
2478
2479 redef class ABlockExpr
2480 redef fun stmt(v)
2481 do
2482 for e in self.n_expr do
2483 v.stmt(e)
2484 end
2485 end
2486 end
2487
2488 redef class AVardeclExpr
2489 redef fun stmt(v)
2490 do
2491 var variable = self.variable.as(not null)
2492 var ne = self.n_expr
2493 if ne != null then
2494 var i = v.expr(ne, variable.declared_type)
2495 v.assign(v.variable(variable), i)
2496 end
2497 end
2498 end
2499
2500 redef class AVarExpr
2501 redef fun expr(v)
2502 do
2503 var res = v.variable(self.variable.as(not null))
2504 var mtype = self.mtype.as(not null)
2505 return v.autoadapt(res, mtype)
2506 end
2507 end
2508
2509 redef class AVarAssignExpr
2510 redef fun stmt(v)
2511 do
2512 var variable = self.variable.as(not null)
2513 var i = v.expr(self.n_value, variable.declared_type)
2514 v.assign(v.variable(variable), i)
2515 end
2516 end
2517
2518 redef class AVarReassignExpr
2519 redef fun stmt(v)
2520 do
2521 var variable = self.variable.as(not null)
2522 var vari = v.variable(variable)
2523 var value = v.expr(self.n_value, variable.declared_type)
2524 var res = v.compile_callsite(self.reassign_callsite.as(not null), [vari, value])
2525 assert res != null
2526 v.assign(v.variable(variable), res)
2527 end
2528 end
2529
2530 redef class ASelfExpr
2531 redef fun expr(v)
2532 do
2533 return v.frame.arguments.first
2534 end
2535 end
2536
2537 redef class AContinueExpr
2538 redef fun stmt(v)
2539 do
2540 v.add("goto CONTINUE_{v.escapemark_name(self.escapemark)};")
2541 end
2542 end
2543
2544 redef class ABreakExpr
2545 redef fun stmt(v)
2546 do
2547 v.add("goto BREAK_{v.escapemark_name(self.escapemark)};")
2548 end
2549 end
2550
2551 redef class AReturnExpr
2552 redef fun stmt(v)
2553 do
2554 var nexpr = self.n_expr
2555 if nexpr != null then
2556 var returnvar = v.frame.returnvar.as(not null)
2557 var i = v.expr(nexpr, returnvar.mtype)
2558 v.assign(returnvar, i)
2559 end
2560 v.add("goto {v.frame.returnlabel.as(not null)};")
2561 end
2562 end
2563
2564 redef class AAbortExpr
2565 redef fun stmt(v)
2566 do
2567 v.add_abort("Aborted")
2568 end
2569 end
2570
2571 redef class AIfExpr
2572 redef fun stmt(v)
2573 do
2574 var cond = v.expr_bool(self.n_expr)
2575 v.add("if ({cond})\{")
2576 v.stmt(self.n_then)
2577 v.add("\} else \{")
2578 v.stmt(self.n_else)
2579 v.add("\}")
2580 end
2581 end
2582
2583 redef class AIfexprExpr
2584 redef fun expr(v)
2585 do
2586 var res = v.new_var(self.mtype.as(not null))
2587 var cond = v.expr_bool(self.n_expr)
2588 v.add("if ({cond})\{")
2589 v.assign(res, v.expr(self.n_then, null))
2590 v.add("\} else \{")
2591 v.assign(res, v.expr(self.n_else, null))
2592 v.add("\}")
2593 return res
2594 end
2595 end
2596
2597 redef class ADoExpr
2598 redef fun stmt(v)
2599 do
2600 v.stmt(self.n_block)
2601 var escapemark = self.escapemark
2602 if escapemark != null then
2603 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2604 end
2605 end
2606 end
2607
2608 redef class AWhileExpr
2609 redef fun stmt(v)
2610 do
2611 v.add("for(;;) \{")
2612 var cond = v.expr_bool(self.n_expr)
2613 v.add("if (!{cond}) break;")
2614 v.stmt(self.n_block)
2615 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2616 v.add("\}")
2617 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2618 end
2619 end
2620
2621 redef class ALoopExpr
2622 redef fun stmt(v)
2623 do
2624 v.add("for(;;) \{")
2625 v.stmt(self.n_block)
2626 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2627 v.add("\}")
2628 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2629 end
2630 end
2631
2632 redef class AForExpr
2633 redef fun stmt(v)
2634 do
2635 # Shortcut on explicit range
2636 # Avoid the instantiation of the range and the iterator
2637 var nexpr = self.n_expr
2638 if self.variables.length == 1 and nexpr isa AOrangeExpr and not v.compiler.modelbuilder.toolcontext.opt_no_shortcut_range.value then
2639 var from = v.expr(nexpr.n_expr, null)
2640 var to = v.expr(nexpr.n_expr2, null)
2641 var variable = v.variable(variables.first)
2642
2643 v.assign(variable, from)
2644 v.add("for(;;) \{ /* shortcut range */")
2645
2646 var ok = v.send(v.get_property("<", variable.mtype), [variable, to])
2647 assert ok != null
2648 v.add("if(!{ok}) break;")
2649
2650 v.stmt(self.n_block)
2651
2652 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2653 var succ = v.send(v.get_property("succ", variable.mtype), [variable])
2654 assert succ != null
2655 v.assign(variable, succ)
2656 v.add("\}")
2657 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2658 return
2659 end
2660
2661 var cl = v.expr(self.n_expr, null)
2662 var it_meth = self.method_iterator
2663 assert it_meth != null
2664 var it = v.send(it_meth, [cl])
2665 assert it != null
2666 v.add("for(;;) \{")
2667 var isok_meth = self.method_is_ok
2668 assert isok_meth != null
2669 var ok = v.send(isok_meth, [it])
2670 assert ok != null
2671 v.add("if(!{ok}) break;")
2672 if self.variables.length == 1 then
2673 var item_meth = self.method_item
2674 assert item_meth != null
2675 var i = v.send(item_meth, [it])
2676 assert i != null
2677 v.assign(v.variable(variables.first), i)
2678 else if self.variables.length == 2 then
2679 var key_meth = self.method_key
2680 assert key_meth != null
2681 var i = v.send(key_meth, [it])
2682 assert i != null
2683 v.assign(v.variable(variables[0]), i)
2684 var item_meth = self.method_item
2685 assert item_meth != null
2686 i = v.send(item_meth, [it])
2687 assert i != null
2688 v.assign(v.variable(variables[1]), i)
2689 else
2690 abort
2691 end
2692 v.stmt(self.n_block)
2693 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2694 var next_meth = self.method_next
2695 assert next_meth != null
2696 v.send(next_meth, [it])
2697 v.add("\}")
2698 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2699 end
2700 end
2701
2702 redef class AAssertExpr
2703 redef fun stmt(v)
2704 do
2705 if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return
2706
2707 var cond = v.expr_bool(self.n_expr)
2708 v.add("if (!{cond}) \{")
2709 v.stmt(self.n_else)
2710 var nid = self.n_id
2711 if nid != null then
2712 v.add_abort("Assert '{nid.text}' failed")
2713 else
2714 v.add_abort("Assert failed")
2715 end
2716 v.add("\}")
2717 end
2718 end
2719
2720 redef class AOrExpr
2721 redef fun expr(v)
2722 do
2723 var res = v.new_var(self.mtype.as(not null))
2724 var i1 = v.expr_bool(self.n_expr)
2725 v.add("if ({i1}) \{")
2726 v.add("{res} = 1;")
2727 v.add("\} else \{")
2728 var i2 = v.expr_bool(self.n_expr2)
2729 v.add("{res} = {i2};")
2730 v.add("\}")
2731 return res
2732 end
2733 end
2734
2735 redef class AAndExpr
2736 redef fun expr(v)
2737 do
2738 var res = v.new_var(self.mtype.as(not null))
2739 var i1 = v.expr_bool(self.n_expr)
2740 v.add("if (!{i1}) \{")
2741 v.add("{res} = 0;")
2742 v.add("\} else \{")
2743 var i2 = v.expr_bool(self.n_expr2)
2744 v.add("{res} = {i2};")
2745 v.add("\}")
2746 return res
2747 end
2748 end
2749
2750 redef class ANotExpr
2751 redef fun expr(v)
2752 do
2753 var cond = v.expr_bool(self.n_expr)
2754 return v.new_expr("!{cond}", self.mtype.as(not null))
2755 end
2756 end
2757
2758 redef class AOrElseExpr
2759 redef fun expr(v)
2760 do
2761 var res = v.new_var(self.mtype.as(not null))
2762 var i1 = v.expr(self.n_expr, null)
2763 v.add("if ({i1}!=NULL) \{")
2764 v.assign(res, i1)
2765 v.add("\} else \{")
2766 var i2 = v.expr(self.n_expr2, null)
2767 v.assign(res, i2)
2768 v.add("\}")
2769 return res
2770 end
2771 end
2772
2773 redef class AEeExpr
2774 redef fun expr(v)
2775 do
2776 var value1 = v.expr(self.n_expr, null)
2777 var value2 = v.expr(self.n_expr2, null)
2778 return v.equal_test(value1, value2)
2779 end
2780 end
2781
2782 redef class AIntExpr
2783 redef fun expr(v)
2784 do
2785 return v.new_expr("{self.n_number.text}", self.mtype.as(not null))
2786 end
2787 end
2788
2789 redef class AFloatExpr
2790 redef fun expr(v)
2791 do
2792 return v.new_expr("{self.n_float.text}", self.mtype.as(not null))
2793 end
2794 end
2795
2796 redef class ACharExpr
2797 redef fun expr(v)
2798 do
2799 return v.new_expr("{self.n_char.text}", self.mtype.as(not null))
2800 end
2801 end
2802
2803 redef class AArrayExpr
2804 redef fun expr(v)
2805 do
2806 var mtype = self.mtype.as(MClassType).arguments.first
2807 var array = new Array[RuntimeVariable]
2808 for nexpr in self.n_exprs.n_exprs do
2809 var i = v.expr(nexpr, mtype)
2810 array.add(i)
2811 end
2812 return v.array_instance(array, mtype)
2813 end
2814 end
2815
2816 redef class AStringFormExpr
2817 redef fun expr(v)
2818 do
2819 return v.string_instance(self.value.as(not null))
2820 end
2821 end
2822
2823 redef class ASuperstringExpr
2824 redef fun expr(v)
2825 do
2826 var array = new Array[RuntimeVariable]
2827 for ne in self.n_exprs do
2828 if ne isa AStringFormExpr and ne.value == "" then continue # skip empty sub-strings
2829 var i = v.expr(ne, null)
2830 array.add(i)
2831 end
2832 var a = v.array_instance(array, v.object_type)
2833 var res = v.send(v.get_property("to_s", a.mtype), [a])
2834 return res
2835 end
2836 end
2837
2838 redef class ACrangeExpr
2839 redef fun expr(v)
2840 do
2841 var i1 = v.expr(self.n_expr, null)
2842 var i2 = v.expr(self.n_expr2, null)
2843 var mtype = self.mtype.as(MClassType)
2844 var res = v.init_instance(mtype)
2845 var it = v.send(v.get_property("init", res.mtype), [res, i1, i2])
2846 v.check_init_instance(res, mtype)
2847 return res
2848 end
2849 end
2850
2851 redef class AOrangeExpr
2852 redef fun expr(v)
2853 do
2854 var i1 = v.expr(self.n_expr, null)
2855 var i2 = v.expr(self.n_expr2, null)
2856 var mtype = self.mtype.as(MClassType)
2857 var res = v.init_instance(mtype)
2858 var it = v.send(v.get_property("without_last", res.mtype), [res, i1, i2])
2859 v.check_init_instance(res, mtype)
2860 return res
2861 end
2862 end
2863
2864 redef class ATrueExpr
2865 redef fun expr(v)
2866 do
2867 return v.new_expr("1", self.mtype.as(not null))
2868 end
2869 end
2870
2871 redef class AFalseExpr
2872 redef fun expr(v)
2873 do
2874 return v.new_expr("0", self.mtype.as(not null))
2875 end
2876 end
2877
2878 redef class ANullExpr
2879 redef fun expr(v)
2880 do
2881 var res = v.new_expr("NULL", self.mtype.as(not null))
2882 return res
2883 end
2884 end
2885
2886 redef class AIsaExpr
2887 redef fun expr(v)
2888 do
2889 var i = v.expr(self.n_expr, null)
2890 return v.type_test(i, self.cast_type.as(not null), "isa")
2891 end
2892 end
2893
2894 redef class AAsCastExpr
2895 redef fun expr(v)
2896 do
2897 var i = v.expr(self.n_expr, null)
2898 if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return i
2899
2900 var cond = v.type_test(i, self.mtype.as(not null), "as")
2901 v.add("if (!{cond}) \{")
2902 v.add_abort("Cast failed")
2903 v.add("\}")
2904 return i
2905 end
2906 end
2907
2908 redef class AAsNotnullExpr
2909 redef fun expr(v)
2910 do
2911 var i = v.expr(self.n_expr, null)
2912 if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return i
2913
2914 v.add("if ({i} == NULL) \{")
2915 v.add_abort("Cast failed")
2916 v.add("\}")
2917 return i
2918 end
2919 end
2920
2921 redef class AParExpr
2922 redef fun expr(v)
2923 do
2924 return v.expr(self.n_expr, null)
2925 end
2926 end
2927
2928 redef class AOnceExpr
2929 redef fun expr(v)
2930 do
2931 var mtype = self.mtype.as(not null)
2932 var name = v.get_name("varonce")
2933 var guard = v.get_name(name + "_guard")
2934 v.add_decl("static {mtype.ctype} {name};")
2935 v.add_decl("static int {guard};")
2936 var res = v.new_var(mtype)
2937 v.add("if ({guard}) \{")
2938 v.add("{res} = {name};")
2939 v.add("\} else \{")
2940 var i = v.expr(self.n_expr, mtype)
2941 v.add("{res} = {i};")
2942 v.add("{name} = {res};")
2943 v.add("{guard} = 1;")
2944 v.add("\}")
2945 return res
2946 end
2947 end
2948
2949 redef class ASendExpr
2950 redef fun expr(v)
2951 do
2952 var recv = v.expr(self.n_expr, null)
2953 var args = [recv]
2954 for a in self.raw_arguments.as(not null) do
2955 args.add(v.expr(a, null))
2956 end
2957 return v.compile_callsite(self.callsite.as(not null), args)
2958 end
2959 end
2960
2961 redef class ASendReassignFormExpr
2962 redef fun stmt(v)
2963 do
2964 var recv = v.expr(self.n_expr, null)
2965 var args = [recv]
2966 for a in self.raw_arguments.as(not null) do
2967 args.add(v.expr(a, null))
2968 end
2969 var value = v.expr(self.n_value, null)
2970
2971 var left = v.compile_callsite(self.callsite.as(not null), args)
2972 assert left != null
2973
2974 var res = v.compile_callsite(self.reassign_callsite.as(not null), [left, value])
2975 assert res != null
2976
2977 args.add(res)
2978 v.compile_callsite(self.write_callsite.as(not null), args)
2979 end
2980 end
2981
2982 redef class ASuperExpr
2983 redef fun expr(v)
2984 do
2985 var recv = v.frame.arguments.first
2986 var args = [recv]
2987 for a in self.n_args.n_exprs do
2988 args.add(v.expr(a, null))
2989 end
2990 if args.length == 1 then
2991 args = v.frame.arguments
2992 end
2993
2994 var mproperty = self.mproperty
2995 if mproperty != null then
2996 if mproperty.intro.msignature.arity == 0 then
2997 args = [recv]
2998 end
2999 # Super init call
3000 var res = v.send(mproperty, args)
3001 return res
3002 end
3003
3004 # stantard call-next-method
3005 var mpropdef = v.frame.mpropdef
3006 # FIXME: we do not want an ugly static call!
3007 var mpropdefs = mpropdef.mproperty.lookup_super_definitions(mpropdef.mclassdef.mmodule, mpropdef.mclassdef.bound_mtype)
3008 if mpropdefs.length != 1 then
3009 v.add("printf(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");")
3010 debug("MPRODFEFS for super {mpropdef} for {recv}: {mpropdefs.join(", ")}")
3011 end
3012 mpropdef = mpropdefs.first
3013 assert mpropdef isa MMethodDef
3014 var res = v.call(mpropdef, recv.mtype.as(MClassType), args)
3015 return res
3016 end
3017 end
3018
3019 redef class ANewExpr
3020 redef fun expr(v)
3021 do
3022 var mtype = self.mtype.as(MClassType)
3023 var recv
3024 var ctype = mtype.ctype
3025 if ctype == "val*" then
3026 recv = v.init_instance(mtype)
3027 else if ctype == "void*" then
3028 recv = v.new_expr("NULL/*special!*/", mtype)
3029 else
3030 debug("cannot new {mtype}")
3031 abort
3032 end
3033 var args = [recv]
3034 for a in self.n_args.n_exprs do
3035 args.add(v.expr(a, null))
3036 end
3037 var res2 = v.compile_callsite(self.callsite.as(not null), args)
3038 if res2 != null then
3039 #self.debug("got {res2} from {mproperty}. drop {recv}")
3040 return res2
3041 end
3042 v.check_init_instance(recv, mtype)
3043 return recv
3044 end
3045 end
3046
3047 redef class AAttrExpr
3048 redef fun expr(v)
3049 do
3050 var recv = v.expr(self.n_expr, null)
3051 var mproperty = self.mproperty.as(not null)
3052 return v.read_attribute(mproperty, recv)
3053 end
3054 end
3055
3056 redef class AAttrAssignExpr
3057 redef fun stmt(v)
3058 do
3059 var recv = v.expr(self.n_expr, null)
3060 var i = v.expr(self.n_value, null)
3061 var mproperty = self.mproperty.as(not null)
3062 v.write_attribute(mproperty, recv, i)
3063 end
3064 end
3065
3066 redef class AAttrReassignExpr
3067 redef fun stmt(v)
3068 do
3069 var recv = v.expr(self.n_expr, null)
3070 var value = v.expr(self.n_value, null)
3071 var mproperty = self.mproperty.as(not null)
3072 var attr = v.read_attribute(mproperty, recv)
3073 var res = v.compile_callsite(self.reassign_callsite.as(not null), [attr, value])
3074 assert res != null
3075 v.write_attribute(mproperty, recv, res)
3076 end
3077 end
3078
3079 redef class AIssetAttrExpr
3080 redef fun expr(v)
3081 do
3082 var recv = v.expr(self.n_expr, null)
3083 var mproperty = self.mproperty.as(not null)
3084 return v.isset_attribute(mproperty, recv)
3085 end
3086 end
3087
3088 redef class ADebugTypeExpr
3089 redef fun stmt(v)
3090 do
3091 # do nothing
3092 end
3093 end