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