nitc: support for native_arg[cv] as intern
[nit.git] / src / compiling / compiling_icode.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2009 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 # Generate C code from intermediate code representation
18 package compiling_icode
19
20 import icode
21 private import analysis
22 import primitive_info
23 import compiling_base
24
25 # Compiler context from ICode to C
26 class I2CCompilerVisitor
27 # Associate things
28 var _ids: HashMap[Object, String] = new HashMap[Object, String]
29 # Associate other things
30 var _ids2: HashMap[Object, String] = new HashMap[Object, String]
31
32 # Return the string associated with a register
33 fun register(e: IRegister): String
34 do
35 if e.stype isa MMTypeNone then return "NIT_NULL"
36 var ids = _ids
37 if closure and not e.is_local then ids = _ids2
38 if ids.has_key(e) then
39 return ids[e]
40 else
41 var i = e.slot_index
42 if i == null then
43 # The register is dead
44 var s = "NIT_NULL"
45 ids[e] = s
46 return s
47 else
48 var s: String
49 var strs: HashMap[Int, String]
50 if e.in_tag_slots then
51 strs = once new HashMap[Int, String]
52 if not strs.has_key(i) then strs[i] = "REGB{i}"
53 else if closure and not e.is_local then
54 strs = once new HashMap[Int, String]
55 if not strs.has_key(i) then strs[i] = "closctx->REG[{i}]"
56 else
57 strs = once new HashMap[Int, String]
58 if not strs.has_key(i) then strs[i] = "fra.me.REG[{i}]"
59 end
60 s = strs[i]
61 ids[e] = s
62 return s
63 end
64 end
65 end
66
67 # Return the strings associated with registers
68 fun registers(a: Collection[IRegister]): Array[String]
69 do
70 var r = new Array[String].with_capacity(a.length)
71 for e in a do
72 r.add(register(e))
73 end
74 return r
75 end
76
77 var _last_number: Int = 0
78 # Give a new unique number (unique for the visitor)
79 fun new_number: Int
80 do
81 _last_number += 1
82 return _last_number
83 end
84
85 # Return the string associated with a escape label
86 fun lab(e: ISeq): String
87 do
88 if _ids.has_key(e) then
89 return _ids[e]
90 else
91 var s = "label{new_number}"
92 _ids[e] = s
93 return s
94 end
95 end
96
97 # The rank (number) of each closure
98 readable var _closures: HashMap[IClosureDecl, String] = new HashMap[IClosureDecl, String]
99
100 # The functionnal type of each closure
101 readable var _clostypes: HashMap[IClosureDecl, String] = new HashMap[IClosureDecl, String]
102
103 # label locally accessibles
104 readable writable var _local_labels: HashSet[ISeq] = new HashSet[ISeq]
105
106 # Not local escaped labels
107 # The integer value is an index identifying the label
108 readable writable var _escaped_labels: HashMap[ISeq, Int] = new HashMap[ISeq, Int]
109
110 # Register a escape to a non local label and return an index identifying the label
111 fun register_escape_label(e: ISeq): Int
112 do
113 if _escaped_labels.has_key(e) then
114 return _escaped_labels[e]
115 else
116 var res = _escaped_labels.length + 1
117 _escaped_labels[e] = res
118 return res
119 end
120 end
121
122 # Add a C label mark (if needed)
123 fun add_label(e: ISeq)
124 do
125 if _ids.has_key(e) then
126 add_instr("{_ids[e]}: while(0);")
127 end
128 end
129
130 # Add a goto to a label (even outside a closure)
131 fun add_goto(seq: ISeq)
132 do
133 if local_labels.has(seq) then
134 add_instr("goto {lab(seq)};")
135 else
136 assert closure
137 var ind = register_escape_label(seq)
138 add_instr("closctx->has_broke = {ind};")
139 add_instr("goto {lab(return_label.as(not null))};")
140 end
141 end
142
143 # Association between IEscapeMarks and visited ISeq
144 readable var _marks_to_seq: Map[IEscapeMark, ISeq] = new HashMap[IEscapeMark, ISeq]
145
146 # Are we in a closure ?
147 readable writable var _closure: Bool = false
148
149 # The current compiler visitor
150 readable var _visitor: CompilerVisitor
151
152 # The current compiled iroutine
153 readable var _iroutine: IRoutine
154
155 # The return label of the current compiling C function
156 readable writable var _return_label: nullable ISeq = null
157
158 fun add_decl(s: String)
159 do
160 visitor.add_decl(s)
161 end
162
163 # Prepare a new instuction (indent, comment)
164 # Caller must ensure to add a new line to finish its instr
165 fun new_instr: Writer
166 do
167 var w = visitor.writer
168 var l = _next_location
169 if l != null then
170 visitor.add_indent(w)
171 w.add("/* ")
172 w.add(l.file.filename)
173 w.add(":")
174 w.add(l.line_start.to_s)
175 w.add(" */\n")
176 _next_location = null
177 end
178 visitor.add_indent(w)
179 return w
180 end
181
182 fun add_instr(s: String)
183 do
184 new_instr.add(s).add("\n")
185 end
186
187 fun indent
188 do
189 visitor.indent
190 end
191
192 fun unindent
193 do
194 visitor.unindent
195 end
196
197 fun add_assignment(to, from: String)
198 do
199 visitor.add_assignment(to, from)
200 end
201
202 var _last_location: nullable Location = null
203 var _next_location: nullable Location = null
204
205 # Add location information in a comment
206 # Do nothing if the last location added is the same
207 fun add_location(l: nullable Location)
208 do
209 var last = _last_location
210 if last == l or l == null then return
211 _last_location = l
212 if last != null and last.file == l.file and last.line_start == l.line_start then
213 return
214 else
215 _next_location = l
216 end
217 end
218
219 # The C fonction name of the iroutine
220 readable var _basecname: String
221
222 init(v: CompilerVisitor, ir: IRoutine, cname: String)
223 do
224 _visitor = v
225 _iroutine = ir
226 _basecname = cname
227 end
228 end
229
230 redef class IRoutine
231 # Declare and start a C function that match the routine
232 # Return what must be given to compile_inside_to_c or to compile_to_c
233 # After the method, an openinig { and and indent is added.
234 # So, do not forget to add a sub_context, to unintent and to add a closing }
235 fun compile_signature_to_c(v: CompilerVisitor, cname: String, human_name: nullable String, before_params, after_params: nullable String): Array[String]
236 do
237 var cargs = new Array[String]
238 var cparams = new Array[String]
239 if before_params != null then cparams.add(before_params)
240 for i in [0..params.length[ do
241 cargs.add("p{i}")
242 cparams.add("val_t p{i}")
243 end
244 if closure_decls != null then
245 cparams.add("struct stack_frame_t *closctx_param")
246 for i in [0..closure_decls.length[ do
247 var closcn = "CLOS_{cname}_{i}"
248 var cs = closure_decls[i].closure.signature
249 var subparams = new Array[String] # Parameters of the closure
250 subparams.add("struct stack_frame_t *")
251 for j in [0..cs.arity[ do
252 subparams.add("val_t")
253 end
254 var rr = "void"
255 if cs.return_type != null then rr = "val_t"
256 v.add_decl("typedef {rr} (*{closcn})({subparams.join(", ")});")
257 cargs.add("clos_fun{i}")
258 cparams.add("fun_t clos_fun{i}")
259 end
260 end
261 if after_params != null then cparams.add(after_params)
262 var r = "void"
263 if result != null then r = "val_t"
264 var p: String
265 if cparams.is_empty then
266 p = "void"
267 else
268 p = cparams.join(", ")
269 end
270 if human_name != null then
271 v.add_instr("static const char LOCATE_{cname}[] = \"{human_name}\";")
272 end
273 v.add_decl("{r} {cname}({p});")
274 v.add_decl("typedef {r} (*{cname}_t)({p});")
275 v.add_instr("{r} {cname}({p})\{")
276 v.indent
277 return cargs
278 end
279
280 # Compile the body of the routine, return the result value is any
281 fun compile_inside_to_c(v: I2CCompilerVisitor, args: Array[String]): nullable String
282 do
283 # Create and push the stack frame
284 var ll = 0
285 if location != null then
286 ll = location.line_start
287 end
288 # Encapsulate the frame ('me') in a larger structure ('fra') that has enough space to store the local variables (REG)
289 if std_slots_nb > 1 then
290 v.add_decl("struct \{struct stack_frame_t me; val_t MORE_REG[{std_slots_nb-1}];\} fra;")
291 else
292 v.add_decl("struct \{struct stack_frame_t me;\} fra;")
293 end
294 v.add_instr("fra.me.prev = stack_frame_head; stack_frame_head = &fra.me;")
295 v.add_instr("fra.me.file = LOCATE_{v.visitor.mmmodule.cname};")
296 v.add_instr("fra.me.line = {ll};")
297 v.add_instr("fra.me.meth = LOCATE_{v.basecname};")
298 v.add_instr("fra.me.has_broke = 0;")
299 v.add_instr("fra.me.REG_size = {std_slots_nb};")
300 v.add_instr("fra.me.nitni_local_ref_head = NULL;")
301
302 # Declare/initialize local variables
303 for i in [0..std_slots_nb[ do
304 v.add_instr("fra.me.REG[{i}] = NIT_NULL;")
305 end
306 for i in [0..tag_slots_nb[ do
307 v.add_decl("val_t REGB{i};")
308 end
309 var iclosdecls = closure_decls
310 if iclosdecls != null then
311 v.add_decl("fun_t CREG[{iclosdecls.length}];")
312 v.add_instr("fra.me.closure_ctx = closctx_param;")
313 v.add_instr("fra.me.closure_funs = CREG;")
314 end
315 var k = 0
316 for r in params do
317 if r.slot_index != null then v.add_assignment(v.register(r), args[k])
318 k += 1
319 end
320 if iclosdecls != null then
321 for i in [0..iclosdecls.length[ do
322 var iclosdecl = iclosdecls[i]
323 v.add_instr("CREG[{i}] = {args[params.length+i]};")
324 v.closures[iclosdecl] = i.to_s
325 var cs = iclosdecl.closure.signature # Closure signature
326 var subparams = new Array[String] # Parameters of the closure
327 subparams.add("struct stack_frame_t *")
328 for j in [0..cs.arity[ do
329 var p = "val_t"
330 subparams.add(p)
331 end
332 var r = "void"
333 if cs.return_type != null then r = "val_t"
334 v.clostypes[iclosdecl] = "{r} (*)({subparams.join(", ")})"
335 end
336 end
337 v.add_decl("val_t tmp;")
338
339 # Prepare return
340 var old_rl = v.return_label
341 v.return_label = body
342
343 # Compile body
344 body.compile_to_c(v)
345
346 v.add_instr("stack_frame_head = fra.me.prev;")
347 v.return_label = old_rl
348 var r = result
349 if r != null then
350 return v.register(r)
351 else
352 return null
353 end
354 end
355
356 # Full compilation of the routine
357 # cv must be in the correct function
358 fun compile_to_c(cv: CompilerVisitor, cname: String, args: Array[String]): nullable String
359 do
360 var v = new I2CCompilerVisitor(cv, self, cname)
361 return compile_inside_to_c(v, args)
362 end
363 end
364
365 redef class ICode
366 # Full compilation of the icode
367 fun compile_to_c(v: I2CCompilerVisitor) is abstract
368
369 # Is a result really needed
370 private fun need_result: Bool
371 do
372 var r = result
373 return r != null and r.slot_index != null
374 end
375
376 # Store s in the result value of self
377 private fun store_result(v: I2CCompilerVisitor, w: nullable Writer)
378 do
379 var r = result
380 if r != null and r.slot_index != null then
381 assert w != null
382 var w2 = v.new_instr
383 w2.add(v.register(r))
384 w2.add(" = ")
385 w2.append(w)
386 w2.add(";\n")
387 else if w != null and not is_pure then
388 # ICode with side effects must be evaluated
389 # even if the result is not wanted
390 var w2 = v.new_instr
391 w2.append(w)
392 w2.add(";\n")
393 end
394 end
395
396 # Prepare a writer if the expression icode need to be compiled
397 # * Result assigment is automatic if needed
398 private fun new_result(v: I2CCompilerVisitor): Writer
399 do
400 assert need_result or not is_pure
401 var w2 = v.new_instr
402 var r = result
403 if r != null and r.slot_index != null then
404 w2.add(v.register(r))
405 w2.add(" = ")
406 end
407 var w = w2.sub
408 w2.add(";\n")
409 return w
410 end
411 end
412
413 redef class ISeq
414 redef fun compile_to_c(v)
415 do
416 v.add_location(location)
417 v.local_labels.add(self)
418 var mark = iescape_mark
419 if mark != null then v.marks_to_seq[mark] = self
420 for ic in icodes do
421 ic.compile_to_c(v)
422 end
423 v.add_label(self)
424 end
425 end
426
427 redef class IIf
428 redef fun compile_to_c(v)
429 do
430 v.add_location(location)
431 var w = v.new_instr
432 w.add("if (UNTAG_Bool(")
433 w.add(v.register(expr))
434 w.add(")) \{\n")
435 if not then_seq.icodes.is_empty then
436 v.indent
437 then_seq.compile_to_c(v)
438 v.unindent
439 end
440 if not else_seq.icodes.is_empty then
441 v.add_instr("\} else \{")
442 v.indent
443 else_seq.compile_to_c(v)
444 v.unindent
445 end
446 v.add_instr("\}")
447 end
448 end
449
450 redef class ILoop
451 redef fun compile_to_c(v)
452 do
453 v.add_location(location)
454 v.local_labels.add(self)
455 var mark = iescape_mark
456 if mark != null then v.marks_to_seq[mark] = self
457 v.add_instr("while(1) \{")
458 v.indent
459 for ic in icodes do
460 ic.compile_to_c(v)
461 end
462 v.unindent
463 v.add_instr("\}")
464 v.add_label(self)
465 end
466 end
467
468 redef class IEscape
469 redef fun compile_to_c(v)
470 do
471 v.add_location(location)
472 v.add_goto(v.marks_to_seq[iescape_mark])
473 end
474 end
475
476 redef class IAbsCall
477 redef fun compile_to_c(v)
478 do
479 v.add_location(location)
480 var args = v.registers(exprs)
481
482 # Compile closure definitions
483 var old_el = v.escaped_labels
484 var closdefs = closure_defs
485 var closctx: nullable String = null # The closure context of closdefs
486 if closdefs != null then
487 # Get the closure context
488 if v.closure then
489 closctx = "closctx"
490 else
491 closctx = "(&(fra.me))"
492 end
493
494 # First aditionnal arguments is the closure context
495 args.add(closctx)
496
497 # We are in a new escape boundary
498 v.escaped_labels = new HashMap[ISeq, Int]
499
500 # Compile each closures and add each sub-function as an other additionnal parameter
501 for cd in closdefs do
502 if cd != null then
503 var cn = cd.compile_closure(v)
504 args.add(cn)
505 else
506 args.add("NULL")
507 end
508 end
509 end
510
511 # Compile the real call
512 var call = compile_call_to_c(v, args)
513 var res: nullable Writer = call
514
515 # Intercept escapes
516 if closctx != null then
517 var els = v.escaped_labels
518 v.escaped_labels = old_el
519 # Is there possible escapes?
520 if not els.is_empty then
521 # Call in a tmp variable to avoid 'break' overwrite
522 var w = v.new_instr
523 if need_result then
524 w.add("tmp")
525 w.add(" = ")
526 w.append(call)
527 w.add(";\n")
528 res = new Writer
529 res.add("tmp")
530 else
531 res = null
532 w.append(call)
533 w.add(";\n")
534 end
535 # What are the expected escape indexes
536 v.new_instr.add("switch (").add(closctx).add("->has_broke) \{\n")
537 v.indent
538 # No escape occured, continue as usual
539 v.add_instr("case 0: break;")
540 var lls = v.local_labels
541 var iels = els.iterator
542 var forward_escape = false
543 while iels.is_ok do
544 var seq = iels.key
545 if lls.has(seq) then
546 # Local escape occured
547 # Clear the has_broke information and go to the target
548 v.new_instr.add("case ").add(iels.item.to_s).add(": ").add(closctx).add("->has_broke = 0; goto ").add(v.lab(seq)).add(";\n")
549 else
550 # Forward escape occured: register the escape label
551 assert v.closure
552 v.register_escape_label(seq)
553 forward_escape = true
554 end
555 iels.next
556 end
557 # If forward escape occured, just pass to the next one
558 if forward_escape then
559 # Do not need to copy 'has_broke' value since it is shared by the next one.
560 # So just exit the C function.
561 v.new_instr.add("default: goto ").add(v.lab(v.return_label.as(not null))).add(";\n")
562 end
563 v.unindent
564 v.add_instr("\}")
565 end
566 end
567
568 if res != null then
569 var w = new_result(v)
570 w.append(res)
571 end
572 end
573
574 # The single invocation witout fancy stuffs
575 private fun compile_call_to_c(v: I2CCompilerVisitor, args: Array[String]): Writer is abstract
576 end
577
578 redef class ICall
579 redef fun compile_call_to_c(v, args)
580 do
581 var w = new Writer
582
583 # do not compile explicit calls from native methods
584 # theses are really manually called in the native implementation
585 if is_explicit_from_extern then return w
586
587 var prop = property
588 if prop.global.is_init then args.add("init_table")
589 w.add(prop.global.meth_call)
590 w.add("(")
591 w.add(args.first)
592 w.add(")(")
593 w.add_all(args, ", ")
594 w.add(")")
595 return w
596 end
597 end
598
599 redef class ISuper
600 redef fun compile_call_to_c(v, args)
601 do
602 # do not compile explicit calls from native methods
603 # theses are really manually called in the native implementation
604 if is_explicit_from_extern then return new Writer
605
606 var prop = property
607 if prop.global.is_init then args.add("init_table")
608 var w = new Writer
609 w.add(prop.super_meth_call)
610 w.add("(")
611 w.add(args.first)
612 w.add(")(")
613 w.add_all(args, ", ")
614 w.add(")")
615 return w
616 end
617 end
618
619 redef class INew
620 redef fun compile_call_to_c(v, args)
621 do
622 var w = new Writer
623
624 # do not compile explicit calls from native methods
625 # theses are really manually called in the native implementation
626 if is_explicit_from_extern then return w
627
628 w.add("NEW_")
629 w.add(stype.local_class.to_s)
630 w.add("_")
631 w.add(property.global.intro.cname)
632 w.add("(")
633 w.add_all(args, ", ")
634 w.add(")")
635 return w
636 end
637 end
638
639 redef class IAllocateInstance
640 redef fun compile_to_c(v)
641 do
642 v.add_location(location)
643 var w = new_result(v)
644 w.add("NEW_")
645 w.add(stype.local_class.cname)
646 w.add("()")
647 end
648 end
649
650 redef class ICheckInstance
651 redef fun compile_to_c(v)
652 do
653 v.add_location(location)
654 var w = new_result(v)
655 w.add("CHECKNEW_")
656 w.add(stype.local_class.cname)
657 w.add("(")
658 w.add(v.register(expr))
659 w.add(")")
660 end
661 end
662
663 redef class IInitAttributes
664 redef fun compile_to_c(v)
665 do
666 v.add_location(location)
667 var w = v.new_instr
668 w.add("INIT_ATTRIBUTES__")
669 w.add(stype.local_class.cname)
670 w.add("(")
671 w.add(v.register(expr))
672 w.add(");\n")
673 end
674 end
675
676 redef class IStaticCall
677 redef fun compile_call_to_c(v, args)
678 do
679 var prop = property
680 if prop.global.is_init then args.add("init_table")
681 var w = new Writer
682 w.add(property.cname)
683 w.add("(")
684 w.add_all(args, ", ")
685 w.add(")")
686 return w
687 end
688 end
689
690 redef class INative
691 redef fun compile_to_c(v)
692 do
693 v.add_location(location)
694 if method.is_intern then
695 compile_intern_method_to_c(v)
696 else if not method.global.is_init then
697 compile_extern_method_to_c(v)
698 end
699 end
700
701 fun compile_extern_method_to_c(v: I2CCompilerVisitor)
702 do
703 var ename = "{method.friendly_extern_name(method.local_class)}___out"
704
705 var sig = method.signature
706 assert exprs.length == sig.arity + 1
707
708 var regs = v.registers(exprs)
709
710 var args = new Array[String]
711 args.add(regs[0])
712 for i in [0..sig.arity[ do
713 args.add(regs[i+1])
714 end
715 var s = "{ename}({args.join(", ")})"
716
717 if need_result then s = s # sig.return_type.boxtype(s)
718 var w = new_result(v)
719 w.add(s)
720 end
721
722 fun compile_intern_method_to_c(v: I2CCompilerVisitor)
723 do
724 var sig = method.signature
725 assert exprs.length == sig.arity + 1
726 var c = method.local_class.name
727 var n = method.name
728 var regs = v.registers(exprs)
729 var s: nullable String = null
730 if c == once "Int".to_symbol then
731 if n == once "object_id".to_symbol then
732 s = regs[0]
733 else if n == once "unary -".to_symbol then
734 s = "TAG_Int(-UNTAG_Int({regs[0]}))"
735 else if n == once "output".to_symbol then
736 s = "printf(\"%ld\\n\", UNTAG_Int({regs[0]}));"
737 else if n == once "ascii".to_symbol then
738 s = "TAG_Char(UNTAG_Int({regs[0]}))"
739 else if n == once "succ".to_symbol then
740 s = "TAG_Int(UNTAG_Int({regs[0]})+1)"
741 else if n == once "prec".to_symbol then
742 s = "TAG_Int(UNTAG_Int({regs[0]})-1)"
743 else if n == once "to_f".to_symbol then
744 s = "BOX_Float((float)UNTAG_Int({regs[0]}))"
745 else if n == once "+".to_symbol then
746 s = "TAG_Int(UNTAG_Int({regs[0]})+UNTAG_Int({regs[1]}))"
747 else if n == once "-".to_symbol then
748 s = "TAG_Int(UNTAG_Int({regs[0]})-UNTAG_Int({regs[1]}))"
749 else if n == once "*".to_symbol then
750 s = "TAG_Int(UNTAG_Int({regs[0]})*UNTAG_Int({regs[1]}))"
751 else if n == once "/".to_symbol then
752 s = "TAG_Int(UNTAG_Int({regs[0]})/UNTAG_Int({regs[1]}))"
753 else if n == once "%".to_symbol then
754 s = "TAG_Int(UNTAG_Int({regs[0]})%UNTAG_Int({regs[1]}))"
755 else if n == once "<".to_symbol then
756 s = "TAG_Bool(UNTAG_Int({regs[0]})<UNTAG_Int({regs[1]}))"
757 else if n == once ">".to_symbol then
758 s = "TAG_Bool(UNTAG_Int({regs[0]})>UNTAG_Int({regs[1]}))"
759 else if n == once "<=".to_symbol then
760 s = "TAG_Bool(UNTAG_Int({regs[0]})<=UNTAG_Int({regs[1]}))"
761 else if n == once ">=".to_symbol then
762 s = "TAG_Bool(UNTAG_Int({regs[0]})>=UNTAG_Int({regs[1]}))"
763 else if n == once "lshift".to_symbol then
764 s = "TAG_Int(UNTAG_Int({regs[0]})<<UNTAG_Int({regs[1]}))"
765 else if n == once "rshift".to_symbol then
766 s = "TAG_Int(UNTAG_Int({regs[0]})>>UNTAG_Int({regs[1]}))"
767 else if n == once "==".to_symbol then
768 s = "TAG_Bool(({regs[0]})==({regs[1]}))"
769 else if n == once "!=".to_symbol then
770 s = "TAG_Bool(({regs[0]})!=({regs[1]}))"
771 end
772 else if c == once "Float".to_symbol then
773 if n == once "object_id".to_symbol then
774 s = "TAG_Int((bigint)UNBOX_Float({regs[0]}))"
775 else if n == once "unary -".to_symbol then
776 s = "BOX_Float(-UNBOX_Float({regs[0]}))"
777 else if n == once "output".to_symbol then
778 s = "printf(\"%f\\n\", UNBOX_Float({regs[0]}));"
779 else if n == once "to_i".to_symbol then
780 s = "TAG_Int((bigint)UNBOX_Float({regs[0]}))"
781 else if n == once "+".to_symbol then
782 s = "BOX_Float(UNBOX_Float({regs[0]})+UNBOX_Float({regs[1]}))"
783 else if n == once "-".to_symbol then
784 s = "BOX_Float(UNBOX_Float({regs[0]})-UNBOX_Float({regs[1]}))"
785 else if n == once "*".to_symbol then
786 s = "BOX_Float(UNBOX_Float({regs[0]})*UNBOX_Float({regs[1]}))"
787 else if n == once "/".to_symbol then
788 s = "BOX_Float(UNBOX_Float({regs[0]})/UNBOX_Float({regs[1]}))"
789 else if n == once "<".to_symbol then
790 s = "TAG_Bool(UNBOX_Float({regs[0]})<UNBOX_Float({regs[1]}))"
791 else if n == once ">".to_symbol then
792 s = "TAG_Bool(UNBOX_Float({regs[0]})>UNBOX_Float({regs[1]}))"
793 else if n == once "<=".to_symbol then
794 s = "TAG_Bool(UNBOX_Float({regs[0]})<=UNBOX_Float({regs[1]}))"
795 else if n == once ">=".to_symbol then
796 s = "TAG_Bool(UNBOX_Float({regs[0]})>=UNBOX_Float({regs[1]}))"
797 end
798 else if c == once "Char".to_symbol then
799 if n == once "object_id".to_symbol then
800 s = "TAG_Int(UNTAG_Char({regs[0]}))"
801 else if n == once "unary -".to_symbol then
802 s = "TAG_Char(-UNTAG_Char({regs[0]}))"
803 else if n == once "output".to_symbol then
804 s = "printf(\"%c\", (unsigned char)UNTAG_Char({regs[0]}));"
805 else if n == once "ascii".to_symbol then
806 s = "TAG_Int((unsigned char)UNTAG_Char({regs[0]}))"
807 else if n == once "succ".to_symbol then
808 s = "TAG_Char(UNTAG_Char({regs[0]})+1)"
809 else if n == once "prec".to_symbol then
810 s = "TAG_Char(UNTAG_Char({regs[0]})-1)"
811 else if n == once "to_i".to_symbol then
812 s = "TAG_Int(UNTAG_Char({regs[0]})-'0')"
813 else if n == once "+".to_symbol then
814 s = "TAG_Char(UNTAG_Char({regs[0]})+UNTAG_Char({regs[1]}))"
815 else if n == once "-".to_symbol then
816 s = "TAG_Char(UNTAG_Char({regs[0]})-UNTAG_Char({regs[1]}))"
817 else if n == once "*".to_symbol then
818 s = "TAG_Char(UNTAG_Char({regs[0]})*UNTAG_Char({regs[1]}))"
819 else if n == once "/".to_symbol then
820 s = "TAG_Char(UNTAG_Char({regs[0]})/UNTAG_Char({regs[1]}))"
821 else if n == once "%".to_symbol then
822 s = "TAG_Char(UNTAG_Char({regs[0]})%UNTAG_Char({regs[1]}))"
823 else if n == once "<".to_symbol then
824 s = "TAG_Bool(UNTAG_Char({regs[0]})<UNTAG_Char({regs[1]}))"
825 else if n == once ">".to_symbol then
826 s = "TAG_Bool(UNTAG_Char({regs[0]})>UNTAG_Char({regs[1]}))"
827 else if n == once "<=".to_symbol then
828 s = "TAG_Bool(UNTAG_Char({regs[0]})<=UNTAG_Char({regs[1]}))"
829 else if n == once ">=".to_symbol then
830 s = "TAG_Bool(UNTAG_Char({regs[0]})>=UNTAG_Char({regs[1]}))"
831 else if n == once "==".to_symbol then
832 s = "TAG_Bool(({regs[0]})==({regs[1]}))"
833 else if n == once "!=".to_symbol then
834 s = "TAG_Bool(({regs[0]})!=({regs[1]}))"
835 end
836 else if c == once "Bool".to_symbol then
837 if n == once "object_id".to_symbol then
838 s = "TAG_Int(UNTAG_Bool({regs[0]}))"
839 else if n == once "unary -".to_symbol then
840 s = "TAG_Bool(-UNTAG_Bool({regs[0]}))"
841 else if n == once "output".to_symbol then
842 s = "(void)printf(UNTAG_Bool({regs[0]})?\"true\\n\":\"false\\n\");"
843 else if n == once "ascii".to_symbol then
844 s = "TAG_Bool(UNTAG_Bool({regs[0]}))"
845 else if n == once "to_i".to_symbol then
846 s = "TAG_Int(UNTAG_Bool({regs[0]}))"
847 else if n == once "==".to_symbol then
848 s = "TAG_Bool(({regs[0]})==({regs[1]}))"
849 else if n == once "!=".to_symbol then
850 s = "TAG_Bool(({regs[0]})!=({regs[1]}))"
851 end
852 else if c == once "NativeArray".to_symbol then
853 if n == once "object_id".to_symbol then
854 s = "TAG_Int(((Nit_NativeArray){regs[0]})->object_id)"
855 else if n == once "[]".to_symbol then
856 s = "((Nit_NativeArray){regs[0]})->val[UNTAG_Int({regs[1]})]"
857 else if n == once "[]=".to_symbol then
858 s = "((Nit_NativeArray){regs[0]})->val[UNTAG_Int({regs[1]})]={regs[2]}"
859 else if n == once "copy_to".to_symbol then
860 s = "(void)memcpy(((Nit_NativeArray ){regs[1]})->val, ((Nit_NativeArray){regs[0]})->val, UNTAG_Int({regs[2]})*sizeof(val_t))"
861 end
862 else if c == once "NativeString".to_symbol then
863 if n == once "object_id".to_symbol then
864 s = "TAG_Int(UNBOX_NativeString({regs[0]}))"
865 else if n == once "atoi".to_symbol then
866 s = "TAG_Int(atoi(UNBOX_NativeString({regs[0]})))"
867 else if n == once "[]".to_symbol then
868 s = "TAG_Char(UNBOX_NativeString({regs[0]})[UNTAG_Int({regs[1]})])"
869 else if n == once "[]=".to_symbol then
870 s = "UNBOX_NativeString({regs[0]})[UNTAG_Int({regs[1]})]=UNTAG_Char({regs[2]});"
871 else if n == once "copy_to".to_symbol then
872 s = "(void)memcpy(UNBOX_NativeString({regs[1]})+UNTAG_Int({regs[4]}), UNBOX_NativeString({regs[0]})+UNTAG_Int({regs[3]}), UNTAG_Int({regs[2]}));"
873 end
874 else if c == once "Sys".to_symbol then
875 if n == once "force_garbage_collection".to_symbol then
876 s = "Nit_gc_force_garbage_collection()"
877 else if n == once "native_argc".to_symbol then
878 s = "TAG_Int(glob_argc)"
879 else if n == once "native_argv".to_symbol then
880 s = "BOX_NativeString(glob_argv[UNTAG_Int({regs[1]})])"
881 end
882 else if n == once "object_id".to_symbol then
883 s = "TAG_Int((bigint)((obj_t){regs[0]})[1].object_id)"
884 else if n == once "sys".to_symbol then
885 s = "(G_sys)"
886 else if n == once "is_same_type".to_symbol then
887 s = "TAG_Bool((VAL2VFT({regs[0]})==VAL2VFT({regs[1]})))"
888 else if n == once "exit".to_symbol then
889 s = "exit(UNTAG_Int({regs[1]}));"
890 else if n == once "calloc_array".to_symbol then
891 s = "NEW_NativeArray(UNTAG_Int({regs[1]}), sizeof(val_t))"
892 else if n == once "calloc_string".to_symbol then
893 s = "BOX_NativeString((char*)raw_alloc((UNTAG_Int({regs[1]}) * sizeof(char))))"
894 # Add output_class_name native implementation
895 else if n == once "output_class_name".to_symbol then
896 s = "printf(\"%s\\n\", VAL2VFT({regs[0]})[2].cname);"
897 # Add class_name implementation
898 else if n == once "native_class_name".to_symbol then
899 s = "BOX_NativeString(VAL2VFT({regs[0]})[2].cname);"
900 end
901
902 if s == null then
903 var ll = location
904 if ll != null then v.add_instr("fprintf(stderr, \"{ll.to_s}: \");")
905 v.add_instr("fprintf(stderr, \"Fatal error: unknown intern method {method.full_name}.\\n\");")
906 v.add_instr("nit_exit(1);")
907 s = "NIT_NULL"
908 end
909 if result == null then
910 v.new_instr.add(s).add(";\n")
911 else if need_result then
912 var w = new_result(v)
913 w.add(s)
914 end
915 end
916 end
917
918 redef class IIntValue
919 redef fun compile_to_c(v)
920 do
921 v.add_location(location)
922 var w = new_result(v)
923 w.add("TAG_Int(").add(value.to_s).add(")")
924 end
925 end
926
927 redef class IBoolValue
928 redef fun compile_to_c(v)
929 do
930 v.add_location(location)
931 var w = new_result(v)
932 w.add("TAG_Bool(")
933 if value then w.add("1") else w.add("0")
934 w.add(")")
935 end
936 end
937
938 redef class ICharValue
939 redef fun compile_to_c(v)
940 do
941 v.add_location(location)
942 var w = new_result(v)
943 w.add("TAG_Char(").add(value).add(")")
944 end
945 end
946
947 redef class IFloatValue
948 redef fun compile_to_c(v)
949 do
950 v.add_location(location)
951 var w = new_result(v)
952 w.add("BOX_Float(").add(value).add(")")
953 end
954 end
955
956 redef class IStringValue
957 redef fun compile_to_c(v)
958 do
959 v.add_location(location)
960 var w = new_result(v)
961 w.add("BOX_NativeString(\"").add(value).add("\")")
962 end
963 end
964
965 redef class IAbort
966 redef fun compile_to_c(v)
967 do
968 v.add_location(location)
969 var w = v.new_instr
970 w.add("nit_abort(\"")
971 w.add(texts[0])
972 if texts.length > 1 then
973 w.add("\", \"")
974 w.add(texts[1])
975 w.add("\"")
976 else
977 w.add("\", NULL")
978 end
979 w.add(", LOCATE_")
980 w.add(module_location.cname)
981 var ll = location
982 if ll != null then
983 w.add(", ")
984 w.add(ll.line_start.to_s)
985 else
986 w.add(", 0")
987 end
988 w.add(");\n")
989 end
990 end
991
992 redef class IMove
993 redef fun compile_to_c(v)
994 do
995 if not need_result then return
996 var e = v.register(expr)
997 var r = v.register(result.as(not null))
998 if e == r then return
999 v.add_location(location)
1000 var w = v.new_instr
1001 w.add(r)
1002 w.add(" = ")
1003 w.add(e)
1004 w.add(";\n")
1005 end
1006 end
1007
1008 redef class IAttrRead
1009 redef fun compile_to_c(v)
1010 do
1011 if not need_result then return
1012 v.add_location(location)
1013 var w = new_result(v)
1014 w.add(property.global.attr_access)
1015 w.add("(")
1016 w.add(v.register(expr))
1017 w.add(")")
1018 end
1019 end
1020
1021 redef class IAttrIsset
1022 redef fun compile_to_c(v)
1023 do
1024 if not need_result then return
1025 v.add_location(location)
1026 var w = new_result(v)
1027 w.add("TAG_Bool(")
1028 w.add(property.global.attr_access)
1029 w.add("(")
1030 w.add(v.register(expr))
1031 w.add(")!=NIT_NULL)")
1032 end
1033 end
1034
1035 redef class IAttrWrite
1036 redef fun compile_to_c(v)
1037 do
1038 v.add_location(location)
1039 var w = v.new_instr
1040 w.add(property.global.attr_access)
1041 w.add("(")
1042 w.add(v.register(expr1))
1043 w.add(") = ")
1044 w.add(v.register(expr2))
1045 w.add(";\n")
1046 end
1047 end
1048
1049 redef class ITypeCheck
1050 redef fun compile_to_c(v)
1051 do
1052 if not need_result then return
1053 v.add_location(location)
1054 var recv = v.register(expr2)
1055 var w = new_result(v)
1056 w.add("TAG_Bool(")
1057 if expr2.stype.is_nullable then
1058 if stype.is_nullable then
1059 w.add("(")
1060 w.add(recv)
1061 w.add("==NIT_NULL) || ")
1062 else if stype.as_nullable == expr2.stype then
1063 w.add(recv)
1064 w.add("!=NIT_NULL)")
1065 return
1066 else
1067 w.add("(")
1068 w.add(recv)
1069 w.add("!=NIT_NULL) && ")
1070 end
1071 end
1072 # FIXME handle formaltypes
1073 var t = stype
1074 if t isa MMVirtualType then
1075 var slf = v.register(expr1)
1076 var g = t.property.global
1077 w.add("VAL_ISA(")
1078 w.add(recv)
1079 w.add(", ")
1080 w.add(g.vt_class_color)
1081 w.add("(")
1082 w.add(slf)
1083 w.add(")")
1084 w.add(", ")
1085 w.add(g.vt_class_id)
1086 w.add("(")
1087 w.add(slf)
1088 w.add(")")
1089 w.add(")) /*cast ")
1090 w.add(t.to_s)
1091 w.add("*/")
1092 else
1093 var g = t.local_class.global
1094 w.add("VAL_ISA(")
1095 w.add(recv)
1096 w.add(", ")
1097 w.add(g.color_id)
1098 w.add(", ")
1099 w.add(g.id_id)
1100 w.add(")) /*cast ")
1101 w.add(t.to_s)
1102 w.add("*/")
1103 end
1104 end
1105 end
1106
1107 redef class IIs
1108 redef fun compile_to_c(v)
1109 do
1110 if not need_result then return
1111 v.add_location(location)
1112 var w = new_result(v)
1113 w.add("TAG_Bool(")
1114 var t1 = expr1.stype
1115 var t2 = expr2.stype
1116 if t1 isa MMTypeNone then
1117 if t2 isa MMTypeNone then
1118 w.add("1)")
1119 return
1120 else if t2.is_nullable then
1121 w.add(v.register(expr2))
1122 w.add("==NIT_NULL)")
1123 return
1124 else
1125 w.add("0)")
1126 return
1127 end
1128 else if t1.is_nullable then
1129 if t2 isa MMTypeNone then
1130 w.add(v.register(expr1))
1131 w.add("==NIT_NULL)")
1132 return
1133 else if t2.is_nullable then
1134 w.add("IS_EQUAL_NN(")
1135 else
1136 w.add("IS_EQUAL_ON(")
1137 w.add(v.register(expr2))
1138 w.add(",")
1139 w.add(v.register(expr1))
1140 w.add("))")
1141 return
1142 end
1143 else
1144 if t2 isa MMTypeNone then
1145 w.add("0)")
1146 return
1147 else if t2.is_nullable then
1148 w.add("IS_EQUAL_ON(")
1149 else
1150 w.add("IS_EQUAL_OO(")
1151 end
1152 end
1153 w.add(v.register(expr1))
1154 w.add(",")
1155 w.add(v.register(expr2))
1156 w.add("))")
1157 end
1158 end
1159
1160 redef class INot
1161 redef fun compile_to_c(v)
1162 do
1163 if not need_result then return
1164 v.add_location(location)
1165 var w = new_result(v)
1166 w.add("TAG_Bool(!UNTAG_Bool(")
1167 w.add(v.register(expr))
1168 w.add("))")
1169 end
1170 end
1171
1172 redef class IOnce
1173 redef fun compile_to_c(v)
1174 do
1175 v.add_location(location)
1176 var i = v.new_number
1177 var res = result.as(not null)
1178 if res.stype.is_nullable then
1179 v.add_decl("static val_t once_value_{i}; static int once_bool_{i}; /* Once value */")
1180 v.add_instr("if (!once_bool_{i}) \{")
1181 else
1182 # Since the value is not nullable, we use the null value to represent the boolean
1183 v.add_decl("static val_t once_value_{i}; /* Once value */")
1184 v.add_instr("if (!once_value_{i}) \{")
1185 end
1186 v.indent
1187 body.compile_to_c(v)
1188 var e = v.register(res)
1189 v.add_instr("once_value_{i} = {e};")
1190 v.add_instr("register_static_object(&once_value_{i});")
1191 if res.stype.is_nullable then v.add_instr("once_bool_{i} = true;")
1192 v.unindent
1193 v.add_instr("\} else {e} = once_value_{i};")
1194 var w = new_result(v)
1195 w.add(e)
1196 end
1197 end
1198
1199 redef class IClosCall
1200 redef fun compile_to_c(v: I2CCompilerVisitor)
1201 do
1202 v.add_location(location)
1203 var ivar: String
1204 var args: Array[String]
1205 if v.closure then
1206 ivar = "closctx->closure_funs[{v.closures[closure_decl]}]"
1207 args = ["closctx->closure_ctx"]
1208 else
1209 ivar = "CREG[{v.closures[closure_decl]}]"
1210 args = ["closctx_param"]
1211 end
1212 args.append(v.registers(exprs))
1213
1214 var s = "(({v.clostypes[closure_decl]})({ivar}))({args.join(", ")})"
1215 var w = new Writer
1216 w.add(s)
1217 store_result(v, w)
1218
1219 # Intercept escape
1220 v.add_instr("if ({args.first}->has_broke) \{")
1221 v.indent
1222 var bs = break_seq
1223 if bs != null then
1224 bs.compile_to_c(v)
1225 end
1226 v.add_goto(v.iroutine.body)
1227 v.unindent
1228 v.add_instr("\}")
1229 end
1230 end
1231
1232 redef class IHasClos
1233 redef fun compile_to_c(v)
1234 do
1235 if not need_result then return
1236 v.add_location(location)
1237 var w = new_result(v)
1238 w.add("TAG_Bool(")
1239 if v.closure then
1240 w.add("closctx->closure_funs[")
1241 w.add(v.closures[closure_decl])
1242 w.add("]")
1243 else
1244 w.add("CREG[")
1245 w.add(v.closures[closure_decl])
1246 w.add("]")
1247 end
1248 w.add(" != NULL)")
1249 end
1250 end
1251
1252 redef class IClosureDef
1253 # Compile the closure as a separate C function in the visitor out_contexts.
1254 # Return a fun_t pointer to the function.
1255 fun compile_closure(v: I2CCompilerVisitor): String
1256 do
1257 var cv = v.visitor
1258
1259 # We are now in a closure
1260 var cfc_old = v.closure
1261 v.closure = true
1262
1263 # We are now in a escape boundary
1264 var lls_old = v.local_labels
1265 v.local_labels = new HashSet[ISeq]
1266
1267 # We are now in a new C context
1268 var decl_writer_old = cv.decl_writer
1269 var writer_old = cv.writer
1270 cv.writer = cv.top_writer.sub
1271 cv.decl_writer = cv.header_writer.sub
1272
1273 # Generate the C function
1274 var cname = "OC_{v.basecname}_{v.new_number}"
1275 var args = compile_signature_to_c(v.visitor, cname, null, "struct stack_frame_t *closctx", null)
1276 cv.decl_writer = cv.writer.sub
1277
1278 var s = compile_inside_to_c(v, args)
1279 if s == null then
1280 v.add_instr("return;")
1281 else
1282 v.add_instr("return {s};")
1283 end
1284 v.unindent
1285 v.add_instr("\}")
1286
1287 # Restore things
1288 cv.writer = writer_old
1289 cv.decl_writer = decl_writer_old
1290 v.closure = cfc_old
1291 v.local_labels = lls_old
1292 return "((fun_t){cname})"
1293 end
1294 end