5374ac83637276ea1d70b3740d044d00855cf595
[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 compiling_base
23
24 # Compiler context from ICode to C
25 class I2CCompilerVisitor
26 # Associate things
27 var _ids: HashMap[Object, String] = new HashMap[Object, String]
28 # Associate other things
29 var _ids2: HashMap[Object, String] = new HashMap[Object, String]
30
31 # Return the string associated with a register
32 fun register(e: IRegister): String
33 do
34 if e.stype isa MMTypeNone then return "NIT_NULL"
35 var ids = _ids
36 if closure and not e.is_local then ids = _ids2
37 if ids.has_key(e) then
38 return ids[e]
39 else
40 var i = e.slot_index
41 if i == null then
42 # The register is dead
43 var s = "NIT_NULL"
44 ids[e] = s
45 return s
46 else
47 var s: String
48 var strs: HashMap[Int, String]
49 if e.in_tag_slots then
50 strs = once new HashMap[Int, String]
51 if not strs.has_key(i) then strs[i] = "REGB{i}"
52 else if closure and not e.is_local then
53 strs = once new HashMap[Int, String]
54 if not strs.has_key(i) then strs[i] = "closctx->REG[{i}]"
55 else
56 strs = once new HashMap[Int, String]
57 if not strs.has_key(i) then strs[i] = "fra.me.REG[{i}]"
58 end
59 s = strs[i]
60 ids[e] = s
61 return s
62 end
63 end
64 end
65
66 # Return the strings associated with registers
67 fun registers(a: Collection[IRegister]): Array[String]
68 do
69 var r = new Array[String].with_capacity(a.length)
70 for e in a do
71 r.add(register(e))
72 end
73 return r
74 end
75
76 var _last_number: Int = 0
77 # Give a new unique number (unique for the visitor)
78 fun new_number: Int
79 do
80 _last_number += 1
81 return _last_number
82 end
83
84 # Return the string associated with a escape label
85 fun lab(e: ISeq): String
86 do
87 if _ids.has_key(e) then
88 return _ids[e]
89 else
90 var s = "label{new_number}"
91 _ids[e] = s
92 return s
93 end
94 end
95
96 # The rank (number) of each closure
97 readable var _closures: HashMap[IClosureDecl, Int] = new HashMap[IClosureDecl, Int]
98
99 # The functionnal type of each closure
100 readable var _clostypes: HashMap[IClosureDecl, String] = new HashMap[IClosureDecl, String]
101
102 # label locally accessibles
103 readable writable var _local_labels: HashSet[ISeq] = new HashSet[ISeq]
104
105 # Not local escaped labels
106 # The integer value is an index identifying the label
107 readable writable var _escaped_labels: HashMap[ISeq, Int] = new HashMap[ISeq, Int]
108
109 # Register a escape to a non local label and return an index identifying the label
110 fun register_escape_label(e: ISeq): Int
111 do
112 if _escaped_labels.has_key(e) then
113 return _escaped_labels[e]
114 else
115 var res = _escaped_labels.length + 1
116 _escaped_labels[e] = res
117 return res
118 end
119 end
120
121 # Add a C label mark (if needed)
122 fun add_label(e: ISeq)
123 do
124 if _ids.has_key(e) then
125 add_instr("{_ids[e]}: while(0);")
126 end
127 end
128
129 # Add a goto to a label (even outside a closure)
130 fun add_goto(seq: ISeq)
131 do
132 if local_labels.has(seq) then
133 add_instr("goto {lab(seq)};")
134 else
135 assert closure
136 var ind = register_escape_label(seq)
137 add_instr("closctx->has_broke = {ind};")
138 add_instr("goto {lab(return_label.as(not null))};")
139 end
140 end
141
142 # Association between IEscapeMarks and visited ISeq
143 readable var _marks_to_seq: Map[IEscapeMark, ISeq] = new HashMap[IEscapeMark, ISeq]
144
145 # Are we in a closure ?
146 readable writable var _closure: Bool = false
147
148 # The current compiler visitor
149 readable var _visitor: CompilerVisitor
150
151 # The current compiled iroutine
152 readable var _iroutine: IRoutine
153
154 # The return label of the current compiling C function
155 readable writable var _return_label: nullable ISeq = null
156
157 fun add_decl(s: String)
158 do
159 visitor.add_decl(s)
160 end
161
162 fun add_instr(s: String)
163 do
164 var l = _next_location
165 if l != null then
166 visitor.add_instr("/* ", l.file, ":", l.line_start.to_s, " */")
167 _next_location = null
168 end
169 visitor.add_instr(s)
170 end
171
172 fun indent
173 do
174 visitor.indent
175 end
176
177 fun unindent
178 do
179 visitor.unindent
180 end
181
182 fun add_assignment(to, from: String)
183 do
184 visitor.add_assignment(to, from)
185 end
186
187 var _last_location: nullable Location = null
188 var _next_location: nullable Location = null
189
190 # Add location information in a comment
191 # Do nothing if the last location added is the same
192 fun add_location(l: nullable Location)
193 do
194 var last = _last_location
195 if last == l or l == null then return
196 _last_location = l
197 if last != null and last.file == l.file and last.line_start == l.line_start then
198 return
199 else
200 _next_location = l
201 end
202 end
203
204 # The C fonction name of the iroutine
205 readable var _basecname: String
206
207 init(v: CompilerVisitor, ir: IRoutine, cname: String)
208 do
209 _visitor = v
210 _iroutine = ir
211 _basecname = cname
212 end
213 end
214
215 redef class IRoutine
216 # Declare and start a C function that match the routine
217 # Return what must be given to compile_inside_to_c or to compile_to_c
218 # After the method, an openinig { and and indent is added.
219 # So, do not forget to add a sub_context, to unintent and to add a closing }
220 fun compile_signature_to_c(v: CompilerVisitor, cname: String, human_name: nullable String, before_params, after_params: nullable String): Array[String]
221 do
222 var cargs = new Array[String]
223 var cparams = new Array[String]
224 if before_params != null then cparams.add(before_params)
225 for i in [0..params.length[ do
226 cargs.add("p{i}")
227 cparams.add("val_t p{i}")
228 end
229 if closure_decls != null then
230 cparams.add("struct stack_frame_t *closctx_param")
231 for i in [0..closure_decls.length[ do
232 var closcn = "CLOS_{cname}_{i}"
233 var cs = closure_decls[i].closure.signature
234 var subparams = new Array[String] # Parameters of the closure
235 subparams.add("struct stack_frame_t *")
236 for j in [0..cs.arity[ do
237 subparams.add("val_t")
238 end
239 var rr = "void"
240 if cs.return_type != null then rr = "val_t"
241 v.add_decl("typedef {rr} (*{closcn})({subparams.join(", ")});")
242 cargs.add("clos_fun{i}")
243 cparams.add("fun_t clos_fun{i}")
244 end
245 end
246 if after_params != null then cparams.add(after_params)
247 var r = "void"
248 if result != null then r = "val_t"
249 var p: String
250 if cparams.is_empty then
251 p = "void"
252 else
253 p = cparams.join(", ")
254 end
255 if human_name != null then v.add_decl("#define LOCATE_", cname, " \"", human_name, "\"")
256 v.add_decl(r, " ", cname, "(", p, ");")
257 v.add_decl("typedef ", r, " (*", cname, "_t)(", p, ");")
258 v.add_instr(r, " ", cname, "(", p, ")\{")
259 v.indent
260 return cargs
261 end
262
263 # Compile the body of the routine, return the result value is any
264 fun compile_inside_to_c(v: I2CCompilerVisitor, args: Array[String]): nullable String
265 do
266 # Create and push the stack frame
267 var ll = 0
268 if location != null then
269 ll = location.line_start
270 end
271 # Encapsulate the frame ('me') in a larger structure ('fra') that has enough space to store the local variables (REG)
272 if std_slots_nb > 1 then
273 v.add_decl("struct \{struct stack_frame_t me; val_t MORE_REG[{std_slots_nb-1}];\} fra;")
274 else
275 v.add_decl("struct \{struct stack_frame_t me;\} fra;")
276 end
277 v.add_instr("fra.me.prev = stack_frame_head; stack_frame_head = &fra.me;")
278 v.add_instr("fra.me.file = LOCATE_{v.visitor.module.name};")
279 v.add_instr("fra.me.line = {ll};")
280 v.add_instr("fra.me.meth = LOCATE_{v.basecname};")
281 v.add_instr("fra.me.has_broke = 0;")
282 v.add_instr("fra.me.REG_size = {std_slots_nb};")
283
284 # Declare/initialize local variables
285 for i in [0..std_slots_nb[ do
286 v.add_instr("fra.me.REG[{i}] = NIT_NULL;")
287 end
288 for i in [0..tag_slots_nb[ do
289 v.add_decl("val_t REGB{i};")
290 end
291 var iclosdecls = closure_decls
292 if iclosdecls != null then
293 v.add_decl("fun_t CREG[{iclosdecls.length}];")
294 v.add_instr("fra.me.closure_ctx = closctx_param;")
295 v.add_instr("fra.me.closure_funs = CREG;")
296 end
297 var k = 0
298 for r in params do
299 if r.slot_index != null then v.add_assignment(v.register(r), args[k])
300 k += 1
301 end
302 if iclosdecls != null then
303 for i in [0..iclosdecls.length[ do
304 var iclosdecl = iclosdecls[i]
305 v.add_instr("CREG[{i}] = {args[params.length+i]};")
306 v.closures[iclosdecl] = i
307 var cs = iclosdecl.closure.signature # Closure signature
308 var subparams = new Array[String] # Parameters of the closure
309 subparams.add("struct stack_frame_t *")
310 for j in [0..cs.arity[ do
311 var p = "val_t"
312 subparams.add(p)
313 end
314 var r = "void"
315 if cs.return_type != null then r = "val_t"
316 v.clostypes[iclosdecl] = "{r} (*)({subparams.join(", ")})"
317 end
318 end
319 v.add_decl("val_t tmp;")
320
321 # Prepare return
322 var old_rl = v.return_label
323 v.return_label = body
324
325 # Compile body
326 body.compile_to_c(v)
327
328 v.add_instr("stack_frame_head = fra.me.prev;")
329 v.return_label = old_rl
330 var r = result
331 if r != null then
332 return v.register(r)
333 else
334 return null
335 end
336 end
337
338 # Full compilation of the routine
339 # cv must be in the correct function
340 fun compile_to_c(cv: CompilerVisitor, cname: String, args: Array[String]): nullable String
341 do
342 var v = new I2CCompilerVisitor(cv, self, cname)
343 return compile_inside_to_c(v, args)
344 end
345 end
346
347 redef class ICode
348 # Full compilation of the icode
349 fun compile_to_c(v: I2CCompilerVisitor)
350 do
351 v.add_location(location)
352 store_result(v, inner_compile_to_c(v))
353 end
354
355 # Is a result really needed
356 private fun need_result: Bool
357 do
358 var r = result
359 return r != null and r.slot_index != null
360 end
361
362 # Store s in the result value of self
363 private fun store_result(v: I2CCompilerVisitor, s: nullable String)
364 do
365 var r = result
366 if r != null and r.slot_index != null then
367 assert s != null
368 v.add_assignment(v.register(r), s)
369 else if s != null and not is_pure then
370 # ICode with side effects must be evaluated
371 # even if the result is not wanted
372 v.add_instr(s + ";")
373 end
374 end
375
376 # Compilation of without the result assigment
377 # Return the right value is case of expression
378 # Return the full expression (witout ;) in case of statement
379 private fun inner_compile_to_c(v: I2CCompilerVisitor): nullable String is abstract
380 end
381
382 redef class ISeq
383 redef fun inner_compile_to_c(v)
384 do
385 v.local_labels.add(self)
386 var mark = iescape_mark
387 if mark != null then v.marks_to_seq[mark] = self
388 for ic in icodes do
389 ic.compile_to_c(v)
390 end
391 v.add_label(self)
392 return null
393 end
394 end
395
396 redef class IIf
397 redef fun inner_compile_to_c(v)
398 do
399 v.add_instr("if (UNTAG_Bool({v.register(expr)})) \{")
400 if not then_seq.icodes.is_empty then
401 v.indent
402 then_seq.inner_compile_to_c(v)
403 v.unindent
404 end
405 if not else_seq.icodes.is_empty then
406 v.add_instr("} else \{")
407 v.indent
408 else_seq.inner_compile_to_c(v)
409 v.unindent
410 end
411 v.add_instr("}")
412 return null
413 end
414 end
415
416 redef class ILoop
417 redef fun inner_compile_to_c(v)
418 do
419 v.local_labels.add(self)
420 var mark = iescape_mark
421 if mark != null then v.marks_to_seq[mark] = self
422 v.add_instr("while(1) \{")
423 v.indent
424 for ic in icodes do
425 ic.compile_to_c(v)
426 end
427 v.unindent
428 v.add_instr("}")
429 v.add_label(self)
430 return null
431 end
432 end
433
434 redef class IEscape
435 redef fun inner_compile_to_c(v)
436 do
437 v.add_goto(v.marks_to_seq[iescape_mark])
438 return null
439 end
440 end
441
442 redef class IAbsCall
443 redef fun compile_to_c(v)
444 do
445 v.add_location(location)
446 var args = v.registers(exprs)
447
448 # Compile closure definitions
449 var old_el = v.escaped_labels
450 var closdefs = closure_defs
451 var closctx: nullable String = null # The closure context of closdefs
452 if closdefs != null then
453 # Get the closure context
454 if v.closure then
455 closctx = "closctx"
456 else
457 closctx = "(&(fra.me))"
458 end
459
460 # First aditionnal arguments is the closure context
461 args.add(closctx)
462
463 # We are in a new escape boundary
464 v.escaped_labels = new HashMap[ISeq, Int]
465
466 # Compile each closures and add each sub-function as an other additionnal parameter
467 for cd in closdefs do
468 if cd != null then
469 var cn = cd.compile_closure(v)
470 args.add(cn)
471 else
472 args.add("NULL")
473 end
474 end
475 end
476
477 # Compile the real call
478 var s = compile_call_to_c(v, args)
479 var r: nullable String = s
480
481 # Intercept escapes
482 if closctx != null then
483 var els = v.escaped_labels
484 v.escaped_labels = old_el
485 # Is there possible escapes?
486 if not els.is_empty then
487 # Call in a tmp variable to avoid 'break' overwrite
488 if need_result then
489 r = "tmp"
490 v.add_assignment(r, s)
491 else
492 r = null
493 v.add_instr(s + ";")
494 end
495 # What are the expected escape indexes
496 v.add_instr("switch ({closctx}->has_broke) \{")
497 v.indent
498 # No escape occured, continue as usual
499 v.add_instr("case 0: break;")
500 var lls = v.local_labels
501 var iels = els.iterator
502 var forward_escape = false
503 while iels.is_ok do
504 var seq = iels.key
505 if lls.has(seq) then
506 # Local escape occured
507 # Clear the has_broke information and go to the target
508 v.add_instr("case {iels.item}: {closctx}->has_broke = 0; goto {v.lab(seq)};")
509 else
510 # Forward escape occured: register the escape label
511 assert v.closure
512 v.register_escape_label(seq)
513 forward_escape = true
514 end
515 iels.next
516 end
517 # If forward escape occured, just pass to the next one
518 if forward_escape then
519 # Do not need to copy 'has_broke' value since it is shared by the next one.
520 # So just exit the C function.
521 v.add_instr("default: goto {v.lab(v.return_label.as(not null))};")
522 end
523 v.unindent
524 v.add_instr("\}")
525 end
526 end
527
528 store_result(v, r)
529 end
530
531 redef fun inner_compile_to_c(v) do abort
532
533 # The single invocation witout fancy stuffs
534 private fun compile_call_to_c(v: I2CCompilerVisitor, args: Array[String]): String is abstract
535 end
536
537 redef class ICall
538 redef fun compile_call_to_c(v, args)
539 do
540 var prop = property
541 if prop.global.is_init then args.add("init_table")
542 if prop.name == (once ("add".to_symbol)) and prop.local_class.name == (once ("Array".to_symbol)) then
543 return "{prop.cname}({args.join(", ")})"
544 else
545 return "{prop.global.meth_call}({args[0]})({args.join(", ")})"
546 end
547 end
548 end
549
550 redef class ISuper
551 redef fun compile_call_to_c(v, args)
552 do
553 var prop = property
554 if prop.global.is_init then args.add("init_table")
555 return "{prop.super_meth_call}({args[0]})({args.join(", ")})"
556 end
557 end
558
559 redef class INew
560 redef fun compile_call_to_c(v, args)
561 do
562 return "NEW_{stype.local_class}_{property.global.intro.cname}({args.join(", ")})"
563 end
564 end
565
566 redef class IAllocateInstance
567 redef fun inner_compile_to_c(v)
568 do
569 return "NEW_{stype.local_class.name}()"
570 end
571 end
572
573 redef class ICheckInstance
574 redef fun inner_compile_to_c(v)
575 do
576 return "CHECKNEW_{stype.local_class.name}({v.register(expr)})"
577 end
578 end
579
580 redef class IInitAttributes
581 redef fun inner_compile_to_c(v)
582 do
583 return "INIT_ATTRIBUTES__{stype.local_class.name}({v.register(expr)})"
584 end
585 end
586
587 redef class IStaticCall
588 redef fun compile_call_to_c(v, args)
589 do
590 var prop = property
591 if prop.global.is_init then args.add("init_table")
592 return "{property.cname}({args.join(", ")})"
593 end
594 end
595
596 redef class INative
597 redef fun inner_compile_to_c(v)
598 do
599 if exprs.is_empty then
600 return code
601 else
602 var res = new Buffer
603 var i = 0
604 var c = code.split_with("@@@")
605 for s in c do
606 res.append(s)
607 if i < exprs.length and i < c.length-1 then
608 res.append(v.register(exprs[i]))
609 end
610 i += 1
611 end
612 return res.to_s
613 end
614 end
615 end
616
617 redef class IAbort
618 redef fun inner_compile_to_c(v)
619 do
620 var s = new Buffer.from("fprintf(stderr")
621 for t in texts do
622 s.append(", \"{t}\"")
623 end
624 s.append(");")
625 v.add_instr(s.to_s)
626
627 var ll = location
628 s = new Buffer.from("fprintf(stderr, \" (%s")
629 if ll != null then
630 s.append(":%d")
631 end
632 s.append(")\\n\", LOCATE_{module_location.name}")
633 if ll != null then
634 s.append(", {ll.line_start}")
635 end
636 s.append(");")
637 v.add_instr(s.to_s)
638
639 v.add_instr("nit_exit(1);")
640 return null
641 end
642 end
643
644 redef class IMove
645 redef fun inner_compile_to_c(v)
646 do
647 return v.register(expr)
648 end
649 end
650
651 redef class IAttrRead
652 redef fun inner_compile_to_c(v)
653 do
654 return "{property.global.attr_access}({v.register(expr)})"
655 end
656 end
657
658 redef class IAttrIsset
659 redef fun inner_compile_to_c(v)
660 do
661 return "TAG_Bool({property.global.attr_access}({v.register(expr)})!=NIT_NULL)"
662 end
663 end
664
665 redef class IAttrWrite
666 redef fun inner_compile_to_c(v)
667 do
668 v.add_instr("{property.global.attr_access}({v.register(expr1)}) = {v.register(expr2)};")
669 return null
670 end
671 end
672
673 redef class ITypeCheck
674 redef fun inner_compile_to_c(v)
675 do
676 # FIXME handle formaltypes
677 var g = stype.local_class.global
678 var recv = v.register(expr)
679 var s = ""
680 if expr.stype.is_nullable then
681 if stype.is_nullable then
682 s = "({recv}==NIT_NULL) || "
683 else if stype.as_nullable == expr.stype then
684 return "TAG_Bool({recv}!=NIT_NULL)"
685 else
686 s = "({recv}!=NIT_NULL) && "
687 end
688 end
689 return "TAG_Bool({s}VAL_ISA({recv}, {g.color_id}, {g.id_id})) /*cast {stype}*/"
690 end
691 end
692
693 redef class IIs
694 redef fun inner_compile_to_c(v)
695 do
696 var t1 = expr1.stype
697 var t2 = expr2.stype
698 if t1 isa MMTypeNone then
699 if t2 isa MMTypeNone then
700 return "TAG_Bool(1)"
701 else if t2.is_nullable then
702 return "TAG_Bool({v.register(expr2)}==NIT_NULL)"
703 else
704 return "TAG_Bool(0)"
705 end
706 else if t1.is_nullable then
707 if t2 isa MMTypeNone then
708 return "TAG_Bool({v.register(expr1)}==NIT_NULL)"
709 else if t2.is_nullable then
710 return "TAG_Bool(IS_EQUAL_NN({v.register(expr1)},{v.register(expr2)}))"
711 else
712 return "TAG_Bool(IS_EQUAL_ON({v.register(expr2)},{v.register(expr1)}))"
713 end
714 else
715 if t2 isa MMTypeNone then
716 return "TAG_Bool(0)"
717 else if t2.is_nullable then
718 return "TAG_Bool(IS_EQUAL_ON({v.register(expr1)},{v.register(expr2)}))"
719 else
720 return "TAG_Bool(IS_EQUAL_OO({v.register(expr1)},{v.register(expr2)}))"
721 end
722 end
723 end
724 end
725
726 redef class INot
727 redef fun inner_compile_to_c(v)
728 do
729 return "TAG_Bool(!UNTAG_Bool({v.register(expr)}))"
730 end
731 end
732
733 redef class IOnce
734 redef fun inner_compile_to_c(v)
735 do
736 var i = v.new_number
737 var res = result.as(not null)
738 if res.stype.is_nullable then
739 v.add_decl("static val_t once_value_{i}; static int once_bool_{i}; /* Once value */")
740 v.add_instr("if (!once_bool_{i}) \{")
741 else
742 # Since the value is not nullable, we use the null value to represent the boolean
743 v.add_decl("static val_t once_value_{i}; /* Once value */")
744 v.add_instr("if (!once_value_{i}) \{")
745 end
746 v.indent
747 body.compile_to_c(v)
748 var e = v.register(result.as(not null))
749 v.add_instr("once_value_{i} = {e};")
750 v.add_instr("register_static_object(&once_value_{i});")
751 if res.stype.is_nullable then v.add_instr("once_bool_{i} = true;")
752 v.unindent
753 v.add_instr("} else {e} = once_value_{i};")
754 return e
755 end
756 end
757
758 redef class IClosCall
759 redef fun compile_to_c(v: I2CCompilerVisitor)
760 do
761 v.add_location(location)
762 var ivar: String
763 var args: Array[String]
764 if v.closure then
765 ivar = "closctx->closure_funs[{v.closures[closure_decl]}]"
766 args = ["closctx->closure_ctx"]
767 else
768 ivar = "CREG[{v.closures[closure_decl]}]"
769 args = ["closctx_param"]
770 end
771 args.append(v.registers(exprs))
772
773 var s = "(({v.clostypes[closure_decl]})({ivar}))({args.join(", ")})"
774 store_result(v, s)
775
776 # Intercept escape
777 v.add_instr("if ({args.first}->has_broke) \{")
778 v.indent
779 var bs = break_seq
780 if bs != null then
781 bs.compile_to_c(v)
782 end
783 v.add_goto(v.iroutine.body)
784 v.unindent
785 v.add_instr("\}")
786 end
787
788 redef fun inner_compile_to_c(v) do abort
789 end
790
791 redef class IHasClos
792 redef fun inner_compile_to_c(v)
793 do
794 var ivar: String
795 if v.closure then
796 ivar = "closctx->closure_funs[{v.closures[closure_decl]}]"
797 else
798 ivar = "CREG[{v.closures[closure_decl]}]"
799 end
800 return "TAG_Bool({ivar} != NULL)"
801 end
802 end
803
804 redef class IClosureDef
805 # Compile the closure as a separate C function in the visitor out_contexts.
806 # Return a fun_t pointer to the function.
807 fun compile_closure(v: I2CCompilerVisitor): String
808 do
809 var cv = v.visitor
810
811 # We are now in a closure
812 var cfc_old = v.closure
813 v.closure = true
814
815 # We are now in a escape boundary
816 var lls_old = v.local_labels
817 v.local_labels = new HashSet[ISeq]
818
819 # We are now in a new C context
820 var ctx_old = cv.ctx
821 cv.ctx = new CContext
822 cv.out_contexts.add(cv.ctx)
823
824 # Generate the C function
825 var cname = "OC_{v.basecname}_{v.new_number}"
826 var args = compile_signature_to_c(v.visitor, cname, null, "struct stack_frame_t *closctx", null)
827 var ctx_old2 = cv.ctx
828 cv.ctx = new CContext
829 var s = compile_inside_to_c(v, args)
830 if s == null then
831 v.add_instr("return;")
832 else
833 v.add_instr("return {s};")
834 end
835 ctx_old2.append(cv.ctx)
836 cv.ctx = ctx_old2
837 v.unindent
838 v.add_instr("}")
839
840 # Restore things
841 cv.ctx = ctx_old
842 v.closure = cfc_old
843 v.local_labels = lls_old
844 return "((fun_t){cname})"
845 end
846 end