nitg: add dangerous options to disable runtime tests
[nit.git] / src / separate_compiler.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Separate compilation of a Nit program
16 module separate_compiler
17
18
19 import global_compiler # TODO better separation of concerns
20 intrude import coloring
21 redef class ToolContext
22 # --separate
23 var opt_separate: OptionBool = new OptionBool("Use separate compilation", "--separate")
24
25 # --no-inline-intern
26 var opt_no_inline_intern: OptionBool = new OptionBool("Do not inline call to intern methods", "--no-inline-intern")
27
28 redef init
29 do
30 super
31 self.option_context.add_option(self.opt_separate)
32 self.option_context.add_option(self.opt_no_inline_intern)
33 end
34 end
35
36 redef class ModelBuilder
37 fun run_separate_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis)
38 do
39 var time0 = get_time
40 self.toolcontext.info("*** COMPILING TO C ***", 1)
41
42 var compiler = new SeparateCompiler(mainmodule, runtime_type_analysis, self)
43 var v = compiler.new_visitor
44 compiler.header = v
45 v.add_decl("#include <stdlib.h>")
46 v.add_decl("#include <stdio.h>")
47 v.add_decl("#include <string.h>")
48 v.add_decl("#include <gc/gc.h>")
49 v.add_decl("typedef void(*nitmethod_t)(void); /* general C type representing a Nit method. */")
50 v.add_decl("typedef void* nitattribute_t; /* general C type representing a Nit attribute. */")
51
52 # Class abstract representation
53 v.add_decl("struct class \{ int box_kind; nitmethod_t vft[1]; \}; /* general C type representing a Nit class. */")
54 # Type abstract representation
55 v.add_decl("struct type \{ int id; int color; int livecolor; short int is_nullable; struct vts_table *vts_table; struct fts_table *fts_table; int table_size; int type_table[1]; \}; /* general C type representing a Nit type. */")
56 v.add_decl("struct fts_table \{ struct type *fts[1]; \}; /* fts list of a C type representation. */")
57 v.add_decl("struct vts_table \{ struct type *vts[1]; \}; /* vts list of a C type representation. */")
58 # Instance abstract representation
59 v.add_decl("typedef struct \{ struct type *type; struct class *class; nitattribute_t attrs[1]; \} val; /* general C type representing a Nit instance. */")
60
61 compiler.compile_box_kinds
62
63 # Declare global instances
64 v.add_decl("extern int glob_argc;")
65 v.add_decl("extern char **glob_argv;")
66 v.add_decl("extern val *glob_sys;")
67
68 # The main function of the C
69 compiler.compile_main_function
70
71 # compile class structures
72 for m in mainmodule.in_importation.greaters do
73 for mclass in m.intro_mclasses do
74 compiler.compile_class_to_c(mclass)
75 end
76 end
77
78 # compile methods
79 for m in mainmodule.in_importation.greaters do
80 compiler.compile_module_to_c(m)
81 end
82
83 # compile live & cast type structures
84 var mtypes = compiler.do_global_type_coloring
85 for t in mtypes do
86 compiler.compile_type_to_c(t)
87 end
88
89 # compile live generic types selection structures
90 for mclass in model.mclasses do
91 compiler.compile_live_gentype_to_c(mclass)
92 end
93
94 # for the class_name and output_class_name methods
95 compiler.compile_class_names
96
97 write_and_make(compiler)
98 end
99 end
100
101 # Singleton that store the knowledge about the separate compilation process
102 class SeparateCompiler
103 super GlobalCompiler # TODO better separation of concerns
104
105 private var undead_types: Set[MType] = new HashSet[MType]
106 protected var typeids: HashMap[MType, Int] protected writable = new HashMap[MType, Int]
107
108 private var type_colors: Map[MType, Int] = typeids
109 private var type_tables: nullable Map[MType, Array[nullable MType]] = null
110
111 private var livetypes_colors: nullable Map[MType, Int]
112 private var livetypes_tables: nullable Map[MClass, Array[nullable Object]]
113 private var livetypes_tables_sizes: nullable Map[MClass, Array[Int]]
114
115 protected var class_colors: Map[MClass, Int] protected writable
116
117 protected var method_colors: Map[MMethod, Int] protected writable
118 protected var method_tables: Map[MClass, Array[nullable MMethodDef]] protected writable
119
120 protected var attr_colors: Map[MAttribute, Int] protected writable
121 protected var attr_tables: Map[MClass, Array[nullable MAttributeDef]] protected writable
122
123 private var vt_colors: Map[MVirtualTypeProp, Int]
124 private var vt_tables: Map[MClass, Array[nullable MVirtualTypeDef]]
125
126 private var ft_colors: Map[MParameterType, Int]
127 private var ft_tables: Map[MClass, Array[nullable MParameterType]]
128
129 init(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis, mmbuilder: ModelBuilder) do
130 # classes coloration
131 var class_coloring = new ClassColoring(mainmodule)
132 self.class_colors = class_coloring.colorize(mmbuilder.model.mclasses)
133
134 # methods coloration
135 var method_coloring = new MethodColoring(class_coloring)
136 self.method_colors = method_coloring.colorize
137 self.method_tables = method_coloring.build_property_tables
138
139 # attributes coloration
140 var attribute_coloring = new AttributeColoring(class_coloring)
141 self.attr_colors = attribute_coloring.colorize
142 self.attr_tables = attribute_coloring.build_property_tables
143
144 # vt coloration
145 var vt_coloring = new VTColoring(class_coloring)
146 self.vt_colors = vt_coloring.colorize
147 self.vt_tables = vt_coloring.build_property_tables
148
149 # fts coloration
150 var ft_coloring = new FTColoring(class_coloring)
151 self.ft_colors = ft_coloring.colorize
152 self.ft_tables = ft_coloring.build_ft_tables
153 end
154
155 fun compile_box_kinds
156 do
157 # Collect all bas box class
158 # FIXME: this is not completely fine with a separate compilation scheme
159 for classname in ["Int", "Bool", "Char", "Float", "NativeString", "Pointer"] do
160 var classes = self.mainmodule.model.get_mclasses_by_name(classname)
161 if classes == null then continue
162 assert classes.length == 1 else print classes.join(", ")
163 self.box_kinds[classes.first] = self.box_kinds.length + 1
164 end
165 end
166
167 var box_kinds = new HashMap[MClass, Int]
168
169 fun box_kind_of(mclass: MClass): Int
170 do
171 if mclass.mclass_type.ctype == "val*" then
172 return 0
173 else if mclass.kind == extern_kind then
174 return self.box_kinds[self.mainmodule.get_primitive_class("Pointer")]
175 else
176 return self.box_kinds[mclass]
177 end
178
179 end
180
181 protected fun compile_class_names do
182
183 # Build type names table
184 var type_array = new Array[nullable MType]
185 for t, i in typeids do
186 if i >= type_array.length then
187 type_array[i] = null
188 end
189 type_array[i] = t
190 end
191
192 var v = self.new_visitor
193 self.header.add_decl("extern const char const * class_names[];")
194 v.add("const char const * class_names[] = \{")
195 for t in type_array do
196 if t == null then
197 v.add("NULL,")
198 else
199 v.add("\"{t}\",")
200 end
201 end
202 v.add("\};")
203 end
204
205 # colorize live types of the program
206 private fun do_global_type_coloring: Set[MType] do
207 var mtypes = new HashSet[MType]
208 mtypes.add_all(self.runtime_type_analysis.live_types)
209 mtypes.add_all(self.runtime_type_analysis.live_cast_types)
210 mtypes.add_all(self.undead_types)
211
212 self.undead_types.clear
213 for mtype in mtypes do
214 # add formal types arguments to mtypes
215 if mtype isa MGenericType then
216 for ft in mtype.arguments do
217 if ft.need_anchor then
218 print("Why do we need anchor here ?")
219 abort
220 end
221 self.undead_types.add(ft)
222 end
223 end
224 var mclass_type: MClassType
225 if mtype isa MNullableType then
226 mclass_type = mtype.mtype.as(MClassType)
227 else
228 mclass_type = mtype.as(MClassType)
229 end
230 # add virtual types to mtypes
231 for vt in self.vt_tables[mclass_type.mclass] do
232 if vt != null then
233 var anchored = vt.bound.anchor_to(self.mainmodule, mclass_type)
234 self.undead_types.add(anchored)
235 end
236 end
237 end
238 mtypes.add_all(self.undead_types)
239
240 # set type unique id
241 for mtype in mtypes do
242 self.typeids[mtype] = self.typeids.length
243 end
244
245 # colorize live entries
246 var entries_coloring = new LiveEntryColoring
247 self.livetypes_colors = entries_coloring.colorize(mtypes)
248 self.livetypes_tables = entries_coloring.build_livetype_tables(mtypes)
249 self.livetypes_tables_sizes = entries_coloring.livetypes_tables_sizes
250
251 # colorize types
252 var type_coloring = new TypeColoring(self.mainmodule, mtypes)
253 self.type_colors = type_coloring.colorize(mtypes)
254 self.type_tables = type_coloring.build_type_tables(mtypes, type_colors)
255
256 return mtypes
257 end
258
259 # declare live generic types tables selection
260 private fun compile_live_gentype_to_c(mclass: MClass) do
261 if mclass.arity > 0 then
262 if self.livetypes_tables.has_key(mclass) then
263 var table = self.livetypes_tables[mclass]
264 var sign = self.livetypes_tables_sizes[mclass]
265 var table_buffer = new Buffer.from("const struct type *livetypes_{mclass.c_name}[{sign.join("][")}] = \{\n")
266 compile_livetype_table(table, table_buffer, 1, mclass.arity)
267 table_buffer.append("\};")
268
269 var v = new SeparateCompilerVisitor(self)
270 self.header.add_decl("extern const struct type *livetypes_{mclass.c_name}[{sign.join("][")}];")
271 v.add_decl(table_buffer.to_s)
272 else
273 var sign = new Array[Int].filled_with(0, mclass.arity)
274 var v = new SeparateCompilerVisitor(self)
275 self.header.add_decl("extern const struct type *livetypes_{mclass.c_name}[{sign.join("][")}];")
276 v.add_decl("const struct type *livetypes_{mclass.c_name}[{sign.join("][")}];")
277 end
278 end
279 end
280
281 private fun compile_livetype_table(table: Array[nullable Object], buffer: Buffer, depth: Int, max: Int) do
282 for obj in table do
283 if obj == null then
284 if depth == max then
285 buffer.append("NULL,\n")
286 else
287 buffer.append("\{\},\n")
288 end
289 else if obj isa MClassType then
290 buffer.append("(struct type*) &type_{obj.c_name}, /* {obj} */\n")
291 else if obj isa Array[nullable Object] then
292 buffer.append("\{\n")
293 compile_livetype_table(obj, buffer, depth + 1, max)
294 buffer.append("\},\n")
295 end
296 end
297 end
298
299 # Separately compile all the method definitions of the module
300 fun compile_module_to_c(mmodule: MModule)
301 do
302 for cd in mmodule.mclassdefs do
303 for pd in cd.mpropdefs do
304 if not pd isa MMethodDef then continue
305 #print "compile {pd} @ {cd} @ {mmodule}"
306 var r = new SeparateRuntimeFunction(pd)
307 r.compile_to_c(self)
308 if true or cd.bound_mtype.ctype != "val*" then
309 var r2 = new VirtualRuntimeFunction(pd)
310 r2.compile_to_c(self)
311 end
312 end
313 end
314 end
315
316 # Globaly compile the type structure of a live type
317 fun compile_type_to_c(mtype: MType)
318 do
319 var c_name = mtype.c_name
320 var v = new SeparateCompilerVisitor(self)
321 v.add_decl("/* runtime type {mtype} */")
322
323 var mclass_type: MClassType
324 if mtype isa MNullableType then
325 mclass_type = mtype.mtype.as(MClassType)
326 else
327 mclass_type = mtype.as(MClassType)
328 end
329
330 # extern const struct type_X
331 self.header.add_decl("extern const struct type_{c_name} type_{c_name};")
332 self.header.add_decl("struct type_{c_name} \{")
333 self.header.add_decl("int id;")
334 self.header.add_decl("int color;")
335 self.header.add_decl("int livecolor;")
336 self.header.add_decl("short int is_nullable;")
337 self.header.add_decl("const struct vts_table_{c_name} *vts_table;")
338 self.header.add_decl("const struct fts_table_{c_name} *fts_table;")
339 self.header.add_decl("int table_size;")
340 self.header.add_decl("int type_table[{self.type_tables[mtype].length}];")
341 self.header.add_decl("\};")
342
343 # extern const struct vts_table_X vts_table_X
344 self.header.add_decl("extern const struct vts_table_{c_name} vts_table_{c_name};")
345 self.header.add_decl("struct vts_table_{c_name} \{")
346 self.header.add_decl("struct type *vts[{self.vt_tables[mclass_type.mclass].length}];")
347 self.header.add_decl("\};")
348
349 # extern const struct fst_table_X fst_table_X
350 self.header.add_decl("extern const struct fts_table_{c_name} fts_table_{c_name};")
351 self.header.add_decl("struct fts_table_{c_name} \{")
352 self.header.add_decl("struct type *fts[{self.ft_tables[mclass_type.mclass].length}];")
353 self.header.add_decl("\};")
354
355 # const struct type_X
356 v.add_decl("const struct type_{c_name} type_{c_name} = \{")
357 v.add_decl("{self.typeids[mtype]},")
358 v.add_decl("{self.type_colors[mtype]},")
359 v.add_decl("{self.livetypes_colors[mtype]},")
360 if mtype isa MNullableType then
361 v.add_decl("1,")
362 else
363 v.add_decl("0,")
364 end
365 v.add_decl("&vts_table_{c_name},")
366 v.add_decl("&fts_table_{c_name},")
367 v.add_decl("{self.type_tables[mtype].length},")
368 v.add_decl("\{")
369 for stype in self.type_tables[mtype] do
370 if stype == null then
371 v.add_decl("-1, /* empty */")
372 else
373 v.add_decl("{self.typeids[stype]}, /* {stype} */")
374 end
375 end
376 v.add_decl("\},")
377 v.add_decl("\};")
378
379 build_fts_table(mtype, v)
380 build_vts_table(mtype, v)
381 end
382
383 # const struct fst_table_X fst_table_X
384 private fun build_fts_table(mtype: MType, v: SeparateCompilerVisitor) do
385 v.add_decl("const struct fts_table_{mtype.c_name} fts_table_{mtype.c_name} = \{")
386 v.add_decl("\{")
387
388 var mclass_type: MClassType
389 if mtype isa MNullableType then
390 mclass_type = mtype.mtype.as(MClassType)
391 else
392 mclass_type = mtype.as(MClassType)
393 end
394
395 for ft in self.ft_tables[mclass_type.mclass] do
396 if ft == null then
397 v.add_decl("NULL, /* empty */")
398 else
399 var ntype: MType
400 if ft.mclass == mclass_type.mclass then
401 ntype = mclass_type.arguments[ft.rank]
402 else
403 ntype = ft.anchor_to(self.mainmodule, mclass_type)
404 end
405 if self.typeids.has_key(ntype) then
406 v.add_decl("(struct type*)&type_{ntype.c_name}, /* {ft} ({ntype}) */")
407 else
408 v.add_decl("NULL, /* empty ({ft} not a live type) */")
409 end
410 end
411 end
412 v.add_decl("\},")
413 v.add_decl("\};")
414 end
415
416 # const struct vts_table_X vts_table_X
417 private fun build_vts_table(mtype: MType, v: SeparateCompilerVisitor) do
418 v.add_decl("const struct vts_table_{mtype.c_name} vts_table_{mtype.c_name} = \{")
419 v.add_decl("\{")
420
421 var mclass_type: MClassType
422 if mtype isa MNullableType then
423 mclass_type = mtype.mtype.as(MClassType)
424 else
425 mclass_type = mtype.as(MClassType)
426 end
427
428 for vt in self.vt_tables[mclass_type.mclass] do
429 if vt == null then
430 v.add_decl("NULL, /* empty */")
431 else
432 var bound = vt.bound
433 if bound == null then
434 #FIXME how can a bound be null here ?
435 print "No bound found for virtual type {vt} ?"
436 abort
437 else
438 var ntype = bound
439 if ntype isa MNullableType then ntype = ntype.mtype
440 if ntype isa MVirtualType then
441 bound = ntype.anchor_to(self.mainmodule, mclass_type)
442 else if ntype isa MParameterType then
443 bound = ntype.anchor_to(self.mainmodule, mclass_type)
444 else if ntype isa MGenericType and bound.need_anchor then
445 bound = ntype.anchor_to(self.mainmodule, mclass_type)
446 else if ntype isa MClassType then
447 else
448 print "NOT YET IMPLEMENTED: mtype_to_livetype with type: {ntype}"
449 abort
450 end
451
452 if self.typeids.has_key(bound) then
453 v.add_decl("(struct type*)&type_{bound.c_name}, /* {ntype} */")
454 else
455 v.add_decl("NULL, /* dead type {ntype} */")
456 end
457 end
458 end
459 end
460 v.add_decl("\},")
461 v.add_decl("\};")
462 end
463
464 # Globally compile the table of the class mclass
465 # In a link-time optimisation compiler, tables are globally computed
466 # In a true separate compiler (a with dynamic loading) you cannot do this unfortnally
467 fun compile_class_to_c(mclass: MClass)
468 do
469 var mtype = mclass.intro.bound_mtype
470 var c_name = mclass.c_name
471
472 var vft = self.method_tables[mclass]
473 var attrs = self.attr_tables[mclass]
474 var v = new SeparateCompilerVisitor(self)
475
476 v.add_decl("/* runtime class {c_name} */")
477 var idnum = classids.length
478 var idname = "ID_" + c_name
479 self.classids[mtype] = idname
480 #self.header.add_decl("#define {idname} {idnum} /* {c_name} */")
481
482 self.header.add_decl("struct class_{c_name} \{")
483 self.header.add_decl("int box_kind;")
484 self.header.add_decl("nitmethod_t vft[{vft.length}];")
485 self.header.add_decl("\};")
486
487 # Build class vft
488 self.header.add_decl("extern const struct class_{c_name} class_{c_name};")
489 v.add_decl("const struct class_{c_name} class_{c_name} = \{")
490 v.add_decl("{self.box_kind_of(mclass)}, /* box_kind */")
491 v.add_decl("\{")
492 for i in [0 .. vft.length[ do
493 var mpropdef = vft[i]
494 if mpropdef == null then
495 v.add_decl("NULL, /* empty */")
496 else
497 if true or mpropdef.mclassdef.bound_mtype.ctype != "val*" then
498 v.add_decl("(nitmethod_t)VIRTUAL_{mpropdef.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
499 else
500 v.add_decl("(nitmethod_t){mpropdef.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
501 end
502 end
503 end
504 v.add_decl("\}")
505 v.add_decl("\};")
506
507 if mtype.ctype != "val*" then
508 #Build instance struct
509 self.header.add_decl("struct instance_{c_name} \{")
510 self.header.add_decl("const struct type *type;")
511 self.header.add_decl("const struct class *class;")
512 self.header.add_decl("{mtype.ctype} value;")
513 self.header.add_decl("\};")
514
515 if not self.runtime_type_analysis.live_types.has(mtype) then return
516
517 self.header.add_decl("val* BOX_{c_name}({mtype.ctype});")
518 v.add_decl("/* allocate {mtype} */")
519 v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value) \{")
520 v.add("struct instance_{c_name}*res = GC_MALLOC(sizeof(struct instance_{c_name}));")
521 v.add("res->type = (struct type*) &type_{c_name};")
522 v.add("res->class = (struct class*) &class_{c_name};")
523 v.add("res->value = value;")
524 v.add("return (val*)res;")
525 v.add("\}")
526 return
527 end
528
529 var is_native_array = mclass.name == "NativeArray"
530
531 var sig
532 if is_native_array then
533 sig = "int length, struct type* type"
534 else
535 sig = "struct type* type"
536 end
537
538 #Build instance struct
539 #extern const struct instance_array__NativeArray instance_array__NativeArray;
540 self.header.add_decl("struct instance_{c_name} \{")
541 self.header.add_decl("const struct type *type;")
542 self.header.add_decl("const struct class *class;")
543 self.header.add_decl("nitattribute_t attrs[{attrs.length}];")
544 if is_native_array then
545 # NativeArrays are just a instance header followed by an array of values
546 self.header.add_decl("val* values[0];")
547 end
548 self.header.add_decl("\};")
549
550
551 self.header.add_decl("{mtype.ctype} NEW_{c_name}({sig});")
552 v.add_decl("/* allocate {mtype} */")
553 v.add_decl("{mtype.ctype} NEW_{c_name}({sig}) \{")
554 var res = v.new_named_var(mtype, "self")
555 res.is_exact = true
556 if is_native_array then
557 var mtype_elt = mtype.arguments.first
558 v.add("{res} = GC_MALLOC(sizeof(struct instance_{c_name}) + length*sizeof({mtype_elt.ctype}));")
559 else
560 v.add("{res} = GC_MALLOC(sizeof(struct instance_{c_name}));")
561 end
562 #v.add("{res} = calloc(sizeof(struct instance_{c_name}), 1);")
563 v.add("{res}->type = type;")
564 v.add("{res}->class = (struct class*) &class_{c_name};")
565
566 for cd in mtype.collect_mclassdefs(self.mainmodule)
567 do
568 var n = self.modelbuilder.mclassdef2nclassdef[cd]
569 for npropdef in n.n_propdefs do
570 if npropdef isa AAttrPropdef then
571 npropdef.init_expr(v, res)
572 end
573 end
574 end
575 v.add("return {res};")
576 v.add("\}")
577 end
578
579 redef fun new_visitor do return new SeparateCompilerVisitor(self)
580 end
581
582 # The C function associated to a methoddef separately compiled
583 class SeparateRuntimeFunction
584 super AbstractRuntimeFunction
585
586 redef fun build_c_name: String
587 do
588 return "{mmethoddef.c_name}"
589 end
590
591 redef fun to_s do return self.mmethoddef.to_s
592
593 redef fun compile_to_c(compiler)
594 do
595 var mmethoddef = self.mmethoddef
596
597 var recv = self.mmethoddef.mclassdef.bound_mtype
598 var v = compiler.new_visitor
599 var selfvar = new RuntimeVariable("self", recv, recv)
600 var arguments = new Array[RuntimeVariable]
601 var frame = new Frame(v, mmethoddef, recv, arguments)
602 v.frame = frame
603
604 var msignature = mmethoddef.msignature.resolve_for(mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.mmodule, true)
605
606 var sig = new Buffer
607 var comment = new Buffer
608 var ret = msignature.return_mtype
609 if ret != null then
610 sig.append("{ret.ctype} ")
611 else if mmethoddef.mproperty.is_new then
612 ret = recv
613 sig.append("{ret.ctype} ")
614 else
615 sig.append("void ")
616 end
617 sig.append(self.c_name)
618 sig.append("({selfvar.mtype.ctype} {selfvar}")
619 comment.append("(self: {selfvar}")
620 arguments.add(selfvar)
621 for i in [0..msignature.arity[ do
622 var mtype = msignature.mparameters[i].mtype
623 if i == msignature.vararg_rank then
624 mtype = v.get_class("Array").get_mtype([mtype])
625 end
626 comment.append(", {mtype}")
627 sig.append(", {mtype.ctype} p{i}")
628 var argvar = new RuntimeVariable("p{i}", mtype, mtype)
629 arguments.add(argvar)
630 end
631 sig.append(")")
632 comment.append(")")
633 if ret != null then
634 comment.append(": {ret}")
635 end
636 compiler.header.add_decl("{sig};")
637
638 v.add_decl("/* method {self} for {comment} */")
639 v.add_decl("{sig} \{")
640 if ret != null then
641 frame.returnvar = v.new_var(ret)
642 end
643 frame.returnlabel = v.get_name("RET_LABEL")
644
645 if recv != arguments.first.mtype then
646 #print "{self} {recv} {arguments.first}"
647 end
648 mmethoddef.compile_inside_to_c(v, arguments)
649
650 v.add("{frame.returnlabel.as(not null)}:;")
651 if ret != null then
652 v.add("return {frame.returnvar.as(not null)};")
653 end
654 v.add("\}")
655 end
656 end
657
658 # The C function associated to a methoddef on a primitive type, stored into a VFT of a class
659 # The first parameter (the reciever) is always typed by val* in order to accept an object value
660 class VirtualRuntimeFunction
661 super AbstractRuntimeFunction
662
663 redef fun build_c_name: String
664 do
665 return "VIRTUAL_{mmethoddef.c_name}"
666 end
667
668 redef fun to_s do return self.mmethoddef.to_s
669
670 redef fun compile_to_c(compiler)
671 do
672 var mmethoddef = self.mmethoddef
673
674 var recv = self.mmethoddef.mclassdef.bound_mtype
675 var v = compiler.new_visitor
676 var selfvar = new RuntimeVariable("self", v.object_type, recv)
677 var arguments = new Array[RuntimeVariable]
678 var frame = new Frame(v, mmethoddef, recv, arguments)
679 v.frame = frame
680
681 var sig = new Buffer
682 var comment = new Buffer
683
684 # Because the function is virtual, the signature must match the one of the original class
685 var intromclassdef = self.mmethoddef.mproperty.intro.mclassdef
686 var msignature = mmethoddef.mproperty.intro.msignature.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
687 var ret = msignature.return_mtype
688 if ret != null then
689 sig.append("{ret.ctype} ")
690 else if mmethoddef.mproperty.is_new then
691 ret = recv
692 sig.append("{ret.ctype} ")
693 else
694 sig.append("void ")
695 end
696 sig.append(self.c_name)
697 sig.append("({selfvar.mtype.ctype} {selfvar}")
698 comment.append("(self: {selfvar}")
699 arguments.add(selfvar)
700 for i in [0..msignature.arity[ do
701 var mtype = msignature.mparameters[i].mtype
702 if i == msignature.vararg_rank then
703 mtype = v.get_class("Array").get_mtype([mtype])
704 end
705 comment.append(", {mtype}")
706 sig.append(", {mtype.ctype} p{i}")
707 var argvar = new RuntimeVariable("p{i}", mtype, mtype)
708 arguments.add(argvar)
709 end
710 sig.append(")")
711 comment.append(")")
712 if ret != null then
713 comment.append(": {ret}")
714 end
715 compiler.header.add_decl("{sig};")
716
717 v.add_decl("/* method {self} for {comment} */")
718 v.add_decl("{sig} \{")
719 if ret != null then
720 frame.returnvar = v.new_var(ret)
721 end
722 frame.returnlabel = v.get_name("RET_LABEL")
723
724 if recv != arguments.first.mtype then
725 #print "{self} {recv} {arguments.first}"
726 end
727 mmethoddef.compile_inside_to_c(v, arguments)
728
729 v.add("{frame.returnlabel.as(not null)}:;")
730 if ret != null then
731 v.add("return {frame.returnvar.as(not null)};")
732 end
733 v.add("\}")
734 end
735
736 redef fun call(v, arguments)
737 do
738 abort
739 # TODO ?
740 end
741 end
742
743 # A visitor on the AST of property definition that generate the C code of a separate compilation process.
744 class SeparateCompilerVisitor
745 super GlobalCompilerVisitor # TODO better separation of concerns
746
747 redef fun adapt_signature(m: MMethodDef, args: Array[RuntimeVariable])
748 do
749 var msignature = m.msignature.resolve_for(m.mclassdef.bound_mtype, m.mclassdef.bound_mtype, m.mclassdef.mmodule, true)
750 var recv = args.first
751 if recv.mtype.ctype != m.mclassdef.mclass.mclass_type.ctype then
752 args.first = self.autobox(args.first, m.mclassdef.mclass.mclass_type)
753 end
754 for i in [0..msignature.arity[ do
755 var t = msignature.mparameters[i].mtype
756 if i == msignature.vararg_rank then
757 t = args[i+1].mtype
758 end
759 args[i+1] = self.autobox(args[i+1], t)
760 end
761 end
762
763 # Box or unbox a value to another type iff a C type conversion is needed
764 # ENSURE: result.mtype.ctype == mtype.ctype
765 redef fun autobox(value: RuntimeVariable, mtype: MType): RuntimeVariable
766 do
767 if value.mtype.ctype == mtype.ctype then
768 return value
769 else if value.mtype.ctype == "val*" then
770 return self.new_expr("((struct instance_{mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
771 else if mtype.ctype == "val*" then
772 var valtype = value.mtype.as(MClassType)
773 var res = self.new_var(mtype)
774 if not compiler.runtime_type_analysis.live_types.has(valtype) then
775 self.add("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */")
776 self.add("printf(\"Dead code executed!\\n\"); exit(1);")
777 return res
778 end
779 self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
780 return res
781 else
782 # Bad things will appen!
783 var res = self.new_var(mtype)
784 self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */")
785 self.add("printf(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); exit(1);")
786 return res
787 end
788 end
789
790 redef fun send(mmethod, arguments)
791 do
792 if arguments.first.mcasttype.ctype != "val*" then
793 return self.monomorphic_send(mmethod, arguments.first.mcasttype, arguments)
794 end
795
796 var res: nullable RuntimeVariable
797 var msignature = mmethod.intro.msignature.resolve_for(mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.mmodule, true)
798 var ret = msignature.return_mtype
799 if mmethod.is_new then
800 ret = arguments.first.mtype
801 res = self.new_var(ret)
802 else if ret == null then
803 res = null
804 else
805 res = self.new_var(ret)
806 end
807
808 var s = new Buffer
809 var ss = new Buffer
810
811 var recv = arguments.first
812 s.append("val*")
813 ss.append("{recv}")
814 self.varargize(msignature, arguments)
815 for i in [0..msignature.arity[ do
816 var a = arguments[i+1]
817 var t = msignature.mparameters[i].mtype
818 if i == msignature.vararg_rank then
819 t = arguments[i+1].mcasttype
820 end
821 s.append(", {t.ctype}")
822 a = self.autobox(a, t)
823 ss.append(", {a}")
824 end
825
826 var consider_null = not self.compiler.modelbuilder.toolcontext.opt_no_check_other.value or mmethod.name == "==" or mmethod.name == "!="
827 var maybenull = recv.mcasttype isa MNullableType and consider_null
828 if maybenull then
829 self.add("if ({recv} == NULL) \{")
830 if mmethod.name == "==" then
831 assert res != null
832 var arg = arguments[1]
833 if arg.mcasttype isa MNullableType then
834 self.add("{res} = ({arg} == NULL);")
835 else if arg.mcasttype isa MNullType then
836 self.add("{res} = 1; /* is null */")
837 else
838 self.add("{res} = 0; /* {arg.inspect} cannot be null */")
839 end
840 else if mmethod.name == "!=" then
841 assert res != null
842 var arg = arguments[1]
843 if arg.mcasttype isa MNullableType then
844 self.add("{res} = ({arg} != NULL);")
845 else if arg.mcasttype isa MNullType then
846 self.add("{res} = 0; /* is null */")
847 else
848 self.add("{res} = 1; /* {arg.inspect} cannot be null */")
849 end
850 else
851 self.add_abort("Reciever is null")
852 end
853 self.add("\} else \{")
854 end
855
856 var color = self.compiler.as(SeparateCompiler).method_colors[mmethod]
857 var r
858 if ret == null then r = "void" else r = ret.ctype
859 var call = "(({r} (*)({s}))({arguments.first}->class->vft[{color}]))({ss}) /* {mmethod} on {arguments.first.inspect}*/"
860
861 if res != null then
862 self.add("{res} = {call};")
863 else
864 self.add("{call};")
865 end
866
867 if maybenull then
868 self.add("\}")
869 end
870
871 return res
872 end
873
874 redef fun call(mmethoddef, recvtype, arguments)
875 do
876 var res: nullable RuntimeVariable
877 var ret = mmethoddef.msignature.return_mtype
878 if mmethoddef.mproperty.is_new then
879 ret = arguments.first.mtype
880 res = self.new_var(ret)
881 else if ret == null then
882 res = null
883 else
884 ret = ret.resolve_for(mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.mmodule, true)
885 res = self.new_var(ret)
886 end
887
888 if self.compiler.modelbuilder.mpropdef2npropdef.has_key(mmethoddef) and
889 self.compiler.modelbuilder.mpropdef2npropdef[mmethoddef] isa AInternMethPropdef and
890 not compiler.modelbuilder.toolcontext.opt_no_inline_intern.value then
891 var frame = new Frame(self, mmethoddef, recvtype, arguments)
892 frame.returnlabel = self.get_name("RET_LABEL")
893 frame.returnvar = res
894 var old_frame = self.frame
895 self.frame = frame
896 self.add("\{ /* Inline {mmethoddef} ({arguments.join(",")}) */")
897 mmethoddef.compile_inside_to_c(self, arguments)
898 self.add("{frame.returnlabel.as(not null)}:(void)0;")
899 self.add("\}")
900 self.frame = old_frame
901 return res
902 end
903
904 # Autobox arguments
905 self.adapt_signature(mmethoddef, arguments)
906
907 if res == null then
908 self.add("{mmethoddef.c_name}({arguments.join(", ")});")
909 return null
910 else
911 self.add("{res} = {mmethoddef.c_name}({arguments.join(", ")});")
912 end
913
914 return res
915 end
916
917 redef fun isset_attribute(a, recv)
918 do
919 self.check_recv_notnull(recv)
920 var res = self.new_var(bool_type)
921 self.add("{res} = {recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}] != NULL; /* {a} on {recv.inspect}*/")
922 return res
923 end
924
925 redef fun read_attribute(a, recv)
926 do
927 self.check_recv_notnull(recv)
928
929 # What is the declared type of the attribute?
930 var ret = a.intro.static_mtype.as(not null)
931 var intromclassdef = a.intro.mclassdef
932 ret = ret.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
933
934 # Get the attribute or a box (ie. always a val*)
935 var cret = self.object_type.as_nullable
936 var res = self.new_var(cret)
937 res.mcasttype = ret
938 self.add("{res} = {recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}]; /* {a} on {recv.inspect} */")
939
940 # Check for Uninitialized attribute
941 if not ret isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_initialization.value then
942 self.add("if ({res} == NULL) \{")
943 self.add_abort("Uninitialized attribute {a.name}")
944 self.add("\}")
945 end
946
947 # Return the attribute or its unboxed version
948 # Note: it is mandatory since we reuse the box on write, we do not whant that the box escapes
949 return self.autobox(res, ret)
950 end
951
952 redef fun write_attribute(a, recv, value)
953 do
954 self.check_recv_notnull(recv)
955
956 # What is the declared type of the attribute?
957 var mtype = a.intro.static_mtype.as(not null)
958 var intromclassdef = a.intro.mclassdef
959 mtype = mtype.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
960
961 # Adapt the value to the declared type
962 value = self.autobox(value, mtype)
963 var attr = "{recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}]"
964 if mtype.ctype != "val*" then
965 assert mtype isa MClassType
966 # The attribute is primitive, thus we store it in a box
967 # The trick is to create the box the first time then resuse the box
968 self.add("if ({attr} != NULL) \{")
969 self.add("((struct instance_{mtype.c_name}*){attr})->value = {value}; /* {a} on {recv.inspect} */")
970 self.add("\} else \{")
971 value = self.autobox(value, self.object_type.as_nullable)
972 self.add("{attr} = {value}; /* {a} on {recv.inspect} */")
973 self.add("\}")
974 else
975 # The attribute is not primitive, thus store it direclty
976 self.add("{attr} = {value}; /* {a} on {recv.inspect} */")
977 end
978 end
979
980 # Build livetype structure retrieving
981 #ENSURE: mtype.need_anchor
982 fun retrieve_anchored_livetype(mtype: MGenericType, buffer: Buffer) do
983 assert mtype.need_anchor
984
985 var compiler = self.compiler.as(SeparateCompiler)
986 for ft in mtype.arguments do
987
988 var ntype = ft
989 var s: String = ""
990 if ntype isa MNullableType then
991 ntype = ntype.mtype
992 end
993
994 if ntype isa MParameterType then
995 var ftcolor = compiler.ft_colors[ntype]
996 buffer.append("[self->type->fts_table->fts[{ftcolor}]->livecolor]")
997 else if ntype isa MVirtualType then
998 var vtcolor = compiler.vt_colors[ntype.mproperty.as(MVirtualTypeProp)]
999 buffer.append("[self->type->vts_table->vts[{vtcolor}]->livecolor]")
1000 else if ntype isa MGenericType and ntype.need_anchor then
1001 var bbuff = new Buffer
1002 retrieve_anchored_livetype(ntype, bbuff)
1003 buffer.append("[livetypes_{ntype.mclass.c_name}{bbuff.to_s}->livecolor]")
1004 else if ntype isa MClassType then
1005 compiler.undead_types.add(ft)
1006 buffer.append("[type_{ft.c_name}.livecolor]")
1007 else
1008 self.add("printf(\"NOT YET IMPLEMENTED: init_instance(%s, {mtype}).\\n\", \"{ft}\"); exit(1);")
1009 end
1010 end
1011 end
1012
1013 redef fun init_instance(mtype)
1014 do
1015 var compiler = self.compiler.as(SeparateCompiler)
1016 if mtype isa MGenericType and mtype.need_anchor then
1017 var buff = new Buffer
1018 retrieve_anchored_livetype(mtype, buff)
1019 mtype = self.anchor(mtype).as(MClassType)
1020 return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) livetypes_{mtype.mclass.c_name}{buff.to_s})", mtype)
1021 end
1022 compiler.undead_types.add(mtype)
1023 return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) &type_{mtype.c_name})", mtype)
1024 end
1025
1026 redef fun type_test(value, mtype)
1027 do
1028 var compiler = self.compiler.as(SeparateCompiler)
1029
1030 var recv = self.frame.arguments.first
1031 var recv_boxed = self.autobox(recv, self.object_type)
1032
1033 var res = self.new_var(bool_type)
1034
1035 var cltype = self.get_name("cltype")
1036 self.add_decl("int {cltype};")
1037 var idtype = self.get_name("idtype")
1038 self.add_decl("int {idtype};")
1039
1040 var is_nullable = self.get_name("is_nullable")
1041 self.add_decl("short int {is_nullable};")
1042
1043 var boxed = self.autobox(value, self.object_type)
1044
1045 var ntype = mtype
1046 if ntype isa MNullableType then
1047 ntype = ntype.mtype
1048 end
1049
1050 if ntype isa MParameterType then
1051 var ftcolor = compiler.ft_colors[ntype]
1052 self.add("{cltype} = {recv_boxed}->type->fts_table->fts[{ftcolor}]->color;")
1053 self.add("{idtype} = {recv_boxed}->type->fts_table->fts[{ftcolor}]->id;")
1054 self.add("{is_nullable} = {recv_boxed}->type->fts_table->fts[{ftcolor}]->is_nullable;")
1055 else if ntype isa MGenericType and ntype.need_anchor then
1056 var buff = new Buffer
1057 retrieve_anchored_livetype(ntype, buff)
1058 self.add("{cltype} = livetypes_{ntype.mclass.c_name}{buff.to_s}->color;")
1059 self.add("{idtype} = livetypes_{ntype.mclass.c_name}{buff.to_s}->id;")
1060 self.add("{is_nullable} = livetypes_{ntype.mclass.c_name}{buff.to_s}->is_nullable;")
1061 else if ntype isa MClassType then
1062 compiler.undead_types.add(mtype)
1063 self.add("{cltype} = type_{mtype.c_name}.color;")
1064 self.add("{idtype} = type_{mtype.c_name}.id;")
1065 self.add("{is_nullable} = type_{mtype.c_name}.is_nullable;")
1066 else if ntype isa MVirtualType then
1067 var vtcolor = compiler.vt_colors[ntype.mproperty.as(MVirtualTypeProp)]
1068 self.add("{cltype} = {recv_boxed}->type->vts_table->vts[{vtcolor}]->color;")
1069 self.add("{idtype} = {recv_boxed}->type->vts_table->vts[{vtcolor}]->id;")
1070 self.add("{is_nullable} = {recv_boxed}->type->vts_table->vts[{vtcolor}]->is_nullable;")
1071 else
1072 self.add("printf(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{boxed.inspect}\"); exit(1);")
1073 end
1074
1075 if mtype isa MNullableType then
1076 self.add("{is_nullable} = 1;")
1077 end
1078
1079 # check color is in table
1080 self.add("if({boxed} == NULL) \{")
1081 self.add("{res} = {is_nullable};")
1082 self.add("\} else \{")
1083 self.add("if({cltype} >= {boxed}->type->table_size) \{")
1084 self.add("{res} = 0;")
1085 self.add("\} else \{")
1086 self.add("{res} = {boxed}->type->type_table[{cltype}] == {idtype};")
1087 self.add("\}")
1088 self.add("\}")
1089
1090 return res
1091 end
1092
1093 redef fun is_same_type_test(value1, value2)
1094 do
1095 var res = self.new_var(bool_type)
1096 # Swap values to be symetric
1097 if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
1098 var tmp = value1
1099 value1 = value2
1100 value2 = tmp
1101 end
1102 if value1.mtype.ctype != "val*" then
1103 if value2.mtype.ctype == value1.mtype.ctype then
1104 self.add("{res} = 1; /* is_same_type_test: compatible types {value1.mtype} vs. {value2.mtype} */")
1105 else if value2.mtype.ctype != "val*" then
1106 self.add("{res} = 0; /* is_same_type_test: incompatible types {value1.mtype} vs. {value2.mtype}*/")
1107 else
1108 var mtype1 = value1.mtype.as(MClassType)
1109 self.add("{res} = ({value2} != NULL) && ({value2}->class == (struct class*) &class_{mtype1.c_name}); /* is_same_type_test */")
1110 end
1111 else
1112 self.add("{res} = ({value1} == {value2}) || ({value1} != NULL && {value2} != NULL && {value1}->class == {value2}->class); /* is_same_type_test */")
1113 end
1114 return res
1115 end
1116
1117 redef fun class_name_string(value)
1118 do
1119 var res = self.get_name("var_class_name")
1120 self.add_decl("const char *{res};")
1121 self.add("{res} = class_names[{value}->type->id];")
1122 return res
1123 end
1124
1125 redef fun equal_test(value1, value2)
1126 do
1127 var res = self.new_var(bool_type)
1128 if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
1129 var tmp = value1
1130 value1 = value2
1131 value2 = tmp
1132 end
1133 if value1.mtype.ctype != "val*" then
1134 if value2.mtype.ctype == value1.mtype.ctype then
1135 self.add("{res} = {value1} == {value2};")
1136 else if value2.mtype.ctype != "val*" then
1137 self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
1138 else
1139 var mtype1 = value1.mtype.as(MClassType)
1140 self.add("{res} = ({value2} != NULL) && ({value2}->class == (struct class*) &class_{mtype1.c_name});")
1141 self.add("if ({res}) \{")
1142 self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
1143 self.add("\}")
1144 end
1145 return res
1146 end
1147 var maybe_null = true
1148 var test = new Array[String]
1149 var t1 = value1.mcasttype
1150 if t1 isa MNullableType then
1151 test.add("{value1} != NULL")
1152 t1 = t1.mtype
1153 else
1154 maybe_null = false
1155 end
1156 var t2 = value2.mcasttype
1157 if t2 isa MNullableType then
1158 test.add("{value2} != NULL")
1159 t2 = t2.mtype
1160 else
1161 maybe_null = false
1162 end
1163
1164 var incompatible = false
1165 var primitive
1166 if t1.ctype != "val*" then
1167 primitive = t1
1168 if t1 == t2 then
1169 # No need to compare class
1170 else if t2.ctype != "val*" then
1171 incompatible = true
1172 else if can_be_primitive(value2) then
1173 test.add("{value1}->class == {value2}->class")
1174 else
1175 incompatible = true
1176 end
1177 else if t2.ctype != "val*" then
1178 primitive = t2
1179 if can_be_primitive(value1) then
1180 test.add("{value1}->class == {value2}->class")
1181 else
1182 incompatible = true
1183 end
1184 else
1185 primitive = null
1186 end
1187
1188 if incompatible then
1189 if maybe_null then
1190 self.add("{res} = {value1} == {value2}; /* incompatible types {t1} vs. {t2}; but may be NULL*/")
1191 return res
1192 else
1193 self.add("{res} = 0; /* incompatible types {t1} vs. {t2}; cannot be NULL */")
1194 return res
1195 end
1196 end
1197 if primitive != null then
1198 test.add("((struct instance_{primitive.c_name}*){value1})->value == ((struct instance_{primitive.c_name}*){value2})->value")
1199 else if can_be_primitive(value1) and can_be_primitive(value2) then
1200 test.add("{value1}->class == {value2}->class")
1201 var s = new Array[String]
1202 for t, v in self.compiler.as(SeparateCompiler).box_kinds do
1203 s.add "({value1}->class->box_kind == {v} && ((struct instance_{t.c_name}*){value1})->value == ((struct instance_{t.c_name}*){value2})->value)"
1204 end
1205 test.add("({s.join(" || ")})")
1206 else
1207 self.add("{res} = {value1} == {value2};")
1208 return res
1209 end
1210 self.add("{res} = {value1} == {value2} || ({test.join(" && ")});")
1211 return res
1212 end
1213
1214 fun can_be_primitive(value: RuntimeVariable): Bool
1215 do
1216 var t = value.mcasttype
1217 if t isa MNullableType then t = t.mtype
1218 if not t isa MClassType then return false
1219 var k = t.mclass.kind
1220 return k == interface_kind or t.ctype != "val*"
1221 end
1222
1223 fun maybe_null(value: RuntimeVariable): Bool
1224 do
1225 var t = value.mcasttype
1226 return t isa MNullableType or t isa MNullType
1227 end
1228
1229 redef fun array_instance(array, elttype)
1230 do
1231 var compiler = self.compiler.as(SeparateCompiler)
1232 var nclass = self.get_class("NativeArray")
1233 elttype = self.anchor(elttype)
1234 var arraytype = self.get_class("Array").get_mtype([elttype])
1235 var res = self.init_instance(arraytype)
1236 self.add("\{ /* {res} = array_instance Array[{elttype}] */")
1237 var nat = self.new_var(self.get_class("NativeArray").get_mtype([elttype]))
1238 nat.is_exact = true
1239 compiler.undead_types.add(nat.mtype.as(MClassType))
1240 self.add("{nat} = NEW_{nclass.c_name}({array.length}, (struct type *) &type_{nat.mtype.c_name});")
1241 for i in [0..array.length[ do
1242 var r = self.autobox(array[i], self.object_type)
1243 self.add("((struct instance_{nclass.c_name}*){nat})->values[{i}] = (val*) {r};")
1244 end
1245 var length = self.int_instance(array.length)
1246 self.send(self.get_property("with_native", arraytype), [res, nat, length])
1247 self.check_init_instance(res)
1248 self.add("\}")
1249 return res
1250 end
1251
1252 redef fun native_array_def(pname, ret_type, arguments)
1253 do
1254 var elttype = arguments.first.mtype
1255 var nclass = self.get_class("NativeArray")
1256 var recv = "((struct instance_{nclass.c_name}*){arguments[0]})->values"
1257 if pname == "[]" then
1258 self.ret(self.new_expr("{recv}[{arguments[1]}]", ret_type.as(not null)))
1259 return
1260 else if pname == "[]=" then
1261 self.add("{recv}[{arguments[1]}]={arguments[2]};")
1262 return
1263 else if pname == "copy_to" then
1264 var recv1 = "((struct instance_{nclass.c_name}*){arguments[1]})->values"
1265 self.add("memcpy({recv1}, {recv}, {arguments[2]}*sizeof({elttype.ctype}));")
1266 return
1267 end
1268 end
1269
1270 redef fun calloc_array(ret_type, arguments)
1271 do
1272 var ret = ret_type.as(MGenericType)
1273 var compiler = self.compiler.as(SeparateCompiler)
1274 compiler.undead_types.add(ret)
1275 var mclass = self.get_class("ArrayCapable")
1276 var ft = mclass.mclass_type.arguments.first.as(MParameterType)
1277 var color = compiler.ft_colors[ft]
1278 self.ret(self.new_expr("NEW_{ret.mclass.c_name}({arguments[1]}, (struct type*) livetypes_array__NativeArray[self->type->fts_table->fts[{color}]->livecolor])", ret_type))
1279 end
1280 end
1281
1282 redef class MClass
1283 # Return the name of the C structure associated to a Nit class
1284 fun c_name: String do
1285 var res = self.c_name_cache
1286 if res != null then return res
1287 res = "{intro_mmodule.name.to_cmangle}__{name.to_cmangle}"
1288 self.c_name_cache = res
1289 return res
1290 end
1291 private var c_name_cache: nullable String
1292 end