# The list of all associated files
# Used to generate .c files
- var files = new List[CodeFile]
+ var files = new Array[CodeFile]
# Initialize a visitor specific for a compiler engine
fun new_visitor: VISITOR is abstract
self.header.add_decl("#include <stdlib.h>")
self.header.add_decl("#include <stdio.h>")
self.header.add_decl("#include <string.h>")
+ # longjmp !
+ self.header.add_decl("#include <setjmp.h>\n")
self.header.add_decl("#include <sys/types.h>\n")
self.header.add_decl("#include <unistd.h>\n")
self.header.add_decl("#include <stdint.h>\n")
compile_header_structs
compile_nitni_structs
+ compile_catch_stack
var gccd_disable = modelbuilder.toolcontext.opt_no_gcc_directive.value
if gccd_disable.has("noreturn") or gccd_disable.has("all") then
self.header.add_decl("extern val *glob_sys;")
end
+ # Stack stocking environment for longjumps
+ protected fun compile_catch_stack do
+ self.header.add_decl """
+struct catch_stack_t {
+ int cursor;
+ jmp_buf envs[100];
+};
+extern struct catch_stack_t catchStack;
+"""
+ end
+
# Declaration of structures for live Nit types
protected fun compile_header_structs is abstract
v.add "\}"
end
+ # Hook to add specif piece of code before the the main C function.
+ #
+ # Is called by `compile_main_function`
+ fun compile_before_main(v: VISITOR)
+ do
+ end
+
+ # Hook to add specif piece of code at the begin on the main C function.
+ #
+ # Is called by `compile_main_function`
+ fun compile_begin_main(v: VISITOR)
+ do
+ end
+
# Generate the main C function.
#
# This function:
v.add_decl("int glob_argc;")
v.add_decl("char **glob_argv;")
v.add_decl("val *glob_sys;")
+ v.add_decl("struct catch_stack_t catchStack;")
if self.modelbuilder.toolcontext.opt_typing_test_metrics.value then
for tag in count_type_test_tags do
v.add_decl("exit(status);")
v.add_decl("\}")
+ compile_before_main(v)
+
if no_main then
v.add_decl("int nit_main(int argc, char** argv) \{")
else
v.add_decl("int main(int argc, char** argv) \{")
end
+ compile_begin_main(v)
+
v.add "#if !defined(__ANDROID__) && !defined(TARGET_OS_IPHONE)"
v.add("signal(SIGABRT, sig_handler);")
v.add("signal(SIGFPE, sig_handler);")
v.add("signal(SIGPIPE, SIG_IGN);")
v.add("glob_argc = argc; glob_argv = argv;")
+ v.add("catchStack.cursor = -1;")
v.add("initialize_gc_option();")
v.add "initialize_nitni_global_refs();"
# Where to store generated lines
class CodeWriter
var file: CodeFile
- var lines: List[String] = new List[String]
- var decl_lines: List[String] = new List[String]
+ var lines = new Array[String]
+ var decl_lines = new Array[String]
# Add a line in the main part of the generated C
fun add(s: String) do self.lines.add(s)
fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable is abstract
- fun calloc_array(ret_type: MType, arguments: Array[RuntimeVariable]) is abstract
-
fun native_array_def(pname: String, ret_type: nullable MType, arguments: Array[RuntimeVariable]): Bool do return false
# Return an element of a native array.
# The method is unsafe and is just a direct wrapper for the specific implementation of native arrays
fun native_array_set(native_array: RuntimeVariable, index: Int, value: RuntimeVariable) is abstract
+ # Allocate `size` bytes with the low_level `nit_alloc` C function
+ #
+ # This method can be redefined to inject statistic or tracing code.
+ #
+ # `tag` if any, is used to mark the class of the allocated object.
+ fun nit_alloc(size: String, tag: nullable String): String
+ do
+ return "nit_alloc({size})"
+ end
+
# Evaluate `args` as expressions in the call of `mpropdef` on `recv`.
# This method is used to manage varargs in signatures and returns the real array
# of runtime variables to use in the call.
var native_mtype = mmodule.native_string_type
var nat = self.new_var(native_mtype)
self.add("{nat} = \"{string.escape_to_c}\";")
- var bytelen = self.int_instance(string.bytelen)
+ var byte_length = self.int_instance(string.byte_length)
var unilen = self.int_instance(string.length)
- self.add("{res} = {self.send(self.get_property("to_s_full", native_mtype), [nat, bytelen, unilen]).as(not null)};")
+ self.add("{res} = {self.send(self.get_property("to_s_full", native_mtype), [nat, byte_length, unilen]).as(not null)};")
self.add("{name} = {res};")
self.add("\}")
return res
# used by aborts, asserts, casts, etc.
fun add_abort(message: String)
do
+ self.add("if(catchStack.cursor >= 0)\{")
+ self.add("longjmp(catchStack.envs[catchStack.cursor], 1);")
+ self.add("\}")
self.add("PRINT_ERROR(\"Runtime error: %s\", \"{message.escape_to_c}\");")
add_raw_abort
end
v.ret(v.new_expr("!{res}", ret.as(not null)))
return true
else if pname == "new" then
- v.ret(v.new_expr("(char*)nit_alloc({arguments[1]})", ret.as(not null)))
+ var alloc = v.nit_alloc(arguments[1].to_s, "NativeString")
+ v.ret(v.new_expr("(char*){alloc}", ret.as(not null)))
return true
else if pname == "fetch_4_chars" then
v.ret(v.new_expr("(long)*((uint32_t*)({arguments[0]} + {arguments[1]}))", ret.as(not null)))
else if pname == "sys" then
v.ret(v.new_expr("glob_sys", ret.as(not null)))
return true
- else if pname == "calloc_string" then
- v.ret(v.new_expr("(char*)nit_alloc({arguments[1]})", ret.as(not null)))
- return true
- else if pname == "calloc_array" then
- v.calloc_array(ret.as(not null), arguments)
- return true
else if pname == "object_id" then
v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
return true
fun init_expr(v: AbstractCompilerVisitor, recv: RuntimeVariable)
do
- if has_value and not is_lazy and not n_expr isa ANullExpr then evaluate_expr(v, recv)
+ if has_value and not is_lazy and not is_optional and not n_expr isa ANullExpr then evaluate_expr(v, recv)
end
# Evaluate, store and return the default value of the attribute
redef class ADoExpr
redef fun stmt(v)
do
- v.stmt(self.n_block)
- v.add_escape_label(break_mark)
+ if self.n_catch != null then
+ v.add("catchStack.cursor += 1;")
+ v.add("if(!setjmp(catchStack.envs[catchStack.cursor]))\{")
+ v.stmt(self.n_block)
+ v.add("catchStack.cursor -= 1;")
+ v.add("\}else \{")
+ v.add("catchStack.cursor -= 1;")
+ v.stmt(self.n_catch)
+ v.add("\}")
+ else
+ v.stmt(self.n_block)
+ end
+ v.add_escape_label(break_mark)
end
end
return v.native_array_instance(elttype, l)
end
- var recv = v.init_instance_or_extern(mtype)
-
var callsite = self.callsite
- if callsite == null then return recv
+ if callsite == null then return v.init_instance_or_extern(mtype)
if callsite.is_broken then return null
+ var recv
+ # new factories are badly implemented.
+ # They assume a stub temporary receiver exists.
+ # This temporary receiver is required because it
+ # currently holds the method and the formal types.
+ #
+ # However, this object could be reused if the formal types are the same.
+ # Therefore, the following code will `once` it in these case
+ if callsite.mproperty.is_new and not mtype.need_anchor then
+ var name = v.get_name("varoncenew")
+ var guard = v.get_name(name + "_guard")
+ v.add_decl("static {mtype.ctype} {name};")
+ v.add_decl("static int {guard};")
+ recv = v.new_var(mtype)
+ v.add("if (likely({guard})) \{")
+ v.add("{recv} = {name};")
+ v.add("\} else \{")
+ var i = v.init_instance_or_extern(mtype)
+ v.add("{recv} = {i};")
+ v.add("{name} = {recv};")
+ v.add("{guard} = 1;")
+ v.add("\}")
+ else
+ recv = v.init_instance_or_extern(mtype)
+ end
+
var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.n_args.n_exprs)
var res2 = v.compile_callsite(callsite, args)
if res2 != null then