1 # This file is part of NIT ( http://www.nitlanguage.org ).
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
15 # Separate compilation of a Nit program
16 module separate_compiler
18 import abstract_compiler
19 intrude import coloring
20 import rapid_type_analysis
22 # Add separate compiler specific options
23 redef class ToolContext
25 var opt_separate
: OptionBool = new OptionBool("Use separate compilation", "--separate")
27 var opt_no_inline_intern
: OptionBool = new OptionBool("Do not inline call to intern methods", "--no-inline-intern")
28 # --no-union-attribute
29 var opt_no_union_attribute
: OptionBool = new OptionBool("Put primitive attibutes in a box instead of an union", "--no-union-attribute")
30 # --no-shortcut-equate
31 var opt_no_shortcut_equate
: OptionBool = new OptionBool("Always call == in a polymorphic way", "--no-shortcut-equal")
32 # --inline-coloring-numbers
33 var opt_inline_coloring_numbers
: OptionBool = new OptionBool("Inline colors and ids", "--inline-coloring-numbers")
34 # --use-naive-coloring
35 var opt_bm_typing
: OptionBool = new OptionBool("Colorize items incrementaly, used to simulate binary matrix typing", "--bm-typing")
36 # --use-mod-perfect-hashing
37 var opt_phmod_typing
: OptionBool = new OptionBool("Replace coloration by perfect hashing (with mod operator)", "--phmod-typing")
38 # --use-and-perfect-hashing
39 var opt_phand_typing
: OptionBool = new OptionBool("Replace coloration by perfect hashing (with and operator)", "--phand-typing")
40 # --generic-resolution-tree
41 var opt_typing_table_metrics
: OptionBool = new OptionBool("Enable static size measuring of tables used for typing and resolution", "--typing-table-metrics")
46 self.option_context
.add_option
(self.opt_separate
)
47 self.option_context
.add_option
(self.opt_no_inline_intern
)
48 self.option_context
.add_option
(self.opt_no_union_attribute
)
49 self.option_context
.add_option
(self.opt_no_shortcut_equate
)
50 self.option_context
.add_option
(self.opt_inline_coloring_numbers
)
51 self.option_context
.add_option
(self.opt_bm_typing
)
52 self.option_context
.add_option
(self.opt_phmod_typing
)
53 self.option_context
.add_option
(self.opt_phand_typing
)
54 self.option_context
.add_option
(self.opt_typing_table_metrics
)
58 redef class ModelBuilder
59 fun run_separate_compiler
(mainmodule
: MModule, runtime_type_analysis
: RapidTypeAnalysis)
62 self.toolcontext
.info
("*** COMPILING TO C ***", 1)
64 var compiler
= new SeparateCompiler(mainmodule
, self, runtime_type_analysis
)
65 compiler
.compile_header
67 # compile class structures
68 for m
in mainmodule
.in_importation
.greaters
do
69 for mclass
in m
.intro_mclasses
do
70 compiler
.compile_class_to_c
(mclass
)
74 # The main function of the C
76 compiler
.compile_main_function
79 for m
in mainmodule
.in_importation
.greaters
do
81 compiler
.compile_module_to_c
(m
)
84 # compile live & cast type structures
86 var mtypes
= compiler
.do_type_coloring
88 compiler
.compile_type_to_c
(t
)
91 compiler
.display_stats
93 write_and_make
(compiler
)
97 # Singleton that store the knowledge about the separate compilation process
98 class SeparateCompiler
99 super AbstractCompiler
102 protected var classids
: HashMap[MClassType, String] = new HashMap[MClassType, String]
104 # The result of the RTA (used to know live types and methods)
105 var runtime_type_analysis
: RapidTypeAnalysis
107 private var undead_types
: Set[MType] = new HashSet[MType]
108 private var partial_types
: Set[MType] = new HashSet[MType]
110 private var type_layout_builder
: TypingLayoutBuilder[MType]
111 private var type_layout
: nullable TypingLayout[MType]
112 private var type_tables
: nullable Map[MType, Array[nullable MType]] = null
114 private var live_unanchored_types
: Map[MClassDef, Set[MType]] = new HashMap[MClassDef, HashSet[MType]]
116 private var unanchored_types_colors
: nullable Map[MType, Int]
117 private var unanchored_types_tables
: nullable Map[MClassType, Array[nullable MType]]
118 private var unanchored_types_masks
: nullable Map[MClassType, Int]
120 protected var method_colors
: Map[MMethod, Int]
121 protected var method_tables
: Map[MClass, Array[nullable MPropDef]]
123 protected var attr_colors
: Map[MAttribute, Int]
124 protected var attr_tables
: Map[MClass, Array[nullable MPropDef]]
126 protected var vt_colors
: Map[MVirtualTypeProp, Int]
127 protected var vt_tables
: Map[MClass, Array[nullable MPropDef]]
128 protected var vt_masks
: nullable Map[MClass, Int]
130 private var ft_colors
: nullable Map[MParameterType, Int]
131 private var ft_tables
: nullable Map[MClass, Array[nullable MParameterType]]
132 private var ft_masks
: nullable Map[MClass, Int]
134 init(mainmodule
: MModule, mmbuilder
: ModelBuilder, runtime_type_analysis
: RapidTypeAnalysis) do
136 self.header
= new_visitor
137 self.init_layout_builders
138 self.runtime_type_analysis
= runtime_type_analysis
139 self.do_property_coloring
140 self.compile_box_kinds
143 protected fun init_layout_builders
do
145 if modelbuilder
.toolcontext
.opt_bm_typing
.value
then
146 self.type_layout_builder
= new BMTypeLayoutBuilder(self.mainmodule
)
147 else if modelbuilder
.toolcontext
.opt_phmod_typing
.value
then
148 self.type_layout_builder
= new PHTypeLayoutBuilder(self.mainmodule
, new PHModOperator)
149 self.header
.add_decl
("#define HASH(mask, id) ((mask)%(id))")
150 else if modelbuilder
.toolcontext
.opt_phand_typing
.value
then
151 self.type_layout_builder
= new PHTypeLayoutBuilder(self.mainmodule
, new PHAndOperator)
152 self.header
.add_decl
("#define HASH(mask, id) ((mask)&(id))")
154 self.type_layout_builder
= new CLTypeLayoutBuilder(self.mainmodule
)
158 redef fun compile_header_structs
do
159 self.header
.add_decl
("typedef void(*nitmethod_t)(void); /* general C type representing a Nit method. */")
160 self.compile_header_attribute_structs
161 self.header
.add_decl
("struct class \{ int box_kind; nitmethod_t vft[1]; \}; /* general C type representing a Nit class. */")
163 # With unanchored_table, all live type resolution are stored in a big table: unanchored_table
164 self.header
.add_decl
("struct type \{ int id; const char *name; int color; short int is_nullable; struct types *unanchored_table; int table_size; int type_table[1]; \}; /* general C type representing a Nit type. */")
166 if modelbuilder
.toolcontext
.opt_phmod_typing
.value
or modelbuilder
.toolcontext
.opt_phand_typing
.value
then
167 self.header
.add_decl
("struct types \{ int mask; struct type *types[1]; \}; /* a list types (used for vts, fts and unanchored lists). */")
169 self.header
.add_decl
("struct types \{ struct type *types[1]; \}; /* a list types (used for vts, fts and unanchored lists). */")
172 self.header
.add_decl
("typedef struct \{ struct type *type; struct class *class; nitattribute_t attrs[1]; \} val; /* general C type representing a Nit instance. */")
175 fun compile_header_attribute_structs
177 if modelbuilder
.toolcontext
.opt_no_union_attribute
.value
then
178 self.header
.add_decl
("typedef void* nitattribute_t; /* general C type representing a Nit attribute. */")
180 self.header
.add_decl
("typedef union \{")
181 self.header
.add_decl
("void* val;")
182 for c
, v
in self.box_kinds
do
183 var t
= c
.mclass_type
184 self.header
.add_decl
("{t.ctype} {t.ctypename};")
186 self.header
.add_decl
("\} nitattribute_t; /* general C type representing a Nit attribute. */")
190 fun compile_box_kinds
192 # Collect all bas box class
193 # FIXME: this is not completely fine with a separate compilation scheme
194 for classname
in ["Int", "Bool", "Char", "Float", "NativeString", "Pointer"] do
195 var classes
= self.mainmodule
.model
.get_mclasses_by_name
(classname
)
196 if classes
== null then continue
197 assert classes
.length
== 1 else print classes
.join
(", ")
198 self.box_kinds
[classes
.first
] = self.box_kinds
.length
+ 1
202 var box_kinds
= new HashMap[MClass, Int]
204 fun box_kind_of
(mclass
: MClass): Int
206 if mclass
.mclass_type
.ctype
== "val*" then
208 else if mclass
.kind
== extern_kind
then
209 return self.box_kinds
[self.mainmodule
.get_primitive_class
("Pointer")]
211 return self.box_kinds
[mclass
]
216 fun compile_color_consts
(colors
: Map[Object, Int]) do
217 for m
, c
in colors
do
218 if m
isa MProperty then
219 if modelbuilder
.toolcontext
.opt_inline_coloring_numbers
.value
then
220 self.header
.add_decl
("#define {m.const_color} {c}")
222 self.header
.add_decl
("extern const int {m.const_color};")
223 self.header
.add
("const int {m.const_color} = {c};")
225 else if m
isa MType then
226 if modelbuilder
.toolcontext
.opt_inline_coloring_numbers
.value
then
227 self.header
.add_decl
("#define {m.const_color} {c}")
229 self.header
.add_decl
("extern const int {m.const_color};")
230 self.header
.add
("const int {m.const_color} = {c};")
236 # colorize classe properties
237 fun do_property_coloring
do
240 var mclasses
= new HashSet[MClass].from
(modelbuilder
.model
.mclasses
)
241 var class_coloring
= new ClassColoring(mainmodule
)
242 class_coloring
.colorize
(mclasses
)
245 var method_coloring
= new MethodColoring(mainmodule
, class_coloring
)
246 self.method_colors
= method_coloring
.colorize
247 self.method_tables
= build_property_tables
(method_coloring
, class_coloring
)
248 self.compile_color_consts
(self.method_colors
)
250 # attributes coloration
251 var attribute_coloring
= new AttributeColoring(mainmodule
, class_coloring
)
252 self.attr_colors
= attribute_coloring
.colorize
253 self.attr_tables
= build_property_tables
(method_coloring
, class_coloring
)
254 self.compile_color_consts
(self.attr_colors
)
257 if modelbuilder
.toolcontext
.opt_bm_typing
.value
then
258 var vt_coloring
= new NaiveVTColoring(mainmodule
, class_coloring
)
259 self.vt_colors
= vt_coloring
.colorize
260 self.vt_tables
= build_property_tables
(vt_coloring
, class_coloring
)
261 else if modelbuilder
.toolcontext
.opt_phmod_typing
.value
then
262 var vt_coloring
= new VTModPerfectHashing(mainmodule
, class_coloring
)
263 self.vt_colors
= vt_coloring
.colorize
264 self.vt_masks
= vt_coloring
.compute_masks
265 self.vt_tables
= build_property_tables
(vt_coloring
, class_coloring
)
266 else if modelbuilder
.toolcontext
.opt_phand_typing
.value
then
267 var vt_coloring
= new VTAndPerfectHashing(mainmodule
, class_coloring
)
268 self.vt_colors
= vt_coloring
.colorize
269 self.vt_masks
= vt_coloring
.compute_masks
270 self.vt_tables
= build_property_tables
(vt_coloring
, class_coloring
)
272 var vt_coloring
= new VTColoring(mainmodule
, class_coloring
)
273 self.vt_colors
= vt_coloring
.colorize
274 self.vt_tables
= build_property_tables
(vt_coloring
, class_coloring
)
276 self.compile_color_consts
(self.vt_colors
)
279 fun build_property_tables
(prop_coloring
: PropertyColoring, class_coloring
: ClassColoring): Map[MClass, Array[nullable MPropDef]] do
280 var tables
= new HashMap[MClass, Array[nullable MPropDef]]
281 var mclasses
= class_coloring
.coloration_result
.keys
282 for mclass
in mclasses
do
283 var table
= new Array[nullable MPropDef]
284 # first, fill table from parents by reverse linearization order
285 var parents
= class_coloring
.mmodule
.super_mclasses
(mclass
)
286 var lin
= class_coloring
.reverse_linearize
(parents
)
288 for mproperty
in prop_coloring
.properties
(parent
) do
289 var color
= prop_coloring
.coloration_result
[mproperty
]
290 if table
.length
<= color
then
291 for i
in [table
.length
.. color
[ do
295 for mpropdef
in mproperty
.mpropdefs
do
296 if mpropdef
.mclassdef
.mclass
== parent
then
297 table
[color
] = mpropdef
303 # then override with local properties
304 for mproperty
in prop_coloring
.properties
(mclass
) do
305 var color
= prop_coloring
.coloration_result
[mproperty
]
306 if table
.length
<= color
then
307 for i
in [table
.length
.. color
[ do
311 for mpropdef
in mproperty
.mpropdefs
do
312 if mpropdef
.mclassdef
.mclass
== mclass
then
313 table
[color
] = mpropdef
317 tables
[mclass
] = table
322 # colorize live types of the program
323 private fun do_type_coloring
: Set[MType] do
324 var mtypes
= new HashSet[MType]
325 mtypes
.add_all
(self.runtime_type_analysis
.live_types
)
326 mtypes
.add_all
(self.runtime_type_analysis
.live_cast_types
)
327 mtypes
.add_all
(self.undead_types
)
328 for c
in self.box_kinds
.keys
do
329 mtypes
.add
(c
.mclass_type
)
332 for mtype
in mtypes
do
333 retieve_live_partial_types
(mtype
)
335 mtypes
.add_all
(self.partial_types
)
337 # VT and FT are stored with other unresolved types in the big unanchored_tables
338 self.compile_unanchored_tables
(mtypes
)
341 self.type_layout
= self.type_layout_builder
.build_layout
(mtypes
)
342 self.type_tables
= self.build_type_tables
(mtypes
)
347 fun build_type_tables
(mtypes
: Set[MType]): Map[MType, Array[nullable MType]] do
348 var tables
= new HashMap[MType, Array[nullable MType]]
349 var layout
= self.type_layout
350 for mtype
in mtypes
do
351 var table
= new Array[nullable MType]
352 var supers
= new HashSet[MType]
353 supers
.add_all
(self.mainmodule
.super_mtypes
(mtype
, mtypes
))
357 if layout
isa PHTypingLayout[MType] then
358 color
= layout
.hashes
[mtype
][sup
]
360 color
= layout
.pos
[sup
]
362 if table
.length
<= color
then
363 for i
in [table
.length
.. color
[ do
369 tables
[mtype
] = table
374 protected fun compile_unanchored_tables
(mtypes
: Set[MType]) do
375 # Unanchored_tables is used to perform a type resolution at runtime in O(1)
377 # During the visit of the body of classes, live_unanchored_types are collected
379 # Collect all live_unanchored_types (visited in the body of classes)
381 # Determinate fo each livetype what are its possible requested anchored types
382 var mtype2unanchored
= new HashMap[MClassType, Set[MType]]
383 for mtype
in self.runtime_type_analysis
.live_types
do
384 var set
= new HashSet[MType]
385 for cd
in mtype
.collect_mclassdefs
(self.mainmodule
) do
386 if self.live_unanchored_types
.has_key
(cd
) then
387 set
.add_all
(self.live_unanchored_types
[cd
])
390 mtype2unanchored
[mtype
] = set
393 # Compute the table layout with the prefered method
394 if modelbuilder
.toolcontext
.opt_bm_typing
.value
then
395 var unanchored_type_coloring
= new NaiveUnanchoredTypeColoring
396 self.unanchored_types_colors
= unanchored_type_coloring
.colorize
(mtype2unanchored
)
397 self.unanchored_types_tables
= unanchored_type_coloring
.build_tables
(mtype2unanchored
)
398 else if modelbuilder
.toolcontext
.opt_phmod_typing
.value
then
399 var unanchored_type_coloring
= new UnanchoredTypeModPerfectHashing
400 self.unanchored_types_colors
= unanchored_type_coloring
.colorize
(mtype2unanchored
)
401 self.unanchored_types_masks
= unanchored_type_coloring
.compute_masks
(mtype2unanchored
)
402 self.unanchored_types_tables
= unanchored_type_coloring
.build_tables
(mtype2unanchored
)
403 else if modelbuilder
.toolcontext
.opt_phand_typing
.value
then
404 var unanchored_type_coloring
= new UnanchoredTypeAndPerfectHashing
405 self.unanchored_types_colors
= unanchored_type_coloring
.colorize
(mtype2unanchored
)
406 self.unanchored_types_masks
= unanchored_type_coloring
.compute_masks
(mtype2unanchored
)
407 self.unanchored_types_tables
= unanchored_type_coloring
.build_tables
(mtype2unanchored
)
409 var unanchored_type_coloring
= new UnanchoredTypeColoring
410 self.unanchored_types_colors
= unanchored_type_coloring
.colorize
(mtype2unanchored
)
411 self.unanchored_types_tables
= unanchored_type_coloring
.build_tables
(mtype2unanchored
)
414 # Compile a C constant for each collected unanchored type.
415 # Either to a color, or to -1 if the unanchored type is dead (no live receiver can require it)
416 var all_unanchored
= new HashSet[MType]
417 for t
in self.live_unanchored_types
.values
do
418 all_unanchored
.add_all
(t
)
420 var all_unanchored_types_colors
= new HashMap[MType, Int]
421 for t
in all_unanchored
do
422 if unanchored_types_colors
.has_key
(t
) then
423 all_unanchored_types_colors
[t
] = unanchored_types_colors
[t
]
425 all_unanchored_types_colors
[t
] = -1
428 self.compile_color_consts
(all_unanchored_types_colors
)
431 #for k, v in unanchored_types_tables.as(not null) do
432 # print "{k}: {v.join(", ")}"
437 fun retieve_live_partial_types
(mtype
: MType) do
438 # add formal types arguments to mtypes
439 if mtype
isa MGenericType then
440 for ft
in mtype
.arguments
do
441 if ft
.need_anchor
then
442 print
("Why do we need anchor here ?")
445 self.partial_types
.add
(ft
)
446 retieve_live_partial_types
(ft
)
449 var mclass_type
: MClassType
450 if mtype
isa MNullableType then
451 mclass_type
= mtype
.mtype
.as(MClassType)
453 mclass_type
= mtype
.as(MClassType)
456 # add virtual types to mtypes
457 for vt
in self.vt_tables
[mclass_type
.mclass
] do
459 var anchored
= vt
.as(MVirtualTypeDef).bound
.anchor_to
(self.mainmodule
, mclass_type
)
460 self.partial_types
.add
(anchored
)
465 # Separately compile all the method definitions of the module
466 fun compile_module_to_c
(mmodule
: MModule)
468 var old_module
= self.mainmodule
469 self.mainmodule
= mmodule
470 for cd
in mmodule
.mclassdefs
do
471 for pd
in cd
.mpropdefs
do
472 if not pd
isa MMethodDef then continue
473 #print "compile {pd} @ {cd} @ {mmodule}"
474 var r
= new SeparateRuntimeFunction(pd
)
476 if true or cd
.bound_mtype
.ctype
!= "val*" then
477 var r2
= new VirtualRuntimeFunction(pd
)
478 r2
.compile_to_c
(self)
482 self.mainmodule
= old_module
485 # Globaly compile the type structure of a live type
486 fun compile_type_to_c
(mtype
: MType)
488 var c_name
= mtype
.c_name
489 var v
= new SeparateCompilerVisitor(self)
490 v
.add_decl
("/* runtime type {mtype} */")
492 # extern const struct type_X
493 self.header
.add_decl
("extern const struct type_{c_name} type_{c_name};")
494 self.header
.add_decl
("struct type_{c_name} \{")
495 self.header
.add_decl
("int id;")
496 self.header
.add_decl
("const char *name;")
497 self.header
.add_decl
("int color;")
498 self.header
.add_decl
("short int is_nullable;")
499 self.header
.add_decl
("const struct types *unanchored_table;")
500 self.header
.add_decl
("int table_size;")
501 self.header
.add_decl
("int type_table[{self.type_tables[mtype].length}];")
502 self.header
.add_decl
("\};")
504 # const struct type_X
505 v
.add_decl
("const struct type_{c_name} type_{c_name} = \{")
506 v
.add_decl
("{self.type_layout.ids[mtype]},")
507 v
.add_decl
("\"{mtype}\
", /* class_name_string */")
508 var layout
= self.type_layout
509 if layout
isa PHTypingLayout[MType] then
510 v
.add_decl
("{layout.masks[mtype]},")
512 v
.add_decl
("{layout.pos[mtype]},")
514 if mtype
isa MNullableType then
519 if compile_type_unanchored_table
(mtype
) then
520 v
.add_decl
("(struct types*) &unanchored_table_{c_name},")
524 v
.add_decl
("{self.type_tables[mtype].length},")
526 for stype
in self.type_tables
[mtype
] do
527 if stype
== null then
528 v
.add_decl
("-1, /* empty */")
530 v
.add_decl
("{self.type_layout.ids[stype]}, /* {stype} */")
537 fun compile_type_unanchored_table
(mtype
: MType): Bool do
539 var mclass_type
: MClassType
540 if mtype
isa MNullableType then
541 mclass_type
= mtype
.mtype
.as(MClassType)
543 mclass_type
= mtype
.as(MClassType)
545 if not self.unanchored_types_tables
.has_key
(mclass_type
) then return false
547 # extern const struct unanchored_table_X unanchored_table_X
548 self.header
.add_decl
("extern const struct unanchored_table_{mtype.c_name} unanchored_table_{mtype.c_name};")
550 self.header
.add_decl
("struct unanchored_table_{mtype.c_name} \{")
551 if modelbuilder
.toolcontext
.opt_phmod_typing
.value
or modelbuilder
.toolcontext
.opt_phand_typing
.value
then
552 self.header
.add_decl
("int mask;")
554 self.header
.add_decl
("struct type *types[{self.unanchored_types_tables[mclass_type].length}];")
555 self.header
.add_decl
("\};")
557 # const struct fts_table_X fts_table_X
559 v
.add_decl
("const struct unanchored_table_{mtype.c_name} unanchored_table_{mtype.c_name} = \{")
560 if modelbuilder
.toolcontext
.opt_phmod_typing
.value
or modelbuilder
.toolcontext
.opt_phand_typing
.value
then
561 v
.add_decl
("{self.unanchored_types_masks[mclass_type]},")
564 for t
in self.unanchored_types_tables
[mclass_type
] do
566 v
.add_decl
("NULL, /* empty */")
568 # The table stores the result of the type resolution
569 # Therefore, for a receiver `mclass_type`, and a unresolved type `t`
570 # the value stored is tv.
571 var tv
= t
.resolve_for
(mclass_type
, mclass_type
, self.mainmodule
, true)
572 # FIXME: What typeids means here? How can a tv not be live?
573 if self.type_layout
.ids
.has_key
(tv
) then
574 v
.add_decl
("(struct type*)&type_{tv.c_name}, /* {t}: {tv} */")
576 v
.add_decl
("NULL, /* empty ({t}: {tv} not a live type) */")
585 # Globally compile the table of the class mclass
586 # In a link-time optimisation compiler, tables are globally computed
587 # In a true separate compiler (a with dynamic loading) you cannot do this unfortnally
588 fun compile_class_to_c
(mclass
: MClass)
590 var mtype
= mclass
.intro
.bound_mtype
591 var c_name
= mclass
.c_name
593 var vft
= self.method_tables
[mclass
]
594 var attrs
= self.attr_tables
[mclass
]
597 v
.add_decl
("/* runtime class {c_name} */")
598 var idnum
= classids
.length
599 var idname
= "ID_" + c_name
600 self.classids
[mtype
] = idname
601 #self.header.add_decl("#define {idname} {idnum} /* {c_name} */")
603 self.header
.add_decl
("struct class_{c_name} \{")
604 self.header
.add_decl
("int box_kind;")
605 self.header
.add_decl
("nitmethod_t vft[{vft.length}];")
606 self.header
.add_decl
("\};")
609 self.header
.add_decl
("extern const struct class_{c_name} class_{c_name};")
610 v
.add_decl
("const struct class_{c_name} class_{c_name} = \{")
611 v
.add_decl
("{self.box_kind_of(mclass)}, /* box_kind */")
613 for i
in [0 .. vft
.length
[ do
614 var mpropdef
= vft
[i
]
615 if mpropdef
== null then
616 v
.add_decl
("NULL, /* empty */")
618 if true or mpropdef
.mclassdef
.bound_mtype
.ctype
!= "val*" then
619 v
.add_decl
("(nitmethod_t)VIRTUAL_{mpropdef.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
621 v
.add_decl
("(nitmethod_t){mpropdef.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
628 if mtype
.ctype
!= "val*" then
629 #Build instance struct
630 self.header
.add_decl
("struct instance_{c_name} \{")
631 self.header
.add_decl
("const struct type *type;")
632 self.header
.add_decl
("const struct class *class;")
633 self.header
.add_decl
("{mtype.ctype} value;")
634 self.header
.add_decl
("\};")
636 if not self.runtime_type_analysis
.live_types
.has
(mtype
) then return
638 self.header
.add_decl
("val* BOX_{c_name}({mtype.ctype});")
639 v
.add_decl
("/* allocate {mtype} */")
640 v
.add_decl
("val* BOX_{mtype.c_name}({mtype.ctype} value) \{")
641 v
.add
("struct instance_{c_name}*res = GC_MALLOC(sizeof(struct instance_{c_name}));")
642 v
.add
("res->type = (struct type*) &type_{c_name};")
643 v
.add
("res->class = (struct class*) &class_{c_name};")
644 v
.add
("res->value = value;")
645 v
.add
("return (val*)res;")
650 var is_native_array
= mclass
.name
== "NativeArray"
653 if is_native_array
then
654 sig
= "int length, struct type* type"
656 sig
= "struct type* type"
659 #Build instance struct
660 #extern const struct instance_array__NativeArray instance_array__NativeArray;
661 self.header
.add_decl
("struct instance_{c_name} \{")
662 self.header
.add_decl
("const struct type *type;")
663 self.header
.add_decl
("const struct class *class;")
664 self.header
.add_decl
("nitattribute_t attrs[{attrs.length}];")
665 if is_native_array
then
666 # NativeArrays are just a instance header followed by an array of values
667 self.header
.add_decl
("val* values[0];")
669 self.header
.add_decl
("\};")
672 self.header
.add_decl
("{mtype.ctype} NEW_{c_name}({sig});")
673 v
.add_decl
("/* allocate {mtype} */")
674 v
.add_decl
("{mtype.ctype} NEW_{c_name}({sig}) \{")
675 var res
= v
.new_named_var
(mtype
, "self")
677 if is_native_array
then
678 var mtype_elt
= mtype
.arguments
.first
679 v
.add
("{res} = GC_MALLOC(sizeof(struct instance_{c_name}) + length*sizeof({mtype_elt.ctype}));")
681 v
.add
("{res} = GC_MALLOC(sizeof(struct instance_{c_name}));")
683 v
.add
("{res}->type = type;")
684 if v
.compiler
.modelbuilder
.toolcontext
.opt_hardening
.value
then
685 v
.add
("if(type == NULL) \{")
686 v
.add_abort
("type null")
688 v
.add
("if(type->unanchored_table == NULL) \{")
689 v
.add
("fprintf(stderr, \"Insantiation of a dead
type: %s\\n\
", type->name);")
690 v
.add_abort
("type dead")
693 v
.add
("{res}->class = (struct class*) &class_{c_name};")
695 self.generate_init_attr
(v
, res
, mtype
)
696 v
.add
("return {res};")
699 generate_check_init_instance
(mtype
)
702 redef fun generate_check_init_instance
(mtype
)
704 if self.modelbuilder
.toolcontext
.opt_no_check_initialization
.value
then return
706 var v
= self.new_visitor
707 var c_name
= mtype
.mclass
.c_name
708 var res
= new RuntimeVariable("self", mtype
, mtype
)
709 self.header
.add_decl
("void CHECK_NEW_{c_name}({mtype.ctype});")
710 v
.add_decl
("/* allocate {mtype} */")
711 v
.add_decl
("void CHECK_NEW_{c_name}({mtype.ctype} {res}) \{")
712 self.generate_check_attr
(v
, res
, mtype
)
716 redef fun new_visitor
do return new SeparateCompilerVisitor(self)
720 redef fun display_stats
723 if self.modelbuilder
.toolcontext
.opt_typing_table_metrics
.value
then
730 print
"# size of tables"
731 print
"\trs size\trs hole\tst size\tst hole"
736 var rtables
= unanchored_types_tables
737 if rtables
!= null then
738 for unanch
, table
in rtables
do
739 rt_table
+= table
.length
740 for e
in table
do if e
== null then rt_holes
+= 1
744 var ttables
= type_tables
745 if ttables
!= null then
746 for t
, table
in ttables
do
747 st_table
+= table
.length
748 for e
in table
do if e
== null then st_holes
+= 1
751 print
"\t{rt_table}\t{rt_holes}\t{st_table}\t{st_holes}"
755 # A visitor on the AST of property definition that generate the C code of a separate compilation process.
756 class SeparateCompilerVisitor
757 super AbstractCompilerVisitor
759 redef type COMPILER: SeparateCompiler
761 redef fun adapt_signature
(m
, args
)
763 var msignature
= m
.msignature
.resolve_for
(m
.mclassdef
.bound_mtype
, m
.mclassdef
.bound_mtype
, m
.mclassdef
.mmodule
, true)
764 var recv
= args
.first
765 if recv
.mtype
.ctype
!= m
.mclassdef
.mclass
.mclass_type
.ctype
then
766 args
.first
= self.autobox
(args
.first
, m
.mclassdef
.mclass
.mclass_type
)
768 for i
in [0..msignature
.arity
[ do
769 var t
= msignature
.mparameters
[i
].mtype
770 if i
== msignature
.vararg_rank
then
773 args
[i
+1] = self.autobox
(args
[i
+1], t
)
777 redef fun autobox
(value
, mtype
)
779 if value
.mtype
== mtype
then
781 else if value
.mtype
.ctype
== "val*" and mtype
.ctype
== "val*" then
783 else if value
.mtype
.ctype
== "val*" then
784 return self.new_expr
("((struct instance_{mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype
)
785 else if mtype
.ctype
== "val*" then
786 var valtype
= value
.mtype
.as(MClassType)
787 var res
= self.new_var
(mtype
)
788 if not compiler
.runtime_type_analysis
.live_types
.has
(valtype
) then
789 self.add
("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */")
790 self.add
("printf(\"Dead code executed
!\\n\
"); exit(1);")
793 self.add
("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
796 # Bad things will appen!
797 var res
= self.new_var
(mtype
)
798 self.add
("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */")
799 self.add
("printf(\"Cast error
: Cannot cast
%s to
%s
.\\n\
", \"{value.mtype}\
", \"{mtype}\
"); exit(1);")
804 # Return a C expression returning the runtime type structure of the value
805 # The point of the method is to works also with primitives types.
806 fun type_info
(value
: RuntimeVariable): String
808 if value
.mtype
.ctype
== "val*" then
809 return "{value}->type"
811 return "(&type_{value.mtype.c_name})"
815 redef fun send
(mmethod
, arguments
)
817 if arguments
.first
.mcasttype
.ctype
!= "val*" then
818 return self.monomorphic_send
(mmethod
, arguments
.first
.mcasttype
, arguments
)
821 var res
: nullable RuntimeVariable
822 var msignature
= mmethod
.intro
.msignature
.resolve_for
(mmethod
.intro
.mclassdef
.bound_mtype
, mmethod
.intro
.mclassdef
.bound_mtype
, mmethod
.intro
.mclassdef
.mmodule
, true)
823 var ret
= msignature
.return_mtype
824 if mmethod
.is_new
then
825 ret
= arguments
.first
.mtype
826 res
= self.new_var
(ret
)
827 else if ret
== null then
830 res
= self.new_var
(ret
)
836 var recv
= arguments
.first
839 self.varargize
(mmethod
.intro
, mmethod
.intro
.msignature
.as(not null), arguments
)
840 for i
in [0..msignature
.arity
[ do
841 var a
= arguments
[i
+1]
842 var t
= msignature
.mparameters
[i
].mtype
843 if i
== msignature
.vararg_rank
then
844 t
= arguments
[i
+1].mcasttype
846 s
.append
(", {t.ctype}")
847 a
= self.autobox
(a
, t
)
851 var consider_null
= not self.compiler
.modelbuilder
.toolcontext
.opt_no_check_other
.value
or mmethod
.name
== "==" or mmethod
.name
== "!="
852 var maybenull
= recv
.mcasttype
isa MNullableType and consider_null
854 self.add
("if ({recv} == NULL) \{")
855 if mmethod
.name
== "==" then
857 var arg
= arguments
[1]
858 if arg
.mcasttype
isa MNullableType then
859 self.add
("{res} = ({arg} == NULL);")
860 else if arg
.mcasttype
isa MNullType then
861 self.add
("{res} = 1; /* is null */")
863 self.add
("{res} = 0; /* {arg.inspect} cannot be null */")
865 else if mmethod
.name
== "!=" then
867 var arg
= arguments
[1]
868 if arg
.mcasttype
isa MNullableType then
869 self.add
("{res} = ({arg} != NULL);")
870 else if arg
.mcasttype
isa MNullType then
871 self.add
("{res} = 0; /* is null */")
873 self.add
("{res} = 1; /* {arg.inspect} cannot be null */")
876 self.add_abort
("Reciever is null")
878 self.add
("\} else \{")
880 if not self.compiler
.modelbuilder
.toolcontext
.opt_no_shortcut_equate
.value
and (mmethod
.name
== "==" or mmethod
.name
== "!=") then
882 # Recv is not null, thus is arg is, it is easy to conclude (and respect the invariants)
883 var arg
= arguments
[1]
884 if arg
.mcasttype
isa MNullType then
885 if mmethod
.name
== "==" then
886 self.add
("{res} = 0; /* arg is null but recv is not */")
888 self.add
("{res} = 1; /* arg is null and recv is not */")
898 if ret
== null then r
= "void" else r
= ret
.ctype
899 var call
= "(({r} (*)({s}))({arguments.first}->class->vft[{mmethod.const_color}]))({ss}) /* {mmethod} on {arguments.first.inspect}*/"
902 self.add
("{res} = {call};")
914 redef fun call
(mmethoddef
, recvtype
, arguments
)
916 var res
: nullable RuntimeVariable
917 var ret
= mmethoddef
.msignature
.return_mtype
918 if mmethoddef
.mproperty
.is_new
then
919 ret
= arguments
.first
.mtype
920 res
= self.new_var
(ret
)
921 else if ret
== null then
924 ret
= ret
.resolve_for
(mmethoddef
.mclassdef
.bound_mtype
, mmethoddef
.mclassdef
.bound_mtype
, mmethoddef
.mclassdef
.mmodule
, true)
925 res
= self.new_var
(ret
)
928 if self.compiler
.modelbuilder
.mpropdef2npropdef
.has_key
(mmethoddef
) and
929 self.compiler
.modelbuilder
.mpropdef2npropdef
[mmethoddef
] isa AInternMethPropdef and
930 not compiler
.modelbuilder
.toolcontext
.opt_no_inline_intern
.value
then
931 var frame
= new Frame(self, mmethoddef
, recvtype
, arguments
)
932 frame
.returnlabel
= self.get_name
("RET_LABEL")
933 frame
.returnvar
= res
934 var old_frame
= self.frame
936 self.add
("\{ /* Inline {mmethoddef} ({arguments.join(",")}) */")
937 mmethoddef
.compile_inside_to_c
(self, arguments
)
938 self.add
("{frame.returnlabel.as(not null)}:(void)0;")
940 self.frame
= old_frame
945 self.adapt_signature
(mmethoddef
, arguments
)
948 self.add
("{mmethoddef.c_name}({arguments.join(", ")});")
951 self.add
("{res} = {mmethoddef.c_name}({arguments.join(", ")});")
957 redef fun vararg_instance
(mpropdef
, recv
, varargs
, elttype
)
959 # A vararg must be stored into an new array
960 # The trick is that the dymaic type of the array may depends on the receiver
961 # of the method (ie recv) if the static type is unresolved
962 # This is more complex than usual because the unanchored type must not be resolved
963 # with the current receiver (ie self).
964 # Therefore to isolate the resolution from self, a local Frame is created.
965 # One can see this implementation as an inlined method of the receiver whose only
966 # job is to allocate the array
967 var old_frame
= self.frame
968 var frame
= new Frame(self, mpropdef
, mpropdef
.mclassdef
.bound_mtype
, [recv
])
970 #print "required Array[{elttype}] for recv {recv.inspect}. bound=Array[{self.resolve_for(elttype, recv)}]. selfvar={frame.arguments.first.inspect}"
971 var res
= self.array_instance
(varargs
, elttype
)
972 self.frame
= old_frame
976 redef fun isset_attribute
(a
, recv
)
978 self.check_recv_notnull
(recv
)
979 var res
= self.new_var
(bool_type
)
981 # What is the declared type of the attribute?
982 var mtype
= a
.intro
.static_mtype
.as(not null)
983 var intromclassdef
= a
.intro
.mclassdef
984 mtype
= mtype
.resolve_for
(intromclassdef
.bound_mtype
, intromclassdef
.bound_mtype
, intromclassdef
.mmodule
, true)
986 if mtype
isa MNullableType then
987 self.add
("{res} = 1; /* easy isset: {a} on {recv.inspect} */")
991 if self.compiler
.modelbuilder
.toolcontext
.opt_no_union_attribute
.value
then
992 self.add
("{res} = {recv}->attrs[{a.const_color}] != NULL; /* {a} on {recv.inspect}*/")
995 if mtype
.ctype
== "val*" then
996 self.add
("{res} = {recv}->attrs[{a.const_color}].val != NULL; /* {a} on {recv.inspect} */")
998 self.add
("{res} = 1; /* NOT YET IMPLEMENTED: isset of primitives: {a} on {recv.inspect} */")
1004 redef fun read_attribute
(a
, recv
)
1006 self.check_recv_notnull
(recv
)
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)
1013 if self.compiler
.modelbuilder
.toolcontext
.opt_no_union_attribute
.value
then
1014 # Get the attribute or a box (ie. always a val*)
1015 var cret
= self.object_type
.as_nullable
1016 var res
= self.new_var
(cret
)
1019 self.add
("{res} = {recv}->attrs[{a.const_color}]; /* {a} on {recv.inspect} */")
1021 # Check for Uninitialized attribute
1022 if not ret
isa MNullableType and not self.compiler
.modelbuilder
.toolcontext
.opt_no_check_initialization
.value
then
1023 self.add
("if ({res} == NULL) \{")
1024 self.add_abort
("Uninitialized attribute {a.name}")
1028 # Return the attribute or its unboxed version
1029 # Note: it is mandatory since we reuse the box on write, we do not whant that the box escapes
1030 return self.autobox
(res
, ret
)
1032 var res
= self.new_var
(ret
)
1033 self.add
("{res} = {recv}->attrs[{a.const_color}].{ret.ctypename}; /* {a} on {recv.inspect} */")
1035 # Check for Uninitialized attribute
1036 if ret
.ctype
== "val*" and not ret
isa MNullableType and not self.compiler
.modelbuilder
.toolcontext
.opt_no_check_initialization
.value
then
1037 self.add
("if ({res} == NULL) \{")
1038 self.add_abort
("Uninitialized attribute {a.name}")
1046 redef fun write_attribute
(a
, recv
, value
)
1048 self.check_recv_notnull
(recv
)
1050 # What is the declared type of the attribute?
1051 var mtype
= a
.intro
.static_mtype
.as(not null)
1052 var intromclassdef
= a
.intro
.mclassdef
1053 mtype
= mtype
.resolve_for
(intromclassdef
.bound_mtype
, intromclassdef
.bound_mtype
, intromclassdef
.mmodule
, true)
1055 # Adapt the value to the declared type
1056 value
= self.autobox
(value
, mtype
)
1058 if self.compiler
.modelbuilder
.toolcontext
.opt_no_union_attribute
.value
then
1059 var attr
= "{recv}->attrs[{a.const_color}]"
1060 if mtype
.ctype
!= "val*" then
1061 assert mtype
isa MClassType
1062 # The attribute is primitive, thus we store it in a box
1063 # The trick is to create the box the first time then resuse the box
1064 self.add
("if ({attr} != NULL) \{")
1065 self.add
("((struct instance_{mtype.c_name}*){attr})->value = {value}; /* {a} on {recv.inspect} */")
1066 self.add
("\} else \{")
1067 value
= self.autobox
(value
, self.object_type
.as_nullable
)
1068 self.add
("{attr} = {value}; /* {a} on {recv.inspect} */")
1071 # The attribute is not primitive, thus store it direclty
1072 self.add
("{attr} = {value}; /* {a} on {recv.inspect} */")
1075 self.add
("{recv}->attrs[{a.const_color}].{mtype.ctypename} = {value}; /* {a} on {recv.inspect} */")
1079 # Build livetype structure retrieving
1080 # ENSURE: mtype.need_anchor
1081 fun retrieve_anchored_livetype
(mtype
: MGenericType, buffer
: Buffer) do
1082 assert mtype
.need_anchor
1084 var compiler
= self.compiler
1085 for ft
in mtype
.arguments
do
1089 if ntype
isa MNullableType then
1093 var recv
= self.frame
.arguments
.first
1094 var recv_type_info
= self.type_info
(recv
)
1095 if ntype
isa MParameterType then
1096 if compiler
.modelbuilder
.toolcontext
.opt_phmod_typing
.value
or compiler
.modelbuilder
.toolcontext
.opt_phand_typing
.value
then
1097 buffer
.append
("[{recv_type_info}->fts_table->types[HASH({recv_type_info}->fts_table->mask, {ntype.const_color})]->livecolor]")
1099 buffer
.append
("[{recv_type_info}->fts_table->types[{ntype.const_color}]->livecolor]")
1101 else if ntype
isa MVirtualType then
1102 if compiler
.modelbuilder
.toolcontext
.opt_phmod_typing
.value
or compiler
.modelbuilder
.toolcontext
.opt_phand_typing
.value
then
1103 buffer
.append
("[{recv_type_info}->vts_table->types[HASH({recv_type_info}->vts_table->mask, {ntype.mproperty.const_color})]->livecolor]")
1105 buffer
.append
("[{recv_type_info}->vts_table->types[{ntype.mproperty.const_color}]->livecolor]")
1107 else if ntype
isa MGenericType and ntype
.need_anchor
then
1108 var bbuff
= new Buffer
1109 retrieve_anchored_livetype
(ntype
, bbuff
)
1110 buffer
.append
("[livetypes_{ntype.mclass.c_name}{bbuff.to_s}->livecolor]")
1111 else if ntype
isa MClassType then
1112 compiler
.undead_types
.add
(ft
)
1113 buffer
.append
("[type_{ft.c_name}.livecolor]")
1115 self.add
("printf(\"NOT YET IMPLEMENTED: init_instance
(%s
, {mtype}).\\n\
", \"{ft}\
"); exit(1);")
1120 redef fun init_instance
(mtype
)
1122 var compiler
= self.compiler
1123 if mtype
isa MGenericType and mtype
.need_anchor
then
1124 link_unanchored_type
(self.frame
.mpropdef
.mclassdef
, mtype
)
1125 var recv
= self.frame
.arguments
.first
1126 var recv_type_info
= self.type_info
(recv
)
1127 if compiler
.modelbuilder
.toolcontext
.opt_phmod_typing
.value
or compiler
.modelbuilder
.toolcontext
.opt_phand_typing
.value
then
1128 return self.new_expr
("NEW_{mtype.mclass.c_name}((struct type *) {recv_type_info}->unanchored_table->types[HASH({recv_type_info}->unanchored_table->mask, {mtype.const_color})])", mtype
)
1130 return self.new_expr
("NEW_{mtype.mclass.c_name}((struct type *) {recv_type_info}->unanchored_table->types[{mtype.const_color}])", mtype
)
1133 compiler
.undead_types
.add
(mtype
)
1134 return self.new_expr
("NEW_{mtype.mclass.c_name}((struct type *) &type_{mtype.c_name})", mtype
)
1137 redef fun check_init_instance
(value
, mtype
)
1139 if self.compiler
.modelbuilder
.toolcontext
.opt_no_check_initialization
.value
then return
1140 self.add
("CHECK_NEW_{mtype.mclass.c_name}({value});")
1143 redef fun type_test
(value
, mtype
, tag
)
1145 self.add
("/* {value.inspect} isa {mtype} */")
1146 var compiler
= self.compiler
1148 var recv
= self.frame
.arguments
.first
1149 var recv_type_info
= self.type_info
(recv
)
1151 var res
= self.new_var
(bool_type
)
1153 var cltype
= self.get_name
("cltype")
1154 self.add_decl
("int {cltype};")
1155 var idtype
= self.get_name
("idtype")
1156 self.add_decl
("int {idtype};")
1158 var maybe_null
= self.maybe_null
(value
)
1159 var accept_null
= "0"
1161 if ntype
isa MNullableType then
1166 if value
.mcasttype
.is_subtype
(self.frame
.mpropdef
.mclassdef
.mmodule
, self.frame
.mpropdef
.mclassdef
.bound_mtype
, mtype
) then
1167 self.add
("{res} = 1; /* easy {value.inspect} isa {mtype}*/")
1168 if compiler
.modelbuilder
.toolcontext
.opt_typing_test_metrics
.value
then
1169 self.compiler
.count_type_test_skipped
[tag
] += 1
1170 self.add
("count_type_test_skipped_{tag}++;")
1175 if ntype
.need_anchor
then
1176 var type_struct
= self.get_name
("type_struct")
1177 self.add_decl
("struct type* {type_struct};")
1179 # Either with unanchored_table with a direct resolution
1180 link_unanchored_type
(self.frame
.mpropdef
.mclassdef
, ntype
)
1181 if compiler
.modelbuilder
.toolcontext
.opt_phmod_typing
.value
or compiler
.modelbuilder
.toolcontext
.opt_phand_typing
.value
then
1182 self.add
("{type_struct} = {recv_type_info}->unanchored_table->types[HASH({recv_type_info}->unanchored_table->mask, {ntype.const_color})];")
1184 self.add
("{type_struct} = {recv_type_info}->unanchored_table->types[{ntype.const_color}];")
1186 if compiler
.modelbuilder
.toolcontext
.opt_typing_test_metrics
.value
then
1187 self.compiler
.count_type_test_unresolved
[tag
] += 1
1188 self.add
("count_type_test_unresolved_{tag}++;")
1190 self.add
("{cltype} = {type_struct}->color;")
1191 self.add
("{idtype} = {type_struct}->id;")
1192 if maybe_null
and accept_null
== "0" then
1193 var is_nullable
= self.get_name
("is_nullable")
1194 self.add_decl
("short int {is_nullable};")
1195 self.add
("{is_nullable} = {type_struct}->is_nullable;")
1196 accept_null
= is_nullable
.to_s
1198 else if ntype
isa MClassType then
1199 compiler
.undead_types
.add
(mtype
)
1200 self.add
("{cltype} = type_{mtype.c_name}.color;")
1201 self.add
("{idtype} = type_{mtype.c_name}.id;")
1202 if compiler
.modelbuilder
.toolcontext
.opt_typing_test_metrics
.value
then
1203 self.compiler
.count_type_test_resolved
[tag
] += 1
1204 self.add
("count_type_test_resolved_{tag}++;")
1207 self.add
("printf(\"NOT YET IMPLEMENTED: type_test
(%s
, {mtype}).\\n\
", \"{value.inspect}\
"); exit(1);")
1210 # check color is in table
1212 self.add
("if({value} == NULL) \{")
1213 self.add
("{res} = {accept_null};")
1214 self.add
("\} else \{")
1216 var value_type_info
= self.type_info
(value
)
1217 if compiler
.modelbuilder
.toolcontext
.opt_phmod_typing
.value
or compiler
.modelbuilder
.toolcontext
.opt_phand_typing
.value
then
1218 self.add
("{cltype} = HASH({value_type_info}->color, {idtype});")
1220 self.add
("if({cltype} >= {value_type_info}->table_size) \{")
1221 self.add
("{res} = 0;")
1222 self.add
("\} else \{")
1223 self.add
("{res} = {value_type_info}->type_table[{cltype}] == {idtype};")
1232 redef fun is_same_type_test
(value1
, value2
)
1234 var res
= self.new_var
(bool_type
)
1235 # Swap values to be symetric
1236 if value2
.mtype
.ctype
!= "val*" and value1
.mtype
.ctype
== "val*" then
1241 if value1
.mtype
.ctype
!= "val*" then
1242 if value2
.mtype
== value1
.mtype
then
1243 self.add
("{res} = 1; /* is_same_type_test: compatible types {value1.mtype} vs. {value2.mtype} */")
1244 else if value2
.mtype
.ctype
!= "val*" then
1245 self.add
("{res} = 0; /* is_same_type_test: incompatible types {value1.mtype} vs. {value2.mtype}*/")
1247 var mtype1
= value1
.mtype
.as(MClassType)
1248 self.add
("{res} = ({value2} != NULL) && ({value2}->class == (struct class*) &class_{mtype1.c_name}); /* is_same_type_test */")
1251 self.add
("{res} = ({value1} == {value2}) || ({value1} != NULL && {value2} != NULL && {value1}->class == {value2}->class); /* is_same_type_test */")
1256 redef fun class_name_string
(value
)
1258 var res
= self.get_name
("var_class_name")
1259 self.add_decl
("const char* {res};")
1260 if value
.mtype
.ctype
== "val*" then
1261 self.add
"{res} = {value} == NULL ? \"null\
" : {value}->type->name;"
1263 self.add
"{res} = type_{value.mtype.c_name}.name;"
1268 redef fun equal_test
(value1
, value2
)
1270 var res
= self.new_var
(bool_type
)
1271 if value2
.mtype
.ctype
!= "val*" and value1
.mtype
.ctype
== "val*" then
1276 if value1
.mtype
.ctype
!= "val*" then
1277 if value2
.mtype
== value1
.mtype
then
1278 self.add
("{res} = {value1} == {value2};")
1279 else if value2
.mtype
.ctype
!= "val*" then
1280 self.add
("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
1282 var mtype1
= value1
.mtype
.as(MClassType)
1283 self.add
("{res} = ({value2} != NULL) && ({value2}->class == (struct class*) &class_{mtype1.c_name});")
1284 self.add
("if ({res}) \{")
1285 self.add
("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
1290 var maybe_null
= true
1291 var test
= new Array[String]
1292 var t1
= value1
.mcasttype
1293 if t1
isa MNullableType then
1294 test
.add
("{value1} != NULL")
1299 var t2
= value2
.mcasttype
1300 if t2
isa MNullableType then
1301 test
.add
("{value2} != NULL")
1307 var incompatible
= false
1309 if t1
.ctype
!= "val*" then
1312 # No need to compare class
1313 else if t2
.ctype
!= "val*" then
1315 else if can_be_primitive
(value2
) then
1316 test
.add
("{value1}->class == {value2}->class")
1320 else if t2
.ctype
!= "val*" then
1322 if can_be_primitive
(value1
) then
1323 test
.add
("{value1}->class == {value2}->class")
1331 if incompatible
then
1333 self.add
("{res} = {value1} == {value2}; /* incompatible types {t1} vs. {t2}; but may be NULL*/")
1336 self.add
("{res} = 0; /* incompatible types {t1} vs. {t2}; cannot be NULL */")
1340 if primitive
!= null then
1341 test
.add
("((struct instance_{primitive.c_name}*){value1})->value == ((struct instance_{primitive.c_name}*){value2})->value")
1342 else if can_be_primitive
(value1
) and can_be_primitive
(value2
) then
1343 test
.add
("{value1}->class == {value2}->class")
1344 var s
= new Array[String]
1345 for t
, v
in self.compiler
.box_kinds
do
1346 s
.add
"({value1}->class->box_kind == {v} && ((struct instance_{t.c_name}*){value1})->value == ((struct instance_{t.c_name}*){value2})->value)"
1348 test
.add
("({s.join(" || ")})")
1350 self.add
("{res} = {value1} == {value2};")
1353 self.add
("{res} = {value1} == {value2} || ({test.join(" && ")});")
1357 fun can_be_primitive
(value
: RuntimeVariable): Bool
1359 var t
= value
.mcasttype
1360 if t
isa MNullableType then t
= t
.mtype
1361 if not t
isa MClassType then return false
1362 var k
= t
.mclass
.kind
1363 return k
== interface_kind
or t
.ctype
!= "val*"
1366 fun maybe_null
(value
: RuntimeVariable): Bool
1368 var t
= value
.mcasttype
1369 return t
isa MNullableType or t
isa MNullType
1372 redef fun array_instance
(array
, elttype
)
1374 var nclass
= self.get_class
("NativeArray")
1375 var arrayclass
= self.get_class
("Array")
1376 var arraytype
= arrayclass
.get_mtype
([elttype
])
1377 var res
= self.init_instance
(arraytype
)
1378 self.add
("\{ /* {res} = array_instance Array[{elttype}] */")
1379 var length
= self.int_instance
(array
.length
)
1380 var nat
= native_array_instance
(elttype
, length
)
1381 for i
in [0..array
.length
[ do
1382 var r
= self.autobox
(array
[i
], self.object_type
)
1383 self.add
("((struct instance_{nclass.c_name}*){nat})->values[{i}] = (val*) {r};")
1385 self.send
(self.get_property
("with_native", arrayclass
.intro
.bound_mtype
), [res
, nat
, length
])
1386 self.check_init_instance
(res
, arraytype
)
1391 fun native_array_instance
(elttype
: MType, length
: RuntimeVariable): RuntimeVariable
1393 var mtype
= self.get_class
("NativeArray").get_mtype
([elttype
])
1394 assert mtype
isa MGenericType
1395 var compiler
= self.compiler
1396 if mtype
.need_anchor
then
1397 link_unanchored_type
(self.frame
.mpropdef
.mclassdef
, mtype
)
1398 var recv
= self.frame
.arguments
.first
1399 var recv_type_info
= self.type_info
(recv
)
1400 if compiler
.modelbuilder
.toolcontext
.opt_phmod_typing
.value
or compiler
.modelbuilder
.toolcontext
.opt_phand_typing
.value
then
1401 return self.new_expr
("NEW_{mtype.mclass.c_name}({length}, (struct type *) {recv_type_info}->unanchored_table->types[HASH({recv_type_info}->unanchored_table->mask, {mtype.const_color})])", mtype
)
1403 return self.new_expr
("NEW_{mtype.mclass.c_name}({length}, (struct type *) {recv_type_info}->unanchored_table->types[{mtype.const_color}])", mtype
)
1406 compiler
.undead_types
.add
(mtype
)
1407 return self.new_expr
("NEW_{mtype.mclass.c_name}({length}, (struct type *) &type_{mtype.c_name})", mtype
)
1410 redef fun native_array_def
(pname
, ret_type
, arguments
)
1412 var elttype
= arguments
.first
.mtype
1413 var nclass
= self.get_class
("NativeArray")
1414 var recv
= "((struct instance_{nclass.c_name}*){arguments[0]})->values"
1415 if pname
== "[]" then
1416 self.ret
(self.new_expr
("{recv}[{arguments[1]}]", ret_type
.as(not null)))
1418 else if pname
== "[]=" then
1419 self.add
("{recv}[{arguments[1]}]={arguments[2]};")
1421 else if pname
== "copy_to" then
1422 var recv1
= "((struct instance_{nclass.c_name}*){arguments[1]})->values"
1423 self.add
("memcpy({recv1}, {recv}, {arguments[2]}*sizeof({elttype.ctype}));")
1428 redef fun calloc_array
(ret_type
, arguments
)
1430 var mclass
= self.get_class
("ArrayCapable")
1431 var ft
= mclass
.mclass_type
.arguments
.first
.as(MParameterType)
1432 var res
= self.native_array_instance
(ft
, arguments
[1])
1436 fun link_unanchored_type
(mclassdef
: MClassDef, mtype
: MType) do
1437 assert mtype
.need_anchor
1438 var compiler
= self.compiler
1439 if not compiler
.live_unanchored_types
.has_key
(self.frame
.mpropdef
.mclassdef
) then
1440 compiler
.live_unanchored_types
[self.frame
.mpropdef
.mclassdef
] = new HashSet[MType]
1442 compiler
.live_unanchored_types
[self.frame
.mpropdef
.mclassdef
].add
(mtype
)
1446 # The C function associated to a methoddef separately compiled
1447 class SeparateRuntimeFunction
1448 super AbstractRuntimeFunction
1450 redef fun build_c_name
: String do return "{mmethoddef.c_name}"
1452 redef fun to_s
do return self.mmethoddef
.to_s
1454 redef fun compile_to_c
(compiler
)
1456 var mmethoddef
= self.mmethoddef
1458 var recv
= self.mmethoddef
.mclassdef
.bound_mtype
1459 var v
= compiler
.new_visitor
1460 var selfvar
= new RuntimeVariable("self", recv
, recv
)
1461 var arguments
= new Array[RuntimeVariable]
1462 var frame
= new Frame(v
, mmethoddef
, recv
, arguments
)
1465 var msignature
= mmethoddef
.msignature
.resolve_for
(mmethoddef
.mclassdef
.bound_mtype
, mmethoddef
.mclassdef
.bound_mtype
, mmethoddef
.mclassdef
.mmodule
, true)
1467 var sig
= new Buffer
1468 var comment
= new Buffer
1469 var ret
= msignature
.return_mtype
1471 sig
.append
("{ret.ctype} ")
1472 else if mmethoddef
.mproperty
.is_new
then
1474 sig
.append
("{ret.ctype} ")
1478 sig
.append
(self.c_name
)
1479 sig
.append
("({selfvar.mtype.ctype} {selfvar}")
1480 comment
.append
("(self: {selfvar}")
1481 arguments
.add
(selfvar
)
1482 for i
in [0..msignature
.arity
[ do
1483 var mtype
= msignature
.mparameters
[i
].mtype
1484 if i
== msignature
.vararg_rank
then
1485 mtype
= v
.get_class
("Array").get_mtype
([mtype
])
1487 comment
.append
(", {mtype}")
1488 sig
.append
(", {mtype.ctype} p{i}")
1489 var argvar
= new RuntimeVariable("p{i}", mtype
, mtype
)
1490 arguments
.add
(argvar
)
1495 comment
.append
(": {ret}")
1497 compiler
.header
.add_decl
("{sig};")
1499 v
.add_decl
("/* method {self} for {comment} */")
1500 v
.add_decl
("{sig} \{")
1502 frame
.returnvar
= v
.new_var
(ret
)
1504 frame
.returnlabel
= v
.get_name
("RET_LABEL")
1506 if recv
!= arguments
.first
.mtype
then
1507 #print "{self} {recv} {arguments.first}"
1509 mmethoddef
.compile_inside_to_c
(v
, arguments
)
1511 v
.add
("{frame.returnlabel.as(not null)}:;")
1513 v
.add
("return {frame.returnvar.as(not null)};")
1519 # The C function associated to a methoddef on a primitive type, stored into a VFT of a class
1520 # The first parameter (the reciever) is always typed by val* in order to accept an object value
1521 class VirtualRuntimeFunction
1522 super AbstractRuntimeFunction
1524 redef fun build_c_name
: String do return "VIRTUAL_{mmethoddef.c_name}"
1526 redef fun to_s
do return self.mmethoddef
.to_s
1528 redef fun compile_to_c
(compiler
)
1530 var mmethoddef
= self.mmethoddef
1532 var recv
= self.mmethoddef
.mclassdef
.bound_mtype
1533 var v
= compiler
.new_visitor
1534 var selfvar
= new RuntimeVariable("self", v
.object_type
, recv
)
1535 var arguments
= new Array[RuntimeVariable]
1536 var frame
= new Frame(v
, mmethoddef
, recv
, arguments
)
1539 var sig
= new Buffer
1540 var comment
= new Buffer
1542 # Because the function is virtual, the signature must match the one of the original class
1543 var intromclassdef
= self.mmethoddef
.mproperty
.intro
.mclassdef
1544 var msignature
= mmethoddef
.mproperty
.intro
.msignature
.resolve_for
(intromclassdef
.bound_mtype
, intromclassdef
.bound_mtype
, intromclassdef
.mmodule
, true)
1545 var ret
= msignature
.return_mtype
1547 sig
.append
("{ret.ctype} ")
1548 else if mmethoddef
.mproperty
.is_new
then
1550 sig
.append
("{ret.ctype} ")
1554 sig
.append
(self.c_name
)
1555 sig
.append
("({selfvar.mtype.ctype} {selfvar}")
1556 comment
.append
("(self: {selfvar}")
1557 arguments
.add
(selfvar
)
1558 for i
in [0..msignature
.arity
[ do
1559 var mtype
= msignature
.mparameters
[i
].mtype
1560 if i
== msignature
.vararg_rank
then
1561 mtype
= v
.get_class
("Array").get_mtype
([mtype
])
1563 comment
.append
(", {mtype}")
1564 sig
.append
(", {mtype.ctype} p{i}")
1565 var argvar
= new RuntimeVariable("p{i}", mtype
, mtype
)
1566 arguments
.add
(argvar
)
1571 comment
.append
(": {ret}")
1573 compiler
.header
.add_decl
("{sig};")
1575 v
.add_decl
("/* method {self} for {comment} */")
1576 v
.add_decl
("{sig} \{")
1578 frame
.returnvar
= v
.new_var
(ret
)
1580 frame
.returnlabel
= v
.get_name
("RET_LABEL")
1582 if recv
!= arguments
.first
.mtype
then
1583 #print "{self} {recv} {arguments.first}"
1585 mmethoddef
.compile_inside_to_c
(v
, arguments
)
1587 v
.add
("{frame.returnlabel.as(not null)}:;")
1589 v
.add
("return {frame.returnvar.as(not null)};")
1595 redef fun call
(v
, arguments
) do abort
1599 fun const_color
: String do return "COLOR_{c_name}"
1602 redef class MProperty
1603 fun const_color
: String do return "COLOR_{c_name}"