compiler: do not call C `nit_alloc` directly but a Nit method.
[nit.git] / src / compiler / abstract_compiler.nit
index 14ae7d4..e9eacef 100644 (file)
@@ -577,7 +577,7 @@ abstract class AbstractCompiler
 
        # 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
@@ -651,6 +651,8 @@ abstract class AbstractCompiler
                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")
@@ -679,6 +681,7 @@ abstract class AbstractCompiler
 
                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
@@ -707,6 +710,17 @@ abstract class AbstractCompiler
                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
 
@@ -790,6 +804,7 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref );
                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
@@ -878,6 +893,7 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref );
                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();"
@@ -1111,8 +1127,8 @@ end
 # 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)
@@ -1192,8 +1208,6 @@ abstract class AbstractCompilerVisitor
 
        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.
@@ -1204,6 +1218,16 @@ abstract class AbstractCompilerVisitor
        # 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.
@@ -1636,9 +1660,9 @@ abstract class AbstractCompilerVisitor
                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
@@ -1731,6 +1755,9 @@ abstract class AbstractCompilerVisitor
        # 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
@@ -2532,7 +2559,8 @@ redef class AMethPropdef
                                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)))
@@ -2985,12 +3013,6 @@ redef class AMethPropdef
                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
@@ -3143,7 +3165,7 @@ redef class AAttrPropdef
 
        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
@@ -3371,8 +3393,19 @@ end
 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
 
@@ -3915,12 +3948,36 @@ redef class ANewExpr
                        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