Merge remote-tracking branch 'github-privat/master'
[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 is_nullable = ""
439 if bound isa MNullableType then
440 bound = bound.mtype
441 is_nullable = "nullable_"
442 end
443 if bound isa MVirtualType then
444 bound = bound.anchor_to(self.mainmodule, mclass_type)
445 else if bound isa MParameterType then
446 bound = bound.anchor_to(self.mainmodule, mclass_type)
447 else if bound isa MGenericType and bound.need_anchor then
448 bound = bound.anchor_to(self.mainmodule, mclass_type)
449 else if bound isa MClassType then
450 else
451 print "NOT YET IMPLEMENTED: mtype_to_livetype with type: {bound}"
452 abort
453 end
454
455 if self.typeids.has_key(bound) then
456 v.add_decl("(struct type*)&type_{is_nullable}{bound.c_name}, /* {bound} */")
457 else
458 v.add_decl("NULL, /* dead type {bound} */")
459 end
460 end
461 end
462 end
463 v.add_decl("\},")
464 v.add_decl("\};")
465 end
466
467 # Globally compile the table of the class mclass
468 # In a link-time optimisation compiler, tables are globally computed
469 # In a true separate compiler (a with dynamic loading) you cannot do this unfortnally
470 fun compile_class_to_c(mclass: MClass)
471 do
472 var mtype = mclass.intro.bound_mtype
473 var c_name = mclass.c_name
474
475 var vft = self.method_tables[mclass]
476 var attrs = self.attr_tables[mclass]
477 var v = new SeparateCompilerVisitor(self)
478
479 v.add_decl("/* runtime class {c_name} */")
480 var idnum = classids.length
481 var idname = "ID_" + c_name
482 self.classids[mtype] = idname
483 #self.header.add_decl("#define {idname} {idnum} /* {c_name} */")
484
485 self.header.add_decl("struct class_{c_name} \{")
486 self.header.add_decl("int box_kind;")
487 self.header.add_decl("nitmethod_t vft[{vft.length}];")
488 self.header.add_decl("\};")
489
490 # Build class vft
491 self.header.add_decl("extern const struct class_{c_name} class_{c_name};")
492 v.add_decl("const struct class_{c_name} class_{c_name} = \{")
493 v.add_decl("{self.box_kind_of(mclass)}, /* box_kind */")
494 v.add_decl("\{")
495 for i in [0 .. vft.length[ do
496 var mpropdef = vft[i]
497 if mpropdef == null then
498 v.add_decl("NULL, /* empty */")
499 else
500 if true or mpropdef.mclassdef.bound_mtype.ctype != "val*" then
501 v.add_decl("(nitmethod_t)VIRTUAL_{mpropdef.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
502 else
503 v.add_decl("(nitmethod_t){mpropdef.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
504 end
505 end
506 end
507 v.add_decl("\}")
508 v.add_decl("\};")
509
510 if mtype.ctype != "val*" then
511 #Build instance struct
512 self.header.add_decl("struct instance_{c_name} \{")
513 self.header.add_decl("const struct type *type;")
514 self.header.add_decl("const struct class *class;")
515 self.header.add_decl("{mtype.ctype} value;")
516 self.header.add_decl("\};")
517
518 if not self.runtime_type_analysis.live_types.has(mtype) then return
519
520 self.header.add_decl("val* BOX_{c_name}({mtype.ctype});")
521 v.add_decl("/* allocate {mtype} */")
522 v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value) \{")
523 v.add("struct instance_{c_name}*res = GC_MALLOC(sizeof(struct instance_{c_name}));")
524 v.add("res->type = (struct type*) &type_{c_name};")
525 v.add("res->class = (struct class*) &class_{c_name};")
526 v.add("res->value = value;")
527 v.add("return (val*)res;")
528 v.add("\}")
529 return
530 end
531
532 var is_native_array = mclass.name == "NativeArray"
533
534 var sig
535 if is_native_array then
536 sig = "int length, struct type* type"
537 else
538 sig = "struct type* type"
539 end
540
541 #Build instance struct
542 #extern const struct instance_array__NativeArray instance_array__NativeArray;
543 self.header.add_decl("struct instance_{c_name} \{")
544 self.header.add_decl("const struct type *type;")
545 self.header.add_decl("const struct class *class;")
546 self.header.add_decl("nitattribute_t attrs[{attrs.length}];")
547 if is_native_array then
548 # NativeArrays are just a instance header followed by an array of values
549 self.header.add_decl("val* values[0];")
550 end
551 self.header.add_decl("\};")
552
553
554 self.header.add_decl("{mtype.ctype} NEW_{c_name}({sig});")
555 v.add_decl("/* allocate {mtype} */")
556 v.add_decl("{mtype.ctype} NEW_{c_name}({sig}) \{")
557 var res = v.new_named_var(mtype, "self")
558 res.is_exact = true
559 if is_native_array then
560 var mtype_elt = mtype.arguments.first
561 v.add("{res} = GC_MALLOC(sizeof(struct instance_{c_name}) + length*sizeof({mtype_elt.ctype}));")
562 else
563 v.add("{res} = GC_MALLOC(sizeof(struct instance_{c_name}));")
564 end
565 #v.add("{res} = calloc(sizeof(struct instance_{c_name}), 1);")
566 v.add("{res}->type = type;")
567 v.add("{res}->class = (struct class*) &class_{c_name};")
568
569 self.generate_init_attr(v, res, mtype)
570 v.add("return {res};")
571 v.add("\}")
572
573 generate_check_init_instance(mtype)
574 end
575
576 redef fun generate_check_init_instance(mtype)
577 do
578 if self.modelbuilder.toolcontext.opt_no_check_initialization.value then return
579
580 var v = self.new_visitor
581 var c_name = mtype.mclass.c_name
582 var res = new RuntimeVariable("self", mtype, mtype)
583 self.header.add_decl("void CHECK_NEW_{c_name}({mtype.ctype});")
584 v.add_decl("/* allocate {mtype} */")
585 v.add_decl("void CHECK_NEW_{c_name}({mtype.ctype} {res}) \{")
586 self.generate_check_attr(v, res, mtype)
587 v.add("\}")
588 end
589
590 redef fun new_visitor do return new SeparateCompilerVisitor(self)
591 end
592
593 # The C function associated to a methoddef separately compiled
594 class SeparateRuntimeFunction
595 super AbstractRuntimeFunction
596
597 redef fun build_c_name: String
598 do
599 return "{mmethoddef.c_name}"
600 end
601
602 redef fun to_s do return self.mmethoddef.to_s
603
604 redef fun compile_to_c(compiler)
605 do
606 var mmethoddef = self.mmethoddef
607
608 var recv = self.mmethoddef.mclassdef.bound_mtype
609 var v = compiler.new_visitor
610 var selfvar = new RuntimeVariable("self", recv, recv)
611 var arguments = new Array[RuntimeVariable]
612 var frame = new Frame(v, mmethoddef, recv, arguments)
613 v.frame = frame
614
615 var msignature = mmethoddef.msignature.resolve_for(mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.mmodule, true)
616
617 var sig = new Buffer
618 var comment = new Buffer
619 var ret = msignature.return_mtype
620 if ret != null then
621 sig.append("{ret.ctype} ")
622 else if mmethoddef.mproperty.is_new then
623 ret = recv
624 sig.append("{ret.ctype} ")
625 else
626 sig.append("void ")
627 end
628 sig.append(self.c_name)
629 sig.append("({selfvar.mtype.ctype} {selfvar}")
630 comment.append("(self: {selfvar}")
631 arguments.add(selfvar)
632 for i in [0..msignature.arity[ do
633 var mtype = msignature.mparameters[i].mtype
634 if i == msignature.vararg_rank then
635 mtype = v.get_class("Array").get_mtype([mtype])
636 end
637 comment.append(", {mtype}")
638 sig.append(", {mtype.ctype} p{i}")
639 var argvar = new RuntimeVariable("p{i}", mtype, mtype)
640 arguments.add(argvar)
641 end
642 sig.append(")")
643 comment.append(")")
644 if ret != null then
645 comment.append(": {ret}")
646 end
647 compiler.header.add_decl("{sig};")
648
649 v.add_decl("/* method {self} for {comment} */")
650 v.add_decl("{sig} \{")
651 if ret != null then
652 frame.returnvar = v.new_var(ret)
653 end
654 frame.returnlabel = v.get_name("RET_LABEL")
655
656 if recv != arguments.first.mtype then
657 #print "{self} {recv} {arguments.first}"
658 end
659 mmethoddef.compile_inside_to_c(v, arguments)
660
661 v.add("{frame.returnlabel.as(not null)}:;")
662 if ret != null then
663 v.add("return {frame.returnvar.as(not null)};")
664 end
665 v.add("\}")
666 end
667 end
668
669 # The C function associated to a methoddef on a primitive type, stored into a VFT of a class
670 # The first parameter (the reciever) is always typed by val* in order to accept an object value
671 class VirtualRuntimeFunction
672 super AbstractRuntimeFunction
673
674 redef fun build_c_name: String
675 do
676 return "VIRTUAL_{mmethoddef.c_name}"
677 end
678
679 redef fun to_s do return self.mmethoddef.to_s
680
681 redef fun compile_to_c(compiler)
682 do
683 var mmethoddef = self.mmethoddef
684
685 var recv = self.mmethoddef.mclassdef.bound_mtype
686 var v = compiler.new_visitor
687 var selfvar = new RuntimeVariable("self", v.object_type, recv)
688 var arguments = new Array[RuntimeVariable]
689 var frame = new Frame(v, mmethoddef, recv, arguments)
690 v.frame = frame
691
692 var sig = new Buffer
693 var comment = new Buffer
694
695 # Because the function is virtual, the signature must match the one of the original class
696 var intromclassdef = self.mmethoddef.mproperty.intro.mclassdef
697 var msignature = mmethoddef.mproperty.intro.msignature.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
698 var ret = msignature.return_mtype
699 if ret != null then
700 sig.append("{ret.ctype} ")
701 else if mmethoddef.mproperty.is_new then
702 ret = recv
703 sig.append("{ret.ctype} ")
704 else
705 sig.append("void ")
706 end
707 sig.append(self.c_name)
708 sig.append("({selfvar.mtype.ctype} {selfvar}")
709 comment.append("(self: {selfvar}")
710 arguments.add(selfvar)
711 for i in [0..msignature.arity[ do
712 var mtype = msignature.mparameters[i].mtype
713 if i == msignature.vararg_rank then
714 mtype = v.get_class("Array").get_mtype([mtype])
715 end
716 comment.append(", {mtype}")
717 sig.append(", {mtype.ctype} p{i}")
718 var argvar = new RuntimeVariable("p{i}", mtype, mtype)
719 arguments.add(argvar)
720 end
721 sig.append(")")
722 comment.append(")")
723 if ret != null then
724 comment.append(": {ret}")
725 end
726 compiler.header.add_decl("{sig};")
727
728 v.add_decl("/* method {self} for {comment} */")
729 v.add_decl("{sig} \{")
730 if ret != null then
731 frame.returnvar = v.new_var(ret)
732 end
733 frame.returnlabel = v.get_name("RET_LABEL")
734
735 if recv != arguments.first.mtype then
736 #print "{self} {recv} {arguments.first}"
737 end
738 mmethoddef.compile_inside_to_c(v, arguments)
739
740 v.add("{frame.returnlabel.as(not null)}:;")
741 if ret != null then
742 v.add("return {frame.returnvar.as(not null)};")
743 end
744 v.add("\}")
745 end
746
747 redef fun call(v, arguments)
748 do
749 abort
750 # TODO ?
751 end
752 end
753
754 # A visitor on the AST of property definition that generate the C code of a separate compilation process.
755 class SeparateCompilerVisitor
756 super GlobalCompilerVisitor # TODO better separation of concerns
757
758 redef fun adapt_signature(m: MMethodDef, args: Array[RuntimeVariable])
759 do
760 var msignature = m.msignature.resolve_for(m.mclassdef.bound_mtype, m.mclassdef.bound_mtype, m.mclassdef.mmodule, true)
761 var recv = args.first
762 if recv.mtype.ctype != m.mclassdef.mclass.mclass_type.ctype then
763 args.first = self.autobox(args.first, m.mclassdef.mclass.mclass_type)
764 end
765 for i in [0..msignature.arity[ do
766 var t = msignature.mparameters[i].mtype
767 if i == msignature.vararg_rank then
768 t = args[i+1].mtype
769 end
770 args[i+1] = self.autobox(args[i+1], t)
771 end
772 end
773
774 # Box or unbox a value to another type iff a C type conversion is needed
775 # ENSURE: result.mtype.ctype == mtype.ctype
776 redef fun autobox(value: RuntimeVariable, mtype: MType): RuntimeVariable
777 do
778 if value.mtype == mtype then
779 return value
780 else if value.mtype.ctype == "val*" and mtype.ctype == "val*" then
781 return value
782 else if value.mtype.ctype == "val*" then
783 return self.new_expr("((struct instance_{mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
784 else if mtype.ctype == "val*" then
785 var valtype = value.mtype.as(MClassType)
786 var res = self.new_var(mtype)
787 if not compiler.runtime_type_analysis.live_types.has(valtype) then
788 self.add("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */")
789 self.add("printf(\"Dead code executed!\\n\"); exit(1);")
790 return res
791 end
792 self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
793 return res
794 else
795 # Bad things will appen!
796 var res = self.new_var(mtype)
797 self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */")
798 self.add("printf(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); exit(1);")
799 return res
800 end
801 end
802
803 redef fun send(mmethod, arguments)
804 do
805 if arguments.first.mcasttype.ctype != "val*" then
806 return self.monomorphic_send(mmethod, arguments.first.mcasttype, arguments)
807 end
808
809 var res: nullable RuntimeVariable
810 var msignature = mmethod.intro.msignature.resolve_for(mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.mmodule, true)
811 var ret = msignature.return_mtype
812 if mmethod.is_new then
813 ret = arguments.first.mtype
814 res = self.new_var(ret)
815 else if ret == null then
816 res = null
817 else
818 res = self.new_var(ret)
819 end
820
821 var s = new Buffer
822 var ss = new Buffer
823
824 var recv = arguments.first
825 s.append("val*")
826 ss.append("{recv}")
827 self.varargize(msignature, arguments)
828 for i in [0..msignature.arity[ do
829 var a = arguments[i+1]
830 var t = msignature.mparameters[i].mtype
831 if i == msignature.vararg_rank then
832 t = arguments[i+1].mcasttype
833 end
834 s.append(", {t.ctype}")
835 a = self.autobox(a, t)
836 ss.append(", {a}")
837 end
838
839 var consider_null = not self.compiler.modelbuilder.toolcontext.opt_no_check_other.value or mmethod.name == "==" or mmethod.name == "!="
840 var maybenull = recv.mcasttype isa MNullableType and consider_null
841 if maybenull then
842 self.add("if ({recv} == NULL) \{")
843 if mmethod.name == "==" then
844 assert res != null
845 var arg = arguments[1]
846 if arg.mcasttype isa MNullableType then
847 self.add("{res} = ({arg} == NULL);")
848 else if arg.mcasttype isa MNullType then
849 self.add("{res} = 1; /* is null */")
850 else
851 self.add("{res} = 0; /* {arg.inspect} cannot be null */")
852 end
853 else if mmethod.name == "!=" then
854 assert res != null
855 var arg = arguments[1]
856 if arg.mcasttype isa MNullableType then
857 self.add("{res} = ({arg} != NULL);")
858 else if arg.mcasttype isa MNullType then
859 self.add("{res} = 0; /* is null */")
860 else
861 self.add("{res} = 1; /* {arg.inspect} cannot be null */")
862 end
863 else
864 self.add_abort("Reciever is null")
865 end
866 self.add("\} else \{")
867 end
868
869 var color = self.compiler.as(SeparateCompiler).method_colors[mmethod]
870 var r
871 if ret == null then r = "void" else r = ret.ctype
872 var call = "(({r} (*)({s}))({arguments.first}->class->vft[{color}]))({ss}) /* {mmethod} on {arguments.first.inspect}*/"
873
874 if res != null then
875 self.add("{res} = {call};")
876 else
877 self.add("{call};")
878 end
879
880 if maybenull then
881 self.add("\}")
882 end
883
884 return res
885 end
886
887 redef fun call(mmethoddef, recvtype, arguments)
888 do
889 var res: nullable RuntimeVariable
890 var ret = mmethoddef.msignature.return_mtype
891 if mmethoddef.mproperty.is_new then
892 ret = arguments.first.mtype
893 res = self.new_var(ret)
894 else if ret == null then
895 res = null
896 else
897 ret = ret.resolve_for(mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.mmodule, true)
898 res = self.new_var(ret)
899 end
900
901 if self.compiler.modelbuilder.mpropdef2npropdef.has_key(mmethoddef) and
902 self.compiler.modelbuilder.mpropdef2npropdef[mmethoddef] isa AInternMethPropdef and
903 not compiler.modelbuilder.toolcontext.opt_no_inline_intern.value then
904 var frame = new Frame(self, mmethoddef, recvtype, arguments)
905 frame.returnlabel = self.get_name("RET_LABEL")
906 frame.returnvar = res
907 var old_frame = self.frame
908 self.frame = frame
909 self.add("\{ /* Inline {mmethoddef} ({arguments.join(",")}) */")
910 mmethoddef.compile_inside_to_c(self, arguments)
911 self.add("{frame.returnlabel.as(not null)}:(void)0;")
912 self.add("\}")
913 self.frame = old_frame
914 return res
915 end
916
917 # Autobox arguments
918 self.adapt_signature(mmethoddef, arguments)
919
920 if res == null then
921 self.add("{mmethoddef.c_name}({arguments.join(", ")});")
922 return null
923 else
924 self.add("{res} = {mmethoddef.c_name}({arguments.join(", ")});")
925 end
926
927 return res
928 end
929
930 redef fun isset_attribute(a, recv)
931 do
932 self.check_recv_notnull(recv)
933 var res = self.new_var(bool_type)
934 self.add("{res} = {recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}] != NULL; /* {a} on {recv.inspect}*/")
935 return res
936 end
937
938 redef fun read_attribute(a, recv)
939 do
940 self.check_recv_notnull(recv)
941
942 # What is the declared type of the attribute?
943 var ret = a.intro.static_mtype.as(not null)
944 var intromclassdef = a.intro.mclassdef
945 ret = ret.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
946
947 # Get the attribute or a box (ie. always a val*)
948 var cret = self.object_type.as_nullable
949 var res = self.new_var(cret)
950 res.mcasttype = ret
951 self.add("{res} = {recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}]; /* {a} on {recv.inspect} */")
952
953 # Check for Uninitialized attribute
954 if not ret isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_initialization.value then
955 self.add("if ({res} == NULL) \{")
956 self.add_abort("Uninitialized attribute {a.name}")
957 self.add("\}")
958 end
959
960 # Return the attribute or its unboxed version
961 # Note: it is mandatory since we reuse the box on write, we do not whant that the box escapes
962 return self.autobox(res, ret)
963 end
964
965 redef fun write_attribute(a, recv, value)
966 do
967 self.check_recv_notnull(recv)
968
969 # What is the declared type of the attribute?
970 var mtype = a.intro.static_mtype.as(not null)
971 var intromclassdef = a.intro.mclassdef
972 mtype = mtype.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
973
974 # Adapt the value to the declared type
975 value = self.autobox(value, mtype)
976 var attr = "{recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}]"
977 if mtype.ctype != "val*" then
978 assert mtype isa MClassType
979 # The attribute is primitive, thus we store it in a box
980 # The trick is to create the box the first time then resuse the box
981 self.add("if ({attr} != NULL) \{")
982 self.add("((struct instance_{mtype.c_name}*){attr})->value = {value}; /* {a} on {recv.inspect} */")
983 self.add("\} else \{")
984 value = self.autobox(value, self.object_type.as_nullable)
985 self.add("{attr} = {value}; /* {a} on {recv.inspect} */")
986 self.add("\}")
987 else
988 # The attribute is not primitive, thus store it direclty
989 self.add("{attr} = {value}; /* {a} on {recv.inspect} */")
990 end
991 end
992
993 # Build livetype structure retrieving
994 #ENSURE: mtype.need_anchor
995 fun retrieve_anchored_livetype(mtype: MGenericType, buffer: Buffer) do
996 assert mtype.need_anchor
997
998 var compiler = self.compiler.as(SeparateCompiler)
999 for ft in mtype.arguments do
1000
1001 var ntype = ft
1002 var s: String = ""
1003 if ntype isa MNullableType then
1004 ntype = ntype.mtype
1005 end
1006
1007 if ntype isa MParameterType then
1008 var ftcolor = compiler.ft_colors[ntype]
1009 buffer.append("[self->type->fts_table->fts[{ftcolor}]->livecolor]")
1010 else if ntype isa MVirtualType then
1011 var vtcolor = compiler.vt_colors[ntype.mproperty.as(MVirtualTypeProp)]
1012 buffer.append("[self->type->vts_table->vts[{vtcolor}]->livecolor]")
1013 else if ntype isa MGenericType and ntype.need_anchor then
1014 var bbuff = new Buffer
1015 retrieve_anchored_livetype(ntype, bbuff)
1016 buffer.append("[livetypes_{ntype.mclass.c_name}{bbuff.to_s}->livecolor]")
1017 else if ntype isa MClassType then
1018 compiler.undead_types.add(ft)
1019 buffer.append("[type_{ft.c_name}.livecolor]")
1020 else
1021 self.add("printf(\"NOT YET IMPLEMENTED: init_instance(%s, {mtype}).\\n\", \"{ft}\"); exit(1);")
1022 end
1023 end
1024 end
1025
1026 redef fun init_instance(mtype)
1027 do
1028 var compiler = self.compiler.as(SeparateCompiler)
1029 if mtype isa MGenericType and mtype.need_anchor then
1030 var buff = new Buffer
1031 retrieve_anchored_livetype(mtype, buff)
1032 mtype = self.anchor(mtype).as(MClassType)
1033 return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) livetypes_{mtype.mclass.c_name}{buff.to_s})", mtype)
1034 end
1035 compiler.undead_types.add(mtype)
1036 return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) &type_{mtype.c_name})", mtype)
1037 end
1038
1039 redef fun check_init_instance(value, mtype)
1040 do
1041 if self.compiler.modelbuilder.toolcontext.opt_no_check_initialization.value then return
1042 self.add("CHECK_NEW_{mtype.mclass.c_name}({value});")
1043 end
1044
1045
1046 redef fun type_test(value, mtype)
1047 do
1048 var compiler = self.compiler.as(SeparateCompiler)
1049
1050 var recv = self.frame.arguments.first
1051 var recv_boxed = self.autobox(recv, self.object_type)
1052
1053 var res = self.new_var(bool_type)
1054
1055 var cltype = self.get_name("cltype")
1056 self.add_decl("int {cltype};")
1057 var idtype = self.get_name("idtype")
1058 self.add_decl("int {idtype};")
1059
1060 var is_nullable = self.get_name("is_nullable")
1061 self.add_decl("short int {is_nullable};")
1062
1063 var boxed = self.autobox(value, self.object_type)
1064
1065 var ntype = mtype
1066 if ntype isa MNullableType then
1067 ntype = ntype.mtype
1068 end
1069
1070 if ntype isa MParameterType then
1071 var ftcolor = compiler.ft_colors[ntype]
1072 self.add("{cltype} = {recv_boxed}->type->fts_table->fts[{ftcolor}]->color;")
1073 self.add("{idtype} = {recv_boxed}->type->fts_table->fts[{ftcolor}]->id;")
1074 self.add("{is_nullable} = {recv_boxed}->type->fts_table->fts[{ftcolor}]->is_nullable;")
1075 else if ntype isa MGenericType and ntype.need_anchor then
1076 var buff = new Buffer
1077 retrieve_anchored_livetype(ntype, buff)
1078 self.add("{cltype} = livetypes_{ntype.mclass.c_name}{buff.to_s}->color;")
1079 self.add("{idtype} = livetypes_{ntype.mclass.c_name}{buff.to_s}->id;")
1080 self.add("{is_nullable} = livetypes_{ntype.mclass.c_name}{buff.to_s}->is_nullable;")
1081 else if ntype isa MClassType then
1082 compiler.undead_types.add(mtype)
1083 self.add("{cltype} = type_{mtype.c_name}.color;")
1084 self.add("{idtype} = type_{mtype.c_name}.id;")
1085 self.add("{is_nullable} = type_{mtype.c_name}.is_nullable;")
1086 else if ntype isa MVirtualType then
1087 var vtcolor = compiler.vt_colors[ntype.mproperty.as(MVirtualTypeProp)]
1088 self.add("{cltype} = {recv_boxed}->type->vts_table->vts[{vtcolor}]->color;")
1089 self.add("{idtype} = {recv_boxed}->type->vts_table->vts[{vtcolor}]->id;")
1090 self.add("{is_nullable} = {recv_boxed}->type->vts_table->vts[{vtcolor}]->is_nullable;")
1091 else
1092 self.add("printf(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{boxed.inspect}\"); exit(1);")
1093 end
1094
1095 if mtype isa MNullableType then
1096 self.add("{is_nullable} = 1;")
1097 end
1098
1099 # check color is in table
1100 self.add("if({boxed} == NULL) \{")
1101 self.add("{res} = {is_nullable};")
1102 self.add("\} else \{")
1103 self.add("if({cltype} >= {boxed}->type->table_size) \{")
1104 self.add("{res} = 0;")
1105 self.add("\} else \{")
1106 self.add("{res} = {boxed}->type->type_table[{cltype}] == {idtype};")
1107 self.add("\}")
1108 self.add("\}")
1109
1110 return res
1111 end
1112
1113 redef fun is_same_type_test(value1, value2)
1114 do
1115 var res = self.new_var(bool_type)
1116 # Swap values to be symetric
1117 if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
1118 var tmp = value1
1119 value1 = value2
1120 value2 = tmp
1121 end
1122 if value1.mtype.ctype != "val*" then
1123 if value2.mtype == value1.mtype then
1124 self.add("{res} = 1; /* is_same_type_test: compatible types {value1.mtype} vs. {value2.mtype} */")
1125 else if value2.mtype.ctype != "val*" then
1126 self.add("{res} = 0; /* is_same_type_test: incompatible types {value1.mtype} vs. {value2.mtype}*/")
1127 else
1128 var mtype1 = value1.mtype.as(MClassType)
1129 self.add("{res} = ({value2} != NULL) && ({value2}->class == (struct class*) &class_{mtype1.c_name}); /* is_same_type_test */")
1130 end
1131 else
1132 self.add("{res} = ({value1} == {value2}) || ({value1} != NULL && {value2} != NULL && {value1}->class == {value2}->class); /* is_same_type_test */")
1133 end
1134 return res
1135 end
1136
1137 redef fun class_name_string(value)
1138 do
1139 var res = self.get_name("var_class_name")
1140 self.add_decl("const char *{res};")
1141 self.add("{res} = class_names[{value}->type->id];")
1142 return res
1143 end
1144
1145 redef fun equal_test(value1, value2)
1146 do
1147 var res = self.new_var(bool_type)
1148 if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
1149 var tmp = value1
1150 value1 = value2
1151 value2 = tmp
1152 end
1153 if value1.mtype.ctype != "val*" then
1154 if value2.mtype == value1.mtype then
1155 self.add("{res} = {value1} == {value2};")
1156 else if value2.mtype.ctype != "val*" then
1157 self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
1158 else
1159 var mtype1 = value1.mtype.as(MClassType)
1160 self.add("{res} = ({value2} != NULL) && ({value2}->class == (struct class*) &class_{mtype1.c_name});")
1161 self.add("if ({res}) \{")
1162 self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
1163 self.add("\}")
1164 end
1165 return res
1166 end
1167 var maybe_null = true
1168 var test = new Array[String]
1169 var t1 = value1.mcasttype
1170 if t1 isa MNullableType then
1171 test.add("{value1} != NULL")
1172 t1 = t1.mtype
1173 else
1174 maybe_null = false
1175 end
1176 var t2 = value2.mcasttype
1177 if t2 isa MNullableType then
1178 test.add("{value2} != NULL")
1179 t2 = t2.mtype
1180 else
1181 maybe_null = false
1182 end
1183
1184 var incompatible = false
1185 var primitive
1186 if t1.ctype != "val*" then
1187 primitive = t1
1188 if t1 == t2 then
1189 # No need to compare class
1190 else if t2.ctype != "val*" then
1191 incompatible = true
1192 else if can_be_primitive(value2) then
1193 test.add("{value1}->class == {value2}->class")
1194 else
1195 incompatible = true
1196 end
1197 else if t2.ctype != "val*" then
1198 primitive = t2
1199 if can_be_primitive(value1) then
1200 test.add("{value1}->class == {value2}->class")
1201 else
1202 incompatible = true
1203 end
1204 else
1205 primitive = null
1206 end
1207
1208 if incompatible then
1209 if maybe_null then
1210 self.add("{res} = {value1} == {value2}; /* incompatible types {t1} vs. {t2}; but may be NULL*/")
1211 return res
1212 else
1213 self.add("{res} = 0; /* incompatible types {t1} vs. {t2}; cannot be NULL */")
1214 return res
1215 end
1216 end
1217 if primitive != null then
1218 test.add("((struct instance_{primitive.c_name}*){value1})->value == ((struct instance_{primitive.c_name}*){value2})->value")
1219 else if can_be_primitive(value1) and can_be_primitive(value2) then
1220 test.add("{value1}->class == {value2}->class")
1221 var s = new Array[String]
1222 for t, v in self.compiler.as(SeparateCompiler).box_kinds do
1223 s.add "({value1}->class->box_kind == {v} && ((struct instance_{t.c_name}*){value1})->value == ((struct instance_{t.c_name}*){value2})->value)"
1224 end
1225 test.add("({s.join(" || ")})")
1226 else
1227 self.add("{res} = {value1} == {value2};")
1228 return res
1229 end
1230 self.add("{res} = {value1} == {value2} || ({test.join(" && ")});")
1231 return res
1232 end
1233
1234 fun can_be_primitive(value: RuntimeVariable): Bool
1235 do
1236 var t = value.mcasttype
1237 if t isa MNullableType then t = t.mtype
1238 if not t isa MClassType then return false
1239 var k = t.mclass.kind
1240 return k == interface_kind or t.ctype != "val*"
1241 end
1242
1243 fun maybe_null(value: RuntimeVariable): Bool
1244 do
1245 var t = value.mcasttype
1246 return t isa MNullableType or t isa MNullType
1247 end
1248
1249 redef fun array_instance(array, elttype)
1250 do
1251 var compiler = self.compiler.as(SeparateCompiler)
1252 var nclass = self.get_class("NativeArray")
1253 elttype = self.anchor(elttype)
1254 var arraytype = self.get_class("Array").get_mtype([elttype])
1255 var res = self.init_instance(arraytype)
1256 self.add("\{ /* {res} = array_instance Array[{elttype}] */")
1257 var nat = self.new_var(self.get_class("NativeArray").get_mtype([elttype]))
1258 nat.is_exact = true
1259 compiler.undead_types.add(nat.mtype.as(MClassType))
1260 self.add("{nat} = NEW_{nclass.c_name}({array.length}, (struct type *) &type_{nat.mtype.c_name});")
1261 for i in [0..array.length[ do
1262 var r = self.autobox(array[i], self.object_type)
1263 self.add("((struct instance_{nclass.c_name}*){nat})->values[{i}] = (val*) {r};")
1264 end
1265 var length = self.int_instance(array.length)
1266 self.send(self.get_property("with_native", arraytype), [res, nat, length])
1267 self.check_init_instance(res, arraytype)
1268 self.add("\}")
1269 return res
1270 end
1271
1272 redef fun native_array_def(pname, ret_type, arguments)
1273 do
1274 var elttype = arguments.first.mtype
1275 var nclass = self.get_class("NativeArray")
1276 var recv = "((struct instance_{nclass.c_name}*){arguments[0]})->values"
1277 if pname == "[]" then
1278 self.ret(self.new_expr("{recv}[{arguments[1]}]", ret_type.as(not null)))
1279 return
1280 else if pname == "[]=" then
1281 self.add("{recv}[{arguments[1]}]={arguments[2]};")
1282 return
1283 else if pname == "copy_to" then
1284 var recv1 = "((struct instance_{nclass.c_name}*){arguments[1]})->values"
1285 self.add("memcpy({recv1}, {recv}, {arguments[2]}*sizeof({elttype.ctype}));")
1286 return
1287 end
1288 end
1289
1290 redef fun calloc_array(ret_type, arguments)
1291 do
1292 var ret = ret_type.as(MGenericType)
1293 var compiler = self.compiler.as(SeparateCompiler)
1294 compiler.undead_types.add(ret)
1295 var mclass = self.get_class("ArrayCapable")
1296 var ft = mclass.mclass_type.arguments.first.as(MParameterType)
1297 var color = compiler.ft_colors[ft]
1298 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))
1299 end
1300 end
1301
1302 redef class MClass
1303 # Return the name of the C structure associated to a Nit class
1304 fun c_name: String do
1305 var res = self.c_name_cache
1306 if res != null then return res
1307 res = "{intro_mmodule.name.to_cmangle}__{name.to_cmangle}"
1308 self.c_name_cache = res
1309 return res
1310 end
1311 private var c_name_cache: nullable String
1312 end