self.toolcontext.info("*** GENERATING C ***", 1)
var compiler = new GlobalCompiler(mainmodule, self, runtime_type_analysis)
- compiler.compile_header
-
- for t in runtime_type_analysis.live_types do
- compiler.declare_runtimeclass(t)
- end
-
- compiler.compile_class_names
-
- # Init instance code (allocate and init-arguments)
- for t in runtime_type_analysis.live_types do
- if t.ctype == "val*" then
- compiler.generate_init_instance(t)
- else
- compiler.generate_box_instance(t)
- end
- end
-
- # The main function of the C
- compiler.compile_nitni_global_ref_functions
- compiler.compile_main_function
-
- # Compile until all runtime_functions are visited
- while not compiler.todos.is_empty do
- var m = compiler.todos.shift
- self.toolcontext.info("Compile {m} ({compiler.seen.length-compiler.todos.length}/{compiler.seen.length})", 3)
- m.compile_to_c(compiler)
- end
- self.toolcontext.info("Total methods to compile to C: {compiler.seen.length}", 2)
-
+ compiler.do_compilation
compiler.display_stats
var time1 = get_time
# The result of the RTA (used to know live types and methods)
var runtime_type_analysis: RapidTypeAnalysis
- init(mainmodule: MModule, modelbuilder: ModelBuilder, runtime_type_analysis: RapidTypeAnalysis)
+ init
do
- super(mainmodule, modelbuilder)
- var file = new_file("{mainmodule.name}.nitgg")
+ var file = new_file("{mainmodule.c_name}.nitgg")
self.header = new CodeWriter(file)
- self.runtime_type_analysis = runtime_type_analysis
self.live_primitive_types = new Array[MClassType]
for t in runtime_type_analysis.live_types do
- if t.ctype != "val*" then
+ if t.ctype != "val*" or t.mclass.name == "Pointer" then
self.live_primitive_types.add(t)
end
end
end
+ redef fun do_compilation
+ do
+ var compiler = self
+
+ compiler.compile_header
+
+ if mainmodule.model.get_mclasses_by_name("Pointer") != null then
+ runtime_type_analysis.live_types.add(mainmodule.pointer_type)
+ end
+ for t in runtime_type_analysis.live_types do
+ compiler.declare_runtimeclass(t)
+ end
+
+ compiler.compile_class_names
+
+ # Init instance code (allocate and init-arguments)
+ for t in runtime_type_analysis.live_types do
+ if t.ctype == "val*" then
+ compiler.generate_init_instance(t)
+ if t.mclass.kind == extern_kind then
+ compiler.generate_box_instance(t)
+ end
+ else
+ compiler.generate_box_instance(t)
+ end
+ end
+
+ # The main function of the C
+ compiler.compile_nitni_global_ref_functions
+ compiler.compile_main_function
+
+ # Compile until all runtime_functions are visited
+ while not compiler.todos.is_empty do
+ var m = compiler.todos.shift
+ modelbuilder.toolcontext.info("Compile {m} ({compiler.seen.length-compiler.todos.length}/{compiler.seen.length})", 3)
+ m.compile_to_c(compiler)
+ end
+ modelbuilder.toolcontext.info("Total methods to compile to C: {compiler.seen.length}", 2)
+
+ end
+
# Compile class names (for the class_name and output_class_name methods)
protected fun compile_class_names do
var v = new_visitor
# Subset of runtime_type_analysis.live_types that contains only primitive types
# Used to implement the equal test
- var live_primitive_types: Array[MClassType]
+ var live_primitive_types: Array[MClassType] is noinit
# Add a new todo task
fun todo(m: AbstractRuntimeFunction)
v.add_decl("{mtype.arguments.first.ctype} values[1];")
end
- if mtype.ctype != "val*" then
+ if mtype.ctype_extern != "val*" then
# Is the Nit type is native then the struct is a box with two fields:
# * the `classid` to be polymorph
# * the `value` that contains the native value.
- v.add_decl("{mtype.ctype} value;")
+ v.add_decl("{mtype.ctype_extern} value;")
end
# Collect all attributes and associate them a field in the structure.
fun generate_box_instance(mtype: MClassType)
do
assert self.runtime_type_analysis.live_types.has(mtype)
- assert mtype.ctype != "val*"
var v = self.new_visitor
self.header.add_decl("val* BOX_{mtype.c_name}({mtype.ctype});")
var res = self.new_var(mtype)
if not compiler.runtime_type_analysis.live_types.has(valtype) then
self.add("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */")
- self.add("PRINT_ERROR(\"Dead code executed!\\n\"); show_backtrace(1);")
+ self.add("PRINT_ERROR(\"Dead code executed!\\n\"); fatal_exit(1);")
return res
end
self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
# Bad things will appen!
var res = self.new_var(mtype)
self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */")
- self.add("PRINT_ERROR(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); show_backtrace(1);")
+ self.add("PRINT_ERROR(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); fatal_exit(1);")
+ return res
+ end
+ end
+
+ redef fun unbox_extern(value, mtype)
+ do
+ if mtype isa MClassType and mtype.mclass.kind == extern_kind and
+ mtype.mclass.name != "NativeString" then
+ var res = self.new_var_extern(mtype)
+ self.add "{res} = ((struct {mtype.c_name}*){value})->value; /* unboxing {value.mtype} */"
+ return res
+ else
+ return value
+ end
+ end
+
+ redef fun box_extern(value, mtype)
+ do
+ if not mtype isa MClassType or mtype.mclass.kind != extern_kind or
+ mtype.mclass.name == "NativeString" then return value
+
+ var valtype = value.mtype.as(MClassType)
+ var res = self.new_var(mtype)
+ if not compiler.runtime_type_analysis.live_types.has(value.mtype.as(MClassType)) then
+ self.add("/*no boxing of {value.mtype}: {value.mtype} is not live! */")
+ self.add("PRINT_ERROR(\"Dead code executed!\\n\"); fatal_exit(1);")
return res
end
+ self.add("{res} = BOX_{valtype.c_name}({value}); /* boxing {value.mtype} */")
+ return res
end
# The runtime types that are acceptable for a given receiver.
redef fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable
do
var ret_type = self.get_class("NativeArray").get_mtype([elttype])
+ ret_type = anchor(ret_type).as(MClassType)
return self.new_expr("NEW_{ret_type.c_name}({length})", ret_type)
end
var res: nullable RuntimeVariable
var ret = m.intro.msignature.return_mtype
- if m.is_new then
- ret = args.first.mtype
- res = self.new_var(ret)
- else if ret == null then
+ if ret == null then
res = null
else
ret = self.resolve_for(ret, args.first)
if args.first.mcasttype isa MNullableType or args.first.mcasttype isa MNullType and consider_null then
# The reciever is potentially null, so we have to 3 cases: ==, != or NullPointerException
self.add("if ({args.first} == NULL) \{ /* Special null case */")
- if m.name == "==" then
+ if m.name == "==" or m.name == "is_same_instance" then
assert res != null
if args[1].mcasttype isa MNullableType then
self.add("{res} = ({args[1]} == NULL);")
return recvtype
end
- # Subpart of old call function
- # Gets the receiver boxed and casted if necessary
- private fun get_recv(recvtype: MClassType, args: Array[RuntimeVariable]): RuntimeVariable
+ redef fun call(m, recvtype, args)
do
- return self.autoadapt(self.autobox(args.first, recvtype), recvtype)
- end
+ var recv_type = get_recvtype(m, recvtype, args)
+ var recv = self.autoadapt(self.autobox(args.first, recvtype), recvtype)
+ if m.is_extern then recv = unbox_extern(recv, recv_type)
+
+ args = args.to_a
+ args.first = recv
- # Finalizes a call to a method ´m´ on type ´recvtype´ with arguments ´args´
- private fun finalize_call(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable
- do
assert args.length == m.msignature.arity + 1 else debug("Invalid arity for {m}. {args.length} arguments given.")
var rm = new CustomizedRuntimeFunction(m, recvtype)
return rm.call(self, args)
end
- redef fun call(m, recvtype, args)
- do
- var recv_type = get_recvtype(m, recvtype, args)
- var recv = get_recv(recv_type, args)
- var new_args = args.to_a
- self.varargize(m, m.msignature.as(not null), new_args)
- new_args.first = recv
- return finalize_call(m, recv_type, new_args)
- end
-
- # Does a call without encapsulating varargs into an array
- # Avoids multiple encapsulation when calling a super in a variadic function
- fun call_without_varargize(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable
- do
- var recv_type = get_recvtype(m, recvtype, args)
- var recv = get_recv(recv_type, args)
- var new_args = args.to_a
- new_args.first = recv
- return finalize_call(m, recv_type, new_args)
- end
-
redef fun supercall(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable
do
var types = self.collect_types(args.first)
return res
end
var propdef = m.lookup_next_definition(self.compiler.mainmodule, mclasstype)
- var res2 = self.call_without_varargize(propdef, mclasstype, args)
+ var res2 = self.call(propdef, mclasstype, args)
if res != null then self.assign(res, res2.as(not null))
return res
end
else
self.add("case {self.compiler.classid(t)}: /* test {t} */")
end
- var res2 = self.call_without_varargize(propdef, t, args)
+ var res2 = self.call(propdef, t, args)
if res != null then self.assign(res, res2.as(not null))
self.add "break;"
end
end
end
+ redef fun unbox_signature_extern(m, args)
+ do
+ var recv = args.first
+ for i in [0..m.msignature.arity[ do
+ var t = m.msignature.mparameters[i].mtype
+ if i == m.msignature.vararg_rank then
+ t = args[i+1].mtype
+ end
+ t = self.resolve_for(t, recv)
+ if m.is_extern then args[i+1] = self.unbox_extern(args[i+1], t)
+ end
+ end
+
# FIXME: this is currently buggy since recv is not exact
redef fun vararg_instance(mpropdef, recv, varargs, elttype)
do
do
if recv.mtype.ctype != "val*" then return
self.add("PRINT_ERROR(\"BTD BUG: Dynamic type is %s, static type is %s\\n\", class_names[{recv}->classid], \"{recv.mcasttype}\");")
- self.add("show_backtrace(1);")
+ self.add("fatal_exit(1);")
end
redef fun isset_attribute(a, recv)
if not t.is_subtype(self.compiler.mainmodule, null, value2.mcasttype) then continue
s.add "({value1}->classid == {self.compiler.classid(t)} && ((struct {t.c_name}*){value1})->value == ((struct {t.c_name}*){value2})->value)"
end
+
+ if self.compiler.mainmodule.model.get_mclasses_by_name("Pointer") != null then
+ var pointer_type = self.compiler.mainmodule.pointer_type
+ if value1.mcasttype.is_subtype(self.compiler.mainmodule, null, pointer_type) or
+ value2.mcasttype.is_subtype(self.compiler.mainmodule, null, pointer_type) then
+ s.add "(((struct {pointer_type.c_name}*){value1})->value == ((struct {pointer_type.c_name}*){value2})->value)"
+ end
+ end
+
if s.is_empty then
self.add("{res} = {value1} == {value2};")
else
# (usually is a live type but no strong guarantee)
var recv: MClassType
- init(mmethoddef: MMethodDef, recv: MClassType)
- do
- super(mmethoddef)
- self.recv = recv
- end
-
redef fun build_c_name
do
var res = self.c_name_cache
selfvar.is_exact = true
end
var arguments = new Array[RuntimeVariable]
- var frame = new Frame(v, mmethoddef, recv, arguments)
+ var frame = new StaticFrame(v, mmethoddef, recv, arguments)
v.frame = frame
var sig = new FlatBuffer
if ret != null then
ret = v.resolve_for(ret, selfvar)
sig.append("{ret.ctype} ")
- else if mmethoddef.mproperty.is_new then
- ret = recv
- sig.append("{ret.ctype} ")
else
sig.append("void ")
end
redef fun call(v: VISITOR, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
do
var ret = self.mmethoddef.msignature.return_mtype
- if self.mmethoddef.mproperty.is_new then
- ret = recv
- end
if ret != null then
ret = v.resolve_for(ret, arguments.first)
end
if self.mmethoddef.can_inline(v) then
- var frame = new Frame(v, self.mmethoddef, self.recv, arguments)
+ var frame = new StaticFrame(v, self.mmethoddef, self.recv, arguments)
frame.returnlabel = v.get_name("RET_LABEL")
if ret != null then
frame.returnvar = v.new_var(ret)