end
end
- var separate_compiler_phase = new SeparateCompilerPhase(self, null)
+ var separate_compiler_phase = new SeparateCompilerPhase(self, [contracts_phase])
end
class SeparateCompilerPhase
private var type_ids: Map[MType, Int] is noinit
private var type_colors: Map[MType, Int] is noinit
private var opentype_colors: Map[MType, Int] is noinit
- private var thunks_to_compile: Set[SeparateRuntimeFunction] = new HashSet[SeparateRuntimeFunction]
+ private var thunks_to_compile: Set[SeparateRuntimeFunction] = new HashSet[SeparateRuntimeFunction]
init do
var file = new_file("nit.common")
compiler.compile_types
end
- fun thunk_todo(thunk: SeparateRuntimeFunction)
- do
- # Concrete instance of `SeparateRuntimeFunction` are already
- # handled by the compiler. Avoid duplicate compilation.
- if thunk isa SeparateThunkFunction then
- thunks_to_compile.add(thunk)
- end
- end
+ fun thunk_todo(thunk: SeparateRuntimeFunction)
+ do
+ # Concrete instance of `SeparateRuntimeFunction` are already
+ # handled by the compiler. Avoid duplicate compilation.
+ if thunk isa SeparateThunkFunction then
+ thunks_to_compile.add(thunk)
+ end
+ end
# Color and compile type structures and cast information
fun compile_types
# Collect all bas box class
# FIXME: this is not completely fine with a separate compilation scheme
for classname in ["Int", "Bool", "Byte", "Char", "Float", "CString",
- "Pointer", "Int8", "Int16", "UInt16", "Int32", "UInt32"] do
+ "Pointer", "Int8", "Int16", "UInt16", "Int32", "UInt32"] do
var classes = self.mainmodule.model.get_mclasses_by_name(classname)
if classes == null then continue
assert classes.length == 1 else print_error classes.join(", ")
return self.box_kinds[self.mainmodule.pointer_type.mclass]
else
return self.box_kinds[mclass]
- end
+ end
end
fun compile_color_consts(colors: Map[Object, Int]) do
end
end
end
- var compiled_thunks = new Array[SeparateRuntimeFunction]
- # Compile thunks here to write them in the same module they are declared.
- for thunk in thunks_to_compile do
- if thunk.mmethoddef.mclassdef.mmodule == mmodule then
- thunk.compile_to_c(self)
- compiled_thunks.add(thunk)
- end
- end
- thunks_to_compile.remove_all(compiled_thunks)
+ var compiled_thunks = new Array[SeparateRuntimeFunction]
+ # Compile thunks here to write them in the same module they are declared.
+ for thunk in thunks_to_compile do
+ if thunk.mmethoddef.mclassdef.mmodule == mmodule then
+ thunk.compile_to_c(self)
+ compiled_thunks.add(thunk)
+ end
+ end
+ thunks_to_compile.remove_all(compiled_thunks)
self.mainmodule = old_module
end
v.add_decl("\};")
end
- # Globally compile the table of the class mclass
- # In a link-time optimisation compiler, tables are globally computed
- # In a true separate compiler (a with dynamic loading) you cannot do this unfortnally
- fun compile_class_to_c(mclass: MClass)
+ protected fun compile_class_vft(ccinfo: ClassCompilationInfo, v: SeparateCompilerVisitor)
do
- if mclass.is_broken then return
-
- var mtype = mclass.intro.bound_mtype
- var c_name = mclass.c_name
-
- var v = new_visitor
-
+ var mclass = ccinfo.mclass
+ var mtype = ccinfo.mtype
var rta = runtime_type_analysis
- var is_dead = rta != null and not rta.live_classes.has(mclass)
- # While the class may be dead, some part of separately compiled code may use symbols associated to the class, so
- # in order to compile and link correctly the C code, these symbols should be declared and defined.
- var need_corpse = is_dead and mtype.is_c_primitive or mclass.kind == extern_kind or mclass.kind == enum_kind
+ var c_name = ccinfo.mclass.c_name
+ var is_dead = ccinfo.is_dead
+ var need_corpse = ccinfo.need_corpse
v.add_decl("/* runtime class {c_name}: {mclass.full_name} (dead={is_dead}; need_corpse={need_corpse})*/")
v.add_decl("\}")
v.add_decl("\};")
end
+ end
+
+ # Given a `MClass`, if it's a universal class and if it needs to be handle
+ # specifically by the compiler, this function will compile it and return
+ # true. Otherwise, no C code will be written in the visitor and the value
+ # false will be returned.
+ fun compile_class_if_universal(ccinfo: ClassCompilationInfo, v: SeparateCompilerVisitor): Bool
+ do
+ var mclass = ccinfo.mclass
+ var mtype = ccinfo.mtype
+ var c_name = ccinfo.mclass.c_name
+ var is_dead = ccinfo.is_dead
+ var need_corpse = ccinfo.need_corpse
if mtype.is_c_primitive or mtype.mclass.name == "Pointer" then
# Is a primitive type or the Pointer class, not any other extern class
- if mtype.is_tagged then return
+ if mtype.is_tagged then return true
#Build instance struct
self.header.add_decl("struct instance_{c_name} \{")
self.header.add_decl("\};")
# Pointer is needed by extern types, live or not
- if is_dead and mtype.mclass.name != "Pointer" then return
+ if is_dead and mtype.mclass.name != "Pointer" then return true
#Build BOX
self.provide_declaration("BOX_{c_name}", "val* BOX_{c_name}({mtype.ctype_extern});")
v.add("\}")
# A Pointer class also need its constructor
- if mtype.mclass.name != "Pointer" then return
+ if mtype.mclass.name != "Pointer" then return true
v = new_visitor
self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(const struct type* type);")
v.add("return {res};")
end
v.add("\}")
- return
+ return true
else if mclass.name == "NativeArray" then
#Build instance struct
self.header.add_decl("struct instance_{c_name} \{")
v.add("{res}->length = length;")
v.add("return (val*){res};")
v.add("\}")
- return
- else if mclass.name == "RoutineRef" then
- self.header.add_decl("struct instance_{c_name} \{")
- self.header.add_decl("const struct type *type;")
- self.header.add_decl("const struct class *class;")
- self.header.add_decl("val* recv;")
- self.header.add_decl("nitmethod_t method;")
- self.header.add_decl("\};")
-
- self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(val* recv, nitmethod_t method, const struct class* class, const struct type* type);")
- v.add_decl("/* allocate {mtype} */")
- v.add_decl("{mtype.ctype} NEW_{c_name}(val* recv, nitmethod_t method, const struct class* class, const struct type* type)\{")
- var res = v.get_name("self")
- v.add_decl("struct instance_{c_name} *{res};")
- var alloc = v.nit_alloc("sizeof(struct instance_{c_name})", mclass.full_name)
- v.add("{res} = {alloc};")
- v.add("{res}->type = type;")
- hardening_live_type(v, "type")
- v.add("{res}->class = class;")
- v.add("{res}->recv = recv;")
- v.add("{res}->method = method;")
- v.add("return (val*){res};")
- v.add("\}")
- return
+ return true
+ else if mclass.name == "RoutineRef" then
+ self.header.add_decl("struct instance_{c_name} \{")
+ self.header.add_decl("const struct type *type;")
+ self.header.add_decl("const struct class *class;")
+ self.header.add_decl("val* recv;")
+ self.header.add_decl("nitmethod_t method;")
+ self.header.add_decl("\};")
+
+ self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(val* recv, nitmethod_t method, const struct class* class, const struct type* type);")
+ v.add_decl("/* allocate {mtype} */")
+ v.add_decl("{mtype.ctype} NEW_{c_name}(val* recv, nitmethod_t method, const struct class* class, const struct type* type)\{")
+ var res = v.get_name("self")
+ v.add_decl("struct instance_{c_name} *{res};")
+ var alloc = v.nit_alloc("sizeof(struct instance_{c_name})", mclass.full_name)
+ v.add("{res} = {alloc};")
+ v.add("{res}->type = type;")
+ hardening_live_type(v, "type")
+ v.add("{res}->class = class;")
+ v.add("{res}->recv = recv;")
+ v.add("{res}->method = method;")
+ v.add("return (val*){res};")
+ v.add("\}")
+ return true
else if mtype.mclass.kind == extern_kind and mtype.mclass.name != "CString" then
# Is an extern class (other than Pointer and CString)
# Pointer is caught in a previous `if`, and CString is internal
v.add("return {res};")
end
v.add("\}")
- return
+ return true
end
+ return false
+ end
+
+ protected fun compile_default_new(ccinfo: ClassCompilationInfo, v: SeparateCompilerVisitor)
+ do
+ var mclass = ccinfo.mclass
+ var mtype = ccinfo.mtype
+ var c_name = ccinfo.mclass.c_name
+ var is_dead = ccinfo.is_dead
#Build NEW
self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(const struct type* type);")
v.add("return {res};")
end
v.add("\}")
+
+ end
+
+ protected fun build_class_compilation_info(mclass: MClass): ClassCompilationInfo
+ do
+ var mtype = mclass.intro.bound_mtype
+ var rta = runtime_type_analysis
+ var is_dead = rta != null and not rta.live_classes.has(mclass)
+
+ # While the class may be dead, some part of separately compiled code may use symbols associated to the class, so
+ # in order to compile and link correctly the C code, these symbols should be declared and defined.
+ var need_corpse = is_dead and mtype.is_c_primitive or mclass.kind == extern_kind or mclass.kind == enum_kind
+
+ var compilation_info = new ClassCompilationInfo(mclass, is_dead, need_corpse)
+ return compilation_info
+ end
+
+ # Globally compile the table of the class mclass
+ # In a link-time optimisation compiler, tables are globally computed
+ # In a true separate compiler (a with dynamic loading) you cannot do this unfortnally
+ fun compile_class_to_c(mclass: MClass)
+ do
+ var v = new_visitor
+ var class_info = build_class_compilation_info(mclass)
+ compile_class_vft(class_info, v)
+ var is_already_managed = compile_class_if_universal(class_info, v)
+ if not is_already_managed then
+ compile_default_new(class_info, v)
+ end
end
# Compile structures used to map tagged primitive values to their classes and types.
self.add("{recv}[{i}]={val};")
end
- redef fun routine_ref_instance(routine_type, recv, mmethoddef)
- do
- #debug "ENTER ref_instance"
- var mmethod = mmethoddef.mproperty
- # routine_mclass is the specialized one, e.g: FunRef1, ProcRef2, etc..
- var routine_mclass = routine_type.mclass
-
- var nclasses = mmodule.model.get_mclasses_by_name("RoutineRef").as(not null)
- var base_routine_mclass = nclasses.first
-
- # All routine classes use the same `NEW` constructor.
- # However, they have different declared `class` and `type` value.
- self.require_declaration("NEW_{base_routine_mclass.c_name}")
-
- var recv_class_cname = recv.mcasttype.as(MClassType).mclass.c_name
- var my_recv = recv
-
- if recv.mtype.is_c_primitive then
- my_recv = autobox(recv, mmodule.object_type)
- end
- var my_recv_mclass_type = my_recv.mtype.as(MClassType)
-
- # The class of the concrete Routine must exist (e.g ProcRef0, FunRef0, etc.)
- self.require_declaration("class_{routine_mclass.c_name}")
- self.require_declaration("type_{routine_type.c_name}")
-
- compiler.undead_types.add(routine_type)
- self.require_declaration(mmethoddef.c_name)
-
- var thunk_function = mmethoddef.callref_thunk(my_recv_mclass_type)
- # If the receiver is exact, then there's no need to make a
- # polymorph call to the underlying method.
- thunk_function.polymorph_call_flag = not my_recv.is_exact
- var runtime_function = mmethoddef.virtual_runtime_function
-
- var is_c_equiv = runtime_function.msignature.c_equiv(thunk_function.msignature)
-
- var c_ref = thunk_function.c_ref
- if is_c_equiv then
- var const_color = mmethoddef.mproperty.const_color
- c_ref = "{class_info(my_recv)}->vft[{const_color}]"
- self.require_declaration(const_color)
- else
- self.require_declaration(thunk_function.c_name)
- compiler.thunk_todo(thunk_function)
- end
-
- # Each RoutineRef points to a receiver AND a callref_thunk
- var res = self.new_expr("NEW_{base_routine_mclass.c_name}({my_recv}, (nitmethod_t){c_ref}, &class_{routine_mclass.c_name}, &type_{routine_type.c_name})", routine_type)
- #debug "LEAVING ref_instance"
- return res
- end
-
- redef fun routine_ref_call(mmethoddef, arguments)
- do
- #debug "ENTER ref_call"
- compiler.modelbuilder.nb_invok_by_tables += 1
- if compiler.modelbuilder.toolcontext.opt_invocation_metrics.value then add("count_invoke_by_tables++;")
- var nclasses = mmodule.model.get_mclasses_by_name("RoutineRef").as(not null)
- var nclass = nclasses.first
- var runtime_function = mmethoddef.virtual_runtime_function
-
- # Save the current receiver since adapt_signature will autobox
- # the routine receiver which is not the underlying receiver.
- # The underlying receiver has already been adapted in the
- # `routine_ref_instance` method. Here we just want to adapt the
- # rest of the signature, but it's easier to pass the wrong
- # receiver in adapt_signature then discards it with `shift`.
- #
- # ~~~~nitish
- # class A; def toto do print "toto"; end
- # var a = new A
- # var f = &a.toto <- `a` is the underlying receiver
- # f.call <- here `f` is the routine receiver
- # ~~~~
- var routine = arguments.first
-
- # Retrieve the concrete routine type
- var original_recv_c = "(((struct instance_{nclass.c_name}*){arguments[0]})->recv)"
- var nitmethod = "(({runtime_function.c_funptrtype})(((struct instance_{nclass.c_name}*){arguments[0]})->method))"
- if arguments.length > 1 then
- adapt_signature(mmethoddef, arguments)
- end
-
- var ret_mtype = runtime_function.called_signature.return_mtype
-
- if ret_mtype != null then
- # `ret` is actually always nullable Object. When invoking
- # a callref, we don't have the original callsite information.
- # Thus, we need to recompute the return type of the callsite.
- ret_mtype = resolve_for(ret_mtype, routine)
- end
-
- # remove the routine's receiver
- arguments.shift
- var ss = arguments.join(", ")
- # replace the receiver with the original one
- if arguments.length > 0 then
- ss = "{original_recv_c}, {ss}"
- else
- ss = original_recv_c
- end
-
- arguments.unshift routine # put back the routine ref receiver
- add "/* {mmethoddef.mproperty} on {arguments.first.inspect}*/"
- var callsite = "{nitmethod}({ss})"
- if ret_mtype != null then
- var subres = new_expr("{callsite}", ret_mtype)
- ret(subres)
- else
- add("{callsite};")
- end
- end
+ redef fun routine_ref_instance(routine_type, recv, callsite)
+ do
+ #debug "ENTER ref_instance"
+ var mmethoddef = callsite.mpropdef
+ var mmethod = mmethoddef.mproperty
+ # routine_mclass is the specialized one, e.g: FunRef1, ProcRef2, etc..
+ var routine_mclass = routine_type.mclass
+
+ var nclasses = mmodule.model.get_mclasses_by_name("RoutineRef").as(not null)
+ var base_routine_mclass = nclasses.first
+
+ # All routine classes use the same `NEW` constructor.
+ # However, they have different declared `class` and `type` value.
+ self.require_declaration("NEW_{base_routine_mclass.c_name}")
+
+ var recv_class_cname = recv.mcasttype.as(MClassType).mclass.c_name
+ var my_recv = recv
+
+ if recv.mtype.is_c_primitive then
+ my_recv = autobox(recv, mmodule.object_type)
+ end
+ var my_recv_mclass_type = my_recv.mtype.as(MClassType)
+
+ # The class of the concrete Routine must exist (e.g ProcRef0, FunRef0, etc.)
+ self.require_declaration("class_{routine_mclass.c_name}")
+ self.require_declaration(mmethoddef.c_name)
+
+ var thunk_function = mmethoddef.callref_thunk(my_recv_mclass_type)
+ # If the receiver is exact, then there's no need to make a
+ # polymorph call to the underlying method.
+ thunk_function.polymorph_call_flag = not my_recv.is_exact
+ var runtime_function = mmethoddef.virtual_runtime_function
+
+ var is_c_equiv = runtime_function.msignature.c_equiv(thunk_function.msignature)
+
+ var c_ref = thunk_function.c_ref
+ if is_c_equiv then
+ var const_color = mmethoddef.mproperty.const_color
+ c_ref = "{class_info(my_recv)}->vft[{const_color}]"
+ self.require_declaration(const_color)
+ else
+ self.require_declaration(thunk_function.c_name)
+ compiler.thunk_todo(thunk_function)
+ end
+ var res: RuntimeVariable
+ if routine_type.need_anchor then
+ hardening_live_open_type(routine_type)
+ link_unresolved_type(self.frame.mpropdef.mclassdef, routine_type)
+ var recv2 = self.frame.arguments.first
+ var recv2_type_info = self.type_info(recv2)
+ self.require_declaration(routine_type.const_color)
+ res = self.new_expr("NEW_{base_routine_mclass.c_name}({my_recv}, (nitmethod_t){c_ref}, &class_{routine_mclass.c_name}, {recv2_type_info}->resolution_table->types[{routine_type.const_color}])", routine_type)
+ else
+ self.require_declaration("type_{routine_type.c_name}")
+ compiler.undead_types.add(routine_type)
+ res = self.new_expr("NEW_{base_routine_mclass.c_name}({my_recv}, (nitmethod_t){c_ref}, &class_{routine_mclass.c_name}, &type_{routine_type.c_name})", routine_type)
+ end
+ return res
+ end
+
+ redef fun routine_ref_call(mmethoddef, arguments)
+ do
+ #debug "ENTER ref_call"
+ compiler.modelbuilder.nb_invok_by_tables += 1
+ if compiler.modelbuilder.toolcontext.opt_invocation_metrics.value then add("count_invoke_by_tables++;")
+ var nclasses = mmodule.model.get_mclasses_by_name("RoutineRef").as(not null)
+ var nclass = nclasses.first
+ var runtime_function = mmethoddef.virtual_runtime_function
+
+ # Save the current receiver since adapt_signature will autobox
+ # the routine receiver which is not the underlying receiver.
+ # The underlying receiver has already been adapted in the
+ # `routine_ref_instance` method. Here we just want to adapt the
+ # rest of the signature, but it's easier to pass the wrong
+ # receiver in adapt_signature then discards it with `shift`.
+ #
+ # ~~~~nitish
+ # class A; def toto do print "toto"; end
+ # var a = new A
+ # var f = &a.toto # `a` is the underlying receiver
+ # f.call # here `f` is the routine receiver
+ # ~~~~
+ var routine = arguments.first
+
+ # Retrieve the concrete routine type
+ var original_recv_c = "(((struct instance_{nclass.c_name}*){arguments[0]})->recv)"
+ var nitmethod = "(({runtime_function.c_funptrtype})(((struct instance_{nclass.c_name}*){arguments[0]})->method))"
+ if arguments.length > 1 then
+ adapt_signature(mmethoddef, arguments)
+ end
+
+ var ret_mtype = runtime_function.called_signature.return_mtype
+
+ if ret_mtype != null then
+ # `ret` is actually always nullable Object. When invoking
+ # a callref, we don't have the original callsite information.
+ # Thus, we need to recompute the return type of the callsite.
+ ret_mtype = resolve_for(ret_mtype, routine)
+ end
+
+ # remove the routine's receiver
+ arguments.shift
+ var ss = arguments.join(", ")
+ # replace the receiver with the original one
+ if arguments.length > 0 then
+ ss = "{original_recv_c}, {ss}"
+ else
+ ss = original_recv_c
+ end
+
+ arguments.unshift routine # put back the routine ref receiver
+ add "/* {mmethoddef.mproperty} on {arguments.first.inspect}*/"
+ var callsite = "{nitmethod}({ss})"
+ if ret_mtype != null then
+ var subres = new_expr("{callsite}", ret_mtype)
+ ret(subres)
+ else
+ add("{callsite};")
+ end
+ end
fun link_unresolved_type(mclassdef: MClassDef, mtype: MType) do
assert mtype.need_anchor
return res
end
- # Returns true if the current method definition differ from
- # its original introduction in terms of receiver type.
- fun recv_differ_from_intro: Bool
- do
- var intromclassdef = mproperty.intro.mclassdef
- var introrecv = intromclassdef.bound_mtype
- return self.mclassdef.bound_mtype != introrecv
- end
-
- # The C thunk function associated to a mmethoddef. Receives only nullable
- # Object and cast them to the original mmethoddef signature.
- fun callref_thunk(recv_mtype: MClassType): SeparateThunkFunction
- do
- var res = callref_thunk_cache
- if res == null then
- #var runtime_function = virtual_runtime_function
- var object_type = mclassdef.mmodule.object_type
- var nullable_object = object_type.as_nullable
- var msignature2 = msignature.change_all_mtype_for(nullable_object)
- var intromclassdef = mproperty.intro.mclassdef
-
- #var introrecv = intromclassdef.bound_mtype
- ## If the thunk signature is equivalent to its
- ## virtual counterpart, then nothing to do.
- #print "recv vs intro : {recv_mtype} vs {introrecv}"
- #if msignature2.c_equiv(runtime_function.called_signature) and recv_mtype == introrecv then
- # callref_thunk_cache = res
- # return runtime_function
- #end
- # receiver cannot be null
- res = new SeparateThunkFunction(self, recv_mtype, msignature2, "THUNK_{c_name}", mclassdef.bound_mtype)
- res.polymorph_call_flag = true
- callref_thunk_cache = res
- end
- return res
- end
-
- private var callref_thunk_cache: nullable SeparateThunkFunction
+ # Returns true if the current method definition differ from
+ # its original introduction in terms of receiver type.
+ fun recv_differ_from_intro: Bool
+ do
+ var intromclassdef = mproperty.intro.mclassdef
+ var introrecv = intromclassdef.bound_mtype
+ return self.mclassdef.bound_mtype != introrecv
+ end
+
+ # The C thunk function associated to a mmethoddef. Receives only nullable
+ # Object and cast them to the original mmethoddef signature.
+ fun callref_thunk(recv_mtype: MClassType): SeparateThunkFunction
+ do
+ var res = callref_thunk_cache
+ if res == null then
+ var object_type = mclassdef.mmodule.object_type
+ var nullable_object = object_type.as_nullable
+ var ps = new Array[MParameter]
+
+ # Replace every argument type by nullable object
+ for p in msignature.mparameters do
+ ps.push(new MParameter(p.name, nullable_object, p.is_vararg))
+ end
+ var ret: nullable MType = null
+ if msignature.return_mtype != null then ret = nullable_object
+ var msignature2 = new MSignature(ps, ret)
+ var intromclassdef = mproperty.intro.mclassdef
+
+ res = new SeparateThunkFunction(self, recv_mtype, msignature2, "THUNK_{c_name}", mclassdef.bound_mtype)
+ res.polymorph_call_flag = true
+ callref_thunk_cache = res
+ end
+ return res
+ end
+
+ private var callref_thunk_cache: nullable SeparateThunkFunction
private var separate_runtime_function_cache: nullable SeparateRuntimeFunction
# The C function associated to a mmethoddef, that can be stored into a VFT of a class
self.virtual_runtime_function_cache = res
return res
end
- res = new SeparateThunkFunction(self, recv, msignature, "VIRTUAL_{c_name}", mclassdef.bound_mtype)
+ res = new SeparateThunkFunction(self, recv, msignature, "VIRTUAL_{c_name}", mclassdef.bound_mtype)
end
return res
end
redef fun to_s do return self.mmethoddef.to_s
- redef fun msignature
- do
- return called_signature
- end
+ redef fun msignature
+ do
+ return called_signature
+ end
- redef fun recv_mtype
- do
- return called_recv
- end
+ redef fun recv_mtype
+ do
+ return called_recv
+ end
- redef fun return_mtype
- do
- return called_signature.return_mtype
- end
+ redef fun return_mtype
+ do
+ return called_signature.return_mtype
+ end
# The C return type (something or `void`)
var c_ret: String is lazy do
# The C type for the function pointer.
var c_funptrtype: String is lazy do return "{c_ret}(*){c_sig}"
- redef fun declare_signature(v, sig)
- do
- v.compiler.provide_declaration(c_name, "{sig};")
- end
+ redef fun declare_signature(v, sig)
+ do
+ v.compiler.provide_declaration(c_name, "{sig};")
+ end
- redef fun body_to_c(v)
- do
- var rta = v.compiler.as(SeparateCompiler).runtime_type_analysis
- if rta != null and not rta.live_mmodules.has(mmethoddef.mclassdef.mmodule) then
+ redef fun body_to_c(v)
+ do
+ var rta = v.compiler.as(SeparateCompiler).runtime_type_analysis
+ if rta != null and not rta.live_mmodules.has(mmethoddef.mclassdef.mmodule) then
v.add_abort("FATAL: Dead method executed.")
- else
- super
- end
- end
-
- redef fun end_compile_to_c(v)
- do
- var compiler = v.compiler
- compiler.names[self.c_name] = "{mmethoddef.full_name} ({mmethoddef.location.file.filename}:{mmethoddef.location.line_start})"
- end
-
- redef fun build_frame(v, arguments)
- do
- var recv = mmethoddef.mclassdef.bound_mtype
- return new StaticFrame(v, mmethoddef, recv, arguments)
- end
+ else
+ super
+ end
+ end
+
+ redef fun end_compile_to_c(v)
+ do
+ var compiler = v.compiler
+ compiler.names[self.c_name] = "{mmethoddef.full_name} ({mmethoddef.location.file.filename}:{mmethoddef.location.line_start})"
+ end
+
+ redef fun build_frame(v, arguments)
+ do
+ var recv = mmethoddef.mclassdef.bound_mtype
+ return new StaticFrame(v, mmethoddef, recv, arguments)
+ end
# Compile the trampolines used to implement late-binding.
#
end
end
+# Encapsulates every information needed to compile a class.
+#
+# The compilation of a class is done by several methods, two of those are
+# mandatory :
+# - compile_class_to_c : starts the compilation process
+# - compile_class_vft : generate the virtual function table
+# And one of them is optional :
+# - compile_class_if_universal : compiles the rest of the class if its a universal
+# type. Universal type are handle in a case-basis, this is why they need special treatment.
+# Generally, universal class will have special structure and a custom allocator.
+#
+# Throughout each step of the class compilation process, some information must be share.
+# This class encapsulates the compilation process state.
+# (except vft), eg
+class ClassCompilationInfo
+ var mclass: MClass # class to compile
+ var is_dead: Bool
+ var need_corpse: Bool
+
+ # Shortcut to access the class's bound type.
+ var mtype: MClassType is noinit
+
+ init
+ do
+ mtype = mclass.intro.bound_mtype
+ end
+end
+
class SeparateThunkFunction
- super ThunkFunction
- super SeparateRuntimeFunction
- redef var target_recv
+ super ThunkFunction
+ super SeparateRuntimeFunction
+ redef var target_recv
end
redef class MType