nitg: add class CodeWriter
[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 abstract_compiler
27 import rapid_type_analysis
28
29 redef class ModelBuilder
30 # Entry point to performs a global compilation on the AST of a complete program.
31 # `mainmodule` is the main module of the program
32 # `runtime_type_analysis` is a already computer type analysis.
33 fun run_global_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis)
34 do
35 var time0 = get_time
36 self.toolcontext.info("*** COMPILING TO C ***", 1)
37
38 var compiler = new GlobalCompiler(mainmodule, self, runtime_type_analysis)
39 compiler.compile_header
40 var v = compiler.header
41
42 for t in runtime_type_analysis.live_types do
43 compiler.declare_runtimeclass(v, t)
44 end
45
46 compiler.compile_class_names
47
48 # Init instance code (allocate and init-arguments)
49 for t in runtime_type_analysis.live_types do
50 if t.ctype == "val*" then
51 compiler.generate_init_instance(t)
52 compiler.generate_check_init_instance(t)
53 else
54 compiler.generate_box_instance(t)
55 end
56 end
57
58 # The main function of the C
59 compiler.compile_main_function
60
61 # Compile until all runtime_functions are visited
62 while not compiler.todos.is_empty do
63 var m = compiler.todos.shift
64 self.toolcontext.info("Compile {m} ({compiler.seen.length-compiler.todos.length}/{compiler.seen.length})", 3)
65 m.compile_to_c(compiler)
66 end
67 self.toolcontext.info("Total methods to compile to C: {compiler.writers.length}", 2)
68
69 compiler.display_stats
70
71 var time1 = get_time
72 self.toolcontext.info("*** END VISITING: {time1-time0} ***", 2)
73 write_and_make(compiler)
74 end
75 end
76
77 # Compiler that use global compilation and perform hard optimisations like:
78 # * customization
79 # * switch dispatch
80 # * inlining
81 class GlobalCompiler
82 super AbstractCompiler
83
84 redef type VISITOR: GlobalCompilerVisitor
85
86 # The result of the RTA (used to know live types and methods)
87 var runtime_type_analysis: RapidTypeAnalysis
88
89 init(mainmodule: MModule, modelbuilder: ModelBuilder, runtime_type_analysis: RapidTypeAnalysis)
90 do
91 super(mainmodule, modelbuilder)
92 self.runtime_type_analysis = runtime_type_analysis
93 self.live_primitive_types = new Array[MClassType]
94 for t in runtime_type_analysis.live_types do
95 if t.ctype != "val*" then
96 self.live_primitive_types.add(t)
97 end
98 end
99 end
100
101 # Compile class names (for the class_name and output_class_name methods)
102 protected fun compile_class_names do
103 self.header.add_decl("extern const char const * class_names[];")
104 self.header.add("const char const * class_names[] = \{")
105 for t in self.runtime_type_analysis.live_types do
106 self.header.add("\"{t}\", /* {self.classid(t)} */")
107 end
108 self.header.add("\};")
109 end
110
111 # Return the C symbol associated to a live type runtime
112 # REQUIRE: self.runtime_type_analysis.live_types.has(mtype)
113 fun classid(mtype: MClassType): String
114 do
115 if self.classids.has_key(mtype) then
116 return self.classids[mtype]
117 end
118 print "No classid for {mtype}"
119 abort
120 end
121
122 # Cache for classid
123 protected var classids: HashMap[MClassType, String] = new HashMap[MClassType, String]
124
125 # Declaration of structures the live Nit types
126 # Each live type is generated as an independent C `struct' type.
127 # They only share a common first field `classid` used to implement the polymorphism.
128 # Usualy, all C variables that refers to a Nit object are typed on the abstract struct `val' that contains only the `classid` field.
129 redef fun compile_header_structs do
130 self.header.add_decl("typedef struct \{int classid;\} val; /* general C type representing a Nit instance. */")
131 end
132
133 # Subset of runtime_type_analysis.live_types that contains only primitive types
134 # Used to implement the equal test
135 var live_primitive_types: Array[MClassType]
136
137 # Add a new todo task
138 fun todo(m: AbstractRuntimeFunction)
139 do
140 if seen.has(m) then return
141 todos.add(m)
142 seen.add(m)
143 end
144
145 # runtime_functions that need to be compiled
146 private var todos: List[AbstractRuntimeFunction] = new List[AbstractRuntimeFunction]
147
148 # runtime_functions already seen (todo or done)
149 private var seen: HashSet[AbstractRuntimeFunction] = new HashSet[AbstractRuntimeFunction]
150
151 # Declare C structures and identifiers for a runtime class
152 fun declare_runtimeclass(v: CodeWriter, mtype: MClassType)
153 do
154 assert self.runtime_type_analysis.live_types.has(mtype)
155 v.add_decl("/* runtime class {mtype} */")
156 var idnum = classids.length
157 var idname = "ID_" + mtype.c_name
158 self.classids[mtype] = idname
159 v.add_decl("#define {idname} {idnum} /* {mtype} */")
160
161 v.add_decl("struct {mtype.c_name} \{")
162 v.add_decl("int classid; /* must be {idname} */")
163
164 if mtype.mclass.name == "NativeArray" then
165 # NativeArrays are just a instance header followed by an array of values
166 v.add_decl("{mtype.arguments.first.ctype} values[1];")
167 end
168
169 if mtype.ctype != "val*" then
170 # Is the Nit type is native then the struct is a box with two fields:
171 # * the `classid` to be polymorph
172 # * the `value` that contains the native value.
173 v.add_decl("{mtype.ctype} value;")
174 end
175
176 # Collect all attributes and associate them a field in the structure.
177 # Note: we do not try to optimize the order and helps CC to optimize the client code.
178 for cd in mtype.collect_mclassdefs(self.mainmodule) do
179 for p in cd.intro_mproperties do
180 if not p isa MAttribute then continue
181 var t = p.intro.static_mtype.as(not null)
182 t = t.anchor_to(self.mainmodule, mtype)
183 v.add_decl("{t.ctype} {p.intro.c_name}; /* {p}: {t} */")
184 end
185 end
186 v.add_decl("\};")
187 end
188
189 # Generate the init-instance of a live type (allocate + init-instance)
190 fun generate_init_instance(mtype: MClassType)
191 do
192 assert self.runtime_type_analysis.live_types.has(mtype)
193 assert mtype.ctype == "val*"
194 var v = self.new_visitor
195
196 var is_native_array = mtype.mclass.name == "NativeArray"
197
198 var sig
199 if is_native_array then
200 sig = "int length"
201 else
202 sig = "void"
203 end
204
205 self.header.add_decl("{mtype.ctype} NEW_{mtype.c_name}({sig});")
206 v.add_decl("/* allocate {mtype} */")
207 v.add_decl("{mtype.ctype} NEW_{mtype.c_name}({sig}) \{")
208 var res = v.new_var(mtype)
209 res.is_exact = true
210 if is_native_array then
211 var mtype_elt = mtype.arguments.first
212 v.add("{res} = GC_MALLOC(sizeof(struct {mtype.c_name}) + length*sizeof({mtype_elt.ctype}));")
213 else
214 v.add("{res} = GC_MALLOC(sizeof(struct {mtype.c_name}));")
215 end
216 v.add("{res}->classid = {self.classid(mtype)};")
217
218 self.generate_init_attr(v, res, mtype)
219 v.add("return {res};")
220 v.add("\}")
221 end
222
223 redef fun generate_check_init_instance(mtype)
224 do
225 if self.modelbuilder.toolcontext.opt_no_check_initialization.value then return
226
227 var v = self.new_visitor
228 var res = new RuntimeVariable("self", mtype, mtype)
229 self.header.add_decl("void CHECK_NEW_{mtype.c_name}({mtype.ctype});")
230 v.add_decl("/* allocate {mtype} */")
231 v.add_decl("void CHECK_NEW_{mtype.c_name}({mtype.ctype} {res}) \{")
232 self.generate_check_attr(v, res, mtype)
233 v.add("\}")
234 end
235
236 fun generate_box_instance(mtype: MClassType)
237 do
238 assert self.runtime_type_analysis.live_types.has(mtype)
239 assert mtype.ctype != "val*"
240 var v = self.new_visitor
241
242 self.header.add_decl("val* BOX_{mtype.c_name}({mtype.ctype});")
243 v.add_decl("/* allocate {mtype} */")
244 v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value) \{")
245 v.add("struct {mtype.c_name}*res = GC_MALLOC(sizeof(struct {mtype.c_name}));")
246 v.add("res->classid = {self.classid(mtype)};")
247 v.add("res->value = value;")
248 v.add("return (val*)res;")
249 v.add("\}")
250
251 end
252
253 redef fun new_visitor do return new GlobalCompilerVisitor(self)
254
255 private var collect_types_cache: HashMap[MType, Array[MClassType]] = new HashMap[MType, Array[MClassType]]
256 end
257
258 # A visitor on the AST of property definition that generate the C code.
259 # Because of inlining, a visitor can visit more than one property.
260 class GlobalCompilerVisitor
261 super AbstractCompilerVisitor
262
263 redef type COMPILER: GlobalCompiler
264
265 redef fun autobox(value, mtype)
266 do
267 if value.mtype == mtype then
268 return value
269 else if value.mtype.ctype == "val*" and mtype.ctype == "val*" then
270 return value
271 else if value.mtype.ctype == "val*" then
272 return self.new_expr("((struct {mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
273 else if mtype.ctype == "val*" then
274 var valtype = value.mtype.as(MClassType)
275 var res = self.new_var(mtype)
276 if not compiler.runtime_type_analysis.live_types.has(valtype) then
277 self.add("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */")
278 self.add("printf(\"Dead code executed!\\n\"); exit(1);")
279 return res
280 end
281 self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
282 return res
283 else
284 # Bad things will appen!
285 var res = self.new_var(mtype)
286 self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */")
287 self.add("printf(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); exit(1);")
288 return res
289 end
290 end
291
292 # The runtime types that are acceptable for a given receiver.
293 fun collect_types(recv: RuntimeVariable): Array[MClassType]
294 do
295 var mtype = recv.mcasttype
296 if recv.is_exact then
297 assert mtype isa MClassType
298 assert self.compiler.runtime_type_analysis.live_types.has(mtype)
299 var types = [mtype]
300 return types
301 end
302 var cache = self.compiler.collect_types_cache
303 if cache.has_key(mtype) then
304 return cache[mtype]
305 end
306 var types = new Array[MClassType]
307 var mainmodule = self.compiler.mainmodule
308 for t in self.compiler.runtime_type_analysis.live_types do
309 if not t.is_subtype(mainmodule, null, mtype) then continue
310 types.add(t)
311 end
312 cache[mtype] = types
313 return types
314 end
315
316 redef fun native_array_def(pname, ret_type, arguments)
317 do
318 var elttype = arguments.first.mtype
319 var recv = "((struct {arguments[0].mcasttype.c_name}*){arguments[0]})->values"
320 if pname == "[]" then
321 self.ret(self.new_expr("{recv}[{arguments[1]}]", ret_type.as(not null)))
322 return
323 else if pname == "[]=" then
324 self.add("{recv}[{arguments[1]}]={arguments[2]};")
325 return
326 else if pname == "copy_to" then
327 var recv1 = "((struct {arguments[1].mcasttype.c_name}*){arguments[1]})->values"
328 self.add("memcpy({recv1},{recv},{arguments[2]}*sizeof({elttype.ctype}));")
329 return
330 end
331 end
332
333 redef fun calloc_array(ret_type, arguments)
334 do
335 self.ret(self.new_expr("NEW_{ret_type.c_name}({arguments[1]})", ret_type))
336 end
337
338 redef fun send(m, args)
339 do
340 var types = self.collect_types(args.first)
341
342 var res: nullable RuntimeVariable
343 var ret = m.intro.msignature.return_mtype
344 if m.is_new then
345 ret = args.first.mtype
346 res = self.new_var(ret)
347 else if ret == null then
348 res = null
349 else
350 ret = self.resolve_for(ret, args.first)
351 res = self.new_var(ret)
352 end
353
354 self.add("/* send {m} on {args.first.inspect} */")
355 if args.first.mtype.ctype != "val*" then
356 var mclasstype = args.first.mtype.as(MClassType)
357 if not self.compiler.runtime_type_analysis.live_types.has(mclasstype) then
358 self.add("/* skip, no method {m} */")
359 return res
360 end
361 var propdef = m.lookup_first_definition(self.compiler.mainmodule, mclasstype)
362 var res2 = self.call(propdef, mclasstype, args)
363 if res != null then self.assign(res, res2.as(not null))
364 return res
365 end
366 var consider_null = not self.compiler.modelbuilder.toolcontext.opt_no_check_other.value or m.name == "==" or m.name == "!="
367 if args.first.mcasttype isa MNullableType or args.first.mcasttype isa MNullType and consider_null then
368 # The reciever is potentially null, so we have to 3 cases: ==, != or NullPointerException
369 self.add("if ({args.first} == NULL) \{ /* Special null case */")
370 if m.name == "==" then
371 assert res != null
372 if args[1].mcasttype isa MNullableType then
373 self.add("{res} = ({args[1]} == NULL);")
374 else if args[1].mcasttype isa MNullType then
375 self.add("{res} = 1; /* is null */")
376 else
377 self.add("{res} = 0; /* {args[1].inspect} cannot be null */")
378 end
379 else if m.name == "!=" then
380 assert res != null
381 if args[1].mcasttype isa MNullableType then
382 self.add("{res} = ({args[1]} != NULL);")
383 else if args[1].mcasttype isa MNullType then
384 self.add("{res} = 0; /* is null */")
385 else
386 self.add("{res} = 1; /* {args[1].inspect} cannot be null */")
387 end
388 else
389 self.add_abort("Reciever is null")
390 end
391 self.add "\} else"
392 end
393 if types.is_empty then
394 self.add("\{")
395 self.add("/*BUG: no live types for {args.first.inspect} . {m}*/")
396 self.bugtype(args.first)
397 self.add("\}")
398 return res
399 end
400
401 self.add("switch({args.first}->classid) \{")
402 var last = types.last
403 var defaultpropdef: nullable MMethodDef = null
404 for t in types do
405 var propdef = m.lookup_first_definition(self.compiler.mainmodule, t)
406 if propdef.mclassdef.mclass.name == "Object" and t.ctype == "val*" then
407 defaultpropdef = propdef
408 continue
409 end
410 if not self.compiler.hardening and t == last and defaultpropdef == null then
411 self.add("default: /* test {t} */")
412 else
413 self.add("case {self.compiler.classid(t)}: /* test {t} */")
414 end
415 var res2 = self.call(propdef, t, args)
416 if res != null then self.assign(res, res2.as(not null))
417 self.add "break;"
418 end
419 if defaultpropdef != null then
420 self.add("default: /* default is Object */")
421 var res2 = self.call(defaultpropdef, defaultpropdef.mclassdef.bound_mtype, args)
422 if res != null then self.assign(res, res2.as(not null))
423 else if self.compiler.hardening then
424 self.add("default: /* bug */")
425 self.bugtype(args.first)
426 end
427 self.add("\}")
428 return res
429 end
430
431 fun check_valid_reciever(recvtype: MClassType)
432 do
433 if self.compiler.runtime_type_analysis.live_types.has(recvtype) or recvtype.mclass.name == "Object" then return
434 print "{recvtype} is not a live type"
435 abort
436 end
437
438 redef fun call(m, recvtype, args)
439 do
440 check_valid_reciever(recvtype)
441 #debug("call {m} on {recvtype} on {args.first}:{args.first.mtype}")
442 if m.mclassdef.mclass.name == "Object" and recvtype.ctype == "val*" then
443 recvtype = m.mclassdef.bound_mtype
444 end
445 var recv = self.autobox(args.first, recvtype)
446 recv = self.autoadapt(recv, recvtype)
447
448 args = args.to_a
449 self.varargize(m, m.msignature.as(not null), args)
450 if args.length != m.msignature.arity + 1 then # because of self
451 add("printf(\"NOT YET IMPLEMENTED: Invalid arity for {m}. {args.length} arguments given.\\n\"); exit(1);")
452 debug("NOT YET IMPLEMENTED: Invalid arity for {m}. {args.length} arguments given.")
453 return null
454 end
455
456 args.first = recv
457 var rm = new CustomizedRuntimeFunction(m, recvtype)
458 return rm.call(self, args)
459 end
460
461 redef fun supercall(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable
462 do
463 var types = self.collect_types(args.first)
464
465 var res: nullable RuntimeVariable
466 var ret = m.mproperty.intro.msignature.return_mtype
467 if ret == null then
468 res = null
469 else
470 ret = self.resolve_for(ret, args.first)
471 res = self.new_var(ret)
472 end
473
474 self.add("/* super {m} on {args.first.inspect} */")
475 if args.first.mtype.ctype != "val*" then
476 var mclasstype = args.first.mtype.as(MClassType)
477 if not self.compiler.runtime_type_analysis.live_types.has(mclasstype) then
478 self.add("/* skip, no method {m} */")
479 return res
480 end
481 var propdef = m.lookup_next_definition(self.compiler.mainmodule, mclasstype)
482 var res2 = self.call(propdef, mclasstype, args)
483 if res != null then self.assign(res, res2.as(not null))
484 return res
485 end
486
487 if types.is_empty then
488 self.add("\{")
489 self.add("/*BUG: no live types for {args.first.inspect} . {m}*/")
490 self.bugtype(args.first)
491 self.add("\}")
492 return res
493 end
494
495 self.add("switch({args.first}->classid) \{")
496 var last = types.last
497 for t in types do
498 var propdef = m.lookup_next_definition(self.compiler.mainmodule, t)
499 if not self.compiler.hardening and t == last then
500 self.add("default: /* test {t} */")
501 else
502 self.add("case {self.compiler.classid(t)}: /* test {t} */")
503 end
504 var res2 = self.call(propdef, t, args)
505 if res != null then self.assign(res, res2.as(not null))
506 self.add "break;"
507 end
508 if self.compiler.hardening then
509 self.add("default: /* bug */")
510 self.bugtype(args.first)
511 end
512 self.add("\}")
513 return res
514 end
515
516 redef fun adapt_signature(m, args)
517 do
518 var recv = args.first
519 for i in [0..m.msignature.arity[ do
520 var t = m.msignature.mparameters[i].mtype
521 if i == m.msignature.vararg_rank then
522 t = args[i+1].mtype
523 end
524 t = self.resolve_for(t, recv)
525 args[i+1] = self.autobox(args[i+1], t)
526 end
527 end
528
529 # FIXME: this is currently buggy since recv is not exact
530 redef fun vararg_instance(mpropdef, recv, varargs, elttype)
531 do
532 elttype = self.resolve_for(elttype, recv)
533 return self.array_instance(varargs, elttype)
534 end
535
536 fun bugtype(recv: RuntimeVariable)
537 do
538 if recv.mtype.ctype != "val*" then return
539 self.add("fprintf(stderr, \"BTD BUG: Dynamic type is %s, static type is %s\\n\", class_names[{recv}->classid], \"{recv.mcasttype}\");")
540 self.add("exit(1);")
541 end
542
543 redef fun isset_attribute(a, recv)
544 do
545 check_recv_notnull(recv)
546
547 var types = self.collect_types(recv)
548 var res = self.new_var(bool_type)
549
550 if types.is_empty then
551 self.add("/*BUG: no live types for {recv.inspect} . {a}*/")
552 self.bugtype(recv)
553 return res
554 end
555 self.add("/* isset {a} on {recv.inspect} */")
556 self.add("switch({recv}->classid) \{")
557 var last = types.last
558 for t in types do
559 if not self.compiler.hardening and t == last then
560 self.add("default: /*{self.compiler.classid(t)}*/")
561 else
562 self.add("case {self.compiler.classid(t)}:")
563 end
564 var recv2 = self.autoadapt(recv, t)
565 var ta = a.intro.static_mtype.as(not null)
566 ta = self.resolve_for(ta, recv2)
567 var attr = self.new_expr("((struct {t.c_name}*){recv})->{a.intro.c_name}", ta)
568 if not ta isa MNullableType then
569 if ta.ctype == "val*" then
570 self.add("{res} = ({attr} != NULL);")
571 else
572 self.add("{res} = 1; /*NOTYET isset on primitive attributes*/")
573 end
574 end
575 self.add("break;")
576 end
577 if self.compiler.hardening then
578 self.add("default: /* Bug */")
579 self.bugtype(recv)
580 end
581 self.add("\}")
582
583 return res
584 end
585
586 redef fun read_attribute(a, recv)
587 do
588 check_recv_notnull(recv)
589
590 var types = self.collect_types(recv)
591
592 var ret = a.intro.static_mtype.as(not null)
593 ret = self.resolve_for(ret, recv)
594 var res = self.new_var(ret)
595
596 if types.is_empty then
597 self.add("/*BUG: no live types for {recv.inspect} . {a}*/")
598 self.bugtype(recv)
599 return res
600 end
601 self.add("/* read {a} on {recv.inspect} */")
602 self.add("switch({recv}->classid) \{")
603 var last = types.last
604 for t in types do
605 if not self.compiler.hardening and t == last then
606 self.add("default: /*{self.compiler.classid(t)}*/")
607 else
608 self.add("case {self.compiler.classid(t)}:")
609 end
610 var recv2 = self.autoadapt(recv, t)
611 var ta = a.intro.static_mtype.as(not null)
612 ta = self.resolve_for(ta, recv2)
613 var res2 = self.new_expr("((struct {t.c_name}*){recv})->{a.intro.c_name}", ta)
614 if not ta isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_other.value then
615 if ta.ctype == "val*" then
616 self.add("if ({res2} == NULL) \{")
617 self.add_abort("Uninitialized attribute {a.name}")
618 self.add("\}")
619 else
620 self.add("/*NOTYET isset on primitive attributes*/")
621 end
622 end
623 self.assign(res, res2)
624 self.add("break;")
625 end
626 if self.compiler.hardening then
627 self.add("default: /* Bug */")
628 self.bugtype(recv)
629 end
630 self.add("\}")
631
632 return res
633 end
634
635 redef fun write_attribute(a, recv, value)
636 do
637 check_recv_notnull(recv)
638
639 var types = self.collect_types(recv)
640
641 if types.is_empty then
642 self.add("/*BUG: no live types for {recv.inspect} . {a}*/")
643 self.bugtype(recv)
644 return
645 end
646 self.add("/* write {a} on {recv.inspect} */")
647 self.add("switch({recv}->classid) \{")
648 var last = types.last
649 for t in types do
650 if not self.compiler.hardening and t == last then
651 self.add("default: /*{self.compiler.classid(t)}*/")
652 else
653 self.add("case {self.compiler.classid(t)}:")
654 end
655 var recv2 = self.autoadapt(recv, t)
656 var ta = a.intro.static_mtype.as(not null)
657 ta = self.resolve_for(ta, recv2)
658 self.add("((struct {t.c_name}*){recv})->{a.intro.c_name} = {self.autobox(value, ta)};")
659 self.add("break;")
660 end
661 if self.compiler.hardening then
662 self.add("default: /* Bug*/")
663 self.bugtype(recv)
664 end
665 self.add("\}")
666 end
667
668 redef fun init_instance(mtype)
669 do
670 mtype = self.anchor(mtype).as(MClassType)
671 if not self.compiler.runtime_type_analysis.live_types.has(mtype) then
672 debug "problem: {mtype} was detected dead"
673 end
674 var res = self.new_expr("NEW_{mtype.c_name}()", mtype)
675 res.is_exact = true
676 return res
677 end
678
679 redef fun type_test(value, mtype, tag)
680 do
681 mtype = self.anchor(mtype)
682 var mclasstype = mtype
683 if mtype isa MNullableType then mclasstype = mtype.mtype
684 assert mclasstype isa MClassType
685 if not self.compiler.runtime_type_analysis.live_cast_types.has(mclasstype) then
686 debug "problem: {mtype} was detected cast-dead"
687 abort
688 end
689
690 var types = self.collect_types(value)
691 var res = self.new_var(bool_type)
692
693 self.add("/* isa {mtype} on {value.inspect} */")
694 if value.mtype.ctype != "val*" then
695 if value.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then
696 self.add("{res} = 1;")
697 else
698 self.add("{res} = 0;")
699 end
700 return res
701 end
702 if value.mcasttype isa MNullableType or value.mcasttype isa MNullType then
703 self.add("if ({value} == NULL) \{")
704 if mtype isa MNullableType then
705 self.add("{res} = 1; /* isa {mtype} */")
706 else
707 self.add("{res} = 0; /* not isa {mtype} */")
708 end
709 self.add("\} else ")
710 end
711 self.add("switch({value}->classid) \{")
712 for t in types do
713 if t.is_subtype(self.compiler.mainmodule, null, mtype) then
714 self.add("case {self.compiler.classid(t)}: /* {t} */")
715 end
716 end
717 self.add("{res} = 1;")
718 self.add("break;")
719 self.add("default:")
720 self.add("{res} = 0;")
721 self.add("\}")
722
723 return res
724 end
725
726 redef fun is_same_type_test(value1, value2)
727 do
728 var res = self.new_var(bool_type)
729 if value2.mtype.ctype == "val*" then
730 if value1.mtype.ctype == "val*" then
731 self.add "{res} = {value1}->classid == {value2}->classid;"
732 else
733 self.add "{res} = {self.compiler.classid(value1.mtype.as(MClassType))} == {value2}->classid;"
734 end
735 else
736 if value1.mtype.ctype == "val*" then
737 self.add "{res} = {value1}->classid == {self.compiler.classid(value2.mtype.as(MClassType))};"
738 else if value1.mcasttype == value2.mcasttype then
739 self.add "{res} = 1;"
740 else
741 self.add "{res} = 0;"
742 end
743 end
744 return res
745 end
746
747 redef fun class_name_string(value)
748 do
749 var res = self.get_name("var_class_name")
750 self.add_decl("const char* {res};")
751 if value.mtype.ctype == "val*" then
752 self.add "{res} = class_names[{value}->classid];"
753 else
754 self.add "{res} = class_names[{self.compiler.classid(value.mtype.as(MClassType))}];"
755 end
756 return res
757 end
758
759 redef fun equal_test(value1, value2)
760 do
761 var res = self.new_var(bool_type)
762 if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
763 var tmp = value1
764 value1 = value2
765 value2 = tmp
766 end
767 if value1.mtype.ctype != "val*" then
768 if value2.mtype == value1.mtype then
769 self.add("{res} = {value1} == {value2};")
770 else if value2.mtype.ctype != "val*" then
771 self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
772 else
773 var mtype1 = value1.mtype.as(MClassType)
774 self.add("{res} = ({value2} != NULL) && ({value2}->classid == {self.compiler.classid(mtype1)});")
775 self.add("if ({res}) \{")
776 self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
777 self.add("\}")
778 end
779 else
780 var s = new Array[String]
781 for t in self.compiler.live_primitive_types do
782 if not t.is_subtype(self.compiler.mainmodule, null, value1.mcasttype) then continue
783 if not t.is_subtype(self.compiler.mainmodule, null, value2.mcasttype) then continue
784 s.add "({value1}->classid == {self.compiler.classid(t)} && ((struct {t.c_name}*){value1})->value == ((struct {t.c_name}*){value2})->value)"
785 end
786 if s.is_empty then
787 self.add("{res} = {value1} == {value2};")
788 else
789 self.add("{res} = {value1} == {value2} || ({value1} != NULL && {value2} != NULL && {value1}->classid == {value2}->classid && ({s.join(" || ")}));")
790 end
791 end
792 return res
793 end
794
795 redef fun check_init_instance(recv, mtype)
796 do
797 if self.compiler.modelbuilder.toolcontext.opt_no_check_initialization.value then return
798
799 mtype = self.anchor(mtype).as(MClassType)
800 if not self.compiler.runtime_type_analysis.live_types.has(mtype) then
801 debug "problem: {mtype} was detected dead"
802 end
803
804 self.add("CHECK_NEW_{mtype.c_name}({recv});")
805 end
806
807 redef fun array_instance(array, elttype)
808 do
809 elttype = self.anchor(elttype)
810 var arraytype = self.get_class("Array").get_mtype([elttype])
811 var res = self.init_instance(arraytype)
812 self.add("\{ /* {res} = array_instance Array[{elttype}] */")
813 var nat = self.new_var(self.get_class("NativeArray").get_mtype([elttype]))
814 nat.is_exact = true
815 self.add("{nat} = NEW_{nat.mtype.c_name}({array.length});")
816 for i in [0..array.length[ do
817 var r = self.autobox(array[i], elttype)
818 self.add("((struct {nat.mtype.c_name}*) {nat})->values[{i}] = {r};")
819 end
820 var length = self.int_instance(array.length)
821 self.send(self.get_property("with_native", arraytype), [res, nat, length])
822 self.check_init_instance(res, arraytype)
823 self.add("\}")
824 return res
825 end
826 end
827
828 # A runtime function customized on a specific monomrph receiver type
829 private class CustomizedRuntimeFunction
830 super AbstractRuntimeFunction
831
832 redef type COMPILER: GlobalCompiler
833 redef type VISITOR: GlobalCompilerVisitor
834
835 # The considered reciever
836 # (usually is a live type but no strong guarantee)
837 var recv: MClassType
838
839 init(mmethoddef: MMethodDef, recv: MClassType)
840 do
841 super(mmethoddef)
842 self.recv = recv
843 end
844
845 redef fun build_c_name
846 do
847 var res = self.c_name_cache
848 if res != null then return res
849 if self.mmethoddef.mclassdef.bound_mtype == self.recv then
850 res = self.mmethoddef.c_name
851 else
852 res = "{mmethoddef.c_name}__{recv.c_name}"
853 end
854 self.c_name_cache = res
855 return res
856 end
857
858 # used in the compiler worklist
859 redef fun ==(o)
860 do
861 if not o isa CustomizedRuntimeFunction then return false
862 if self.mmethoddef != o.mmethoddef then return false
863 if self.recv != o.recv then return false
864 return true
865 end
866
867 # used in the compiler work-list
868 redef fun hash do return self.mmethoddef.hash + self.recv.hash
869
870 redef fun to_s
871 do
872 if self.mmethoddef.mclassdef.bound_mtype == self.recv then
873 return self.mmethoddef.to_s
874 else
875 return "{self.mmethoddef}@{self.recv}"
876 end
877 end
878
879 # compile the code customized for the reciever
880 redef fun compile_to_c(compiler)
881 do
882 var recv = self.recv
883 var mmethoddef = self.mmethoddef
884 if not recv.is_subtype(compiler.mainmodule, null, mmethoddef.mclassdef.bound_mtype) then
885 print("problem: why do we compile {self} for {recv}?")
886 abort
887 end
888
889 var v = compiler.new_visitor
890 var selfvar = new RuntimeVariable("self", recv, recv)
891 if compiler.runtime_type_analysis.live_types.has(recv) then
892 selfvar.is_exact = true
893 end
894 var arguments = new Array[RuntimeVariable]
895 var frame = new Frame(v, mmethoddef, recv, arguments)
896 v.frame = frame
897
898 var sig = new Buffer
899 var comment = new Buffer
900 var ret = mmethoddef.msignature.return_mtype
901 if ret != null then
902 ret = v.resolve_for(ret, selfvar)
903 sig.append("{ret.ctype} ")
904 else if mmethoddef.mproperty.is_new then
905 ret = recv
906 sig.append("{ret.ctype} ")
907 else
908 sig.append("void ")
909 end
910 sig.append(self.c_name)
911 sig.append("({recv.ctype} {selfvar}")
912 comment.append("(self: {recv}")
913 arguments.add(selfvar)
914 for i in [0..mmethoddef.msignature.arity[ do
915 var mtype = mmethoddef.msignature.mparameters[i].mtype
916 if i == mmethoddef.msignature.vararg_rank then
917 mtype = v.get_class("Array").get_mtype([mtype])
918 end
919 mtype = v.resolve_for(mtype, selfvar)
920 comment.append(", {mtype}")
921 sig.append(", {mtype.ctype} p{i}")
922 var argvar = new RuntimeVariable("p{i}", mtype, mtype)
923 arguments.add(argvar)
924 end
925 sig.append(")")
926 comment.append(")")
927 if ret != null then
928 comment.append(": {ret}")
929 end
930 compiler.header.add_decl("{sig};")
931
932 v.add_decl("/* method {self} for {comment} */")
933 v.add_decl("{sig} \{")
934 #v.add("printf(\"method {self} for {comment}\\n\");")
935 if ret != null then
936 frame.returnvar = v.new_var(ret)
937 end
938 frame.returnlabel = v.get_name("RET_LABEL")
939
940 mmethoddef.compile_inside_to_c(v, arguments)
941
942 v.add("{frame.returnlabel.as(not null)}:;")
943 if ret != null then
944 v.add("return {frame.returnvar.as(not null)};")
945 end
946 v.add("\}")
947 end
948
949 redef fun call(v: VISITOR, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
950 do
951 var ret = self.mmethoddef.msignature.return_mtype
952 if self.mmethoddef.mproperty.is_new then
953 ret = recv
954 end
955 if ret != null then
956 ret = v.resolve_for(ret, arguments.first)
957 end
958 if self.mmethoddef.can_inline(v) then
959 var frame = new Frame(v, self.mmethoddef, self.recv, arguments)
960 frame.returnlabel = v.get_name("RET_LABEL")
961 if ret != null then
962 frame.returnvar = v.new_var(ret)
963 end
964 var old_frame = v.frame
965 v.frame = frame
966 v.add("\{ /* Inline {self} ({arguments.join(",")}) */")
967 self.mmethoddef.compile_inside_to_c(v, arguments)
968 v.add("{frame.returnlabel.as(not null)}:(void)0;")
969 v.add("\}")
970 v.frame = old_frame
971 return frame.returnvar
972 end
973 v.adapt_signature(self.mmethoddef, arguments)
974 v.compiler.todo(self)
975 if ret == null then
976 v.add("{self.c_name}({arguments.join(",")});")
977 return null
978 else
979 var res = v.new_var(ret)
980 v.add("{res} = {self.c_name}({arguments.join(",")});")
981 return res
982 end
983 end
984 end