Merge: Portable stack-traces
[nit.git] / src / compiler / abstract_compiler.nit
index 894a13d..a095201 100644 (file)
@@ -63,8 +63,8 @@ redef class ToolContext
        var opt_invocation_metrics = new OptionBool("Enable static and dynamic count of all method invocations", "--invocation-metrics")
        # --isset-checks-metrics
        var opt_isset_checks_metrics = new OptionBool("Enable static and dynamic count of isset checks before attributes access", "--isset-checks-metrics")
-       # --stacktrace
-       var opt_stacktrace = new OptionString("Control the generation of stack traces", "--stacktrace")
+       # --no-stacktrace
+       var opt_no_stacktrace = new OptionBool("Disable the generation of stack traces", "--no-stacktrace")
        # --no-gcc-directives
        var opt_no_gcc_directive = new OptionArray("Disable a advanced gcc directives for optimization", "--no-gcc-directive")
        # --release
@@ -76,7 +76,7 @@ redef class ToolContext
                self.option_context.add_option(self.opt_output, self.opt_dir, self.opt_no_cc, self.opt_no_main, self.opt_make_flags, self.opt_compile_dir, self.opt_hardening)
                self.option_context.add_option(self.opt_no_check_covariance, self.opt_no_check_attr_isset, self.opt_no_check_assert, self.opt_no_check_autocast, self.opt_no_check_null, self.opt_no_check_all)
                self.option_context.add_option(self.opt_typing_test_metrics, self.opt_invocation_metrics, self.opt_isset_checks_metrics)
-               self.option_context.add_option(self.opt_stacktrace)
+               self.option_context.add_option(self.opt_no_stacktrace)
                self.option_context.add_option(self.opt_no_gcc_directive)
                self.option_context.add_option(self.opt_release)
                self.option_context.add_option(self.opt_max_c_lines, self.opt_group_c_files)
@@ -88,19 +88,8 @@ redef class ToolContext
        do
                super
 
-               var st = opt_stacktrace.value
-               if st == "none" or st == "libunwind" or st == "nitstack" then
-                       # Fine, do nothing
-               else if st == "auto" or st == null then
-                       # Default is nitstack
-                       opt_stacktrace.value = "nitstack"
-               else
-                       print "Error: unknown value `{st}` for --stacktrace. Use `none`, `libunwind`, `nitstack` or `auto`."
-                       exit(1)
-               end
-
                if opt_output.value != null and opt_dir.value != null then
-                       print "Error: cannot use both --dir and --output"
+                       print "Option Error: cannot use both --dir and --output"
                        exit(1)
                end
 
@@ -115,15 +104,12 @@ redef class ToolContext
 end
 
 redef class ModelBuilder
-       # The compilation directory
-       var compile_dir: String
-
        # Simple indirection to `Toolchain::write_and_make`
        protected fun write_and_make(compiler: AbstractCompiler)
        do
                var platform = compiler.target_platform
                var toolchain = platform.toolchain(toolcontext, compiler)
-               compile_dir = toolchain.compile_dir
+               compiler.toolchain = toolchain
                toolchain.write_and_make
        end
 end
@@ -145,14 +131,21 @@ class Toolchain
        # Compiler of the target program
        var compiler: AbstractCompiler
 
-       # Directory where to generate all C files
-       fun compile_dir: String
+       # Directory where to generate all files
+       #
+       # The option `--compile_dir` change this directory.
+       fun root_compile_dir: String
        do
                var compile_dir = toolcontext.opt_compile_dir.value
-               if compile_dir == null then compile_dir = ".nit_compile"
+               if compile_dir == null then compile_dir = "nit_compile"
                return compile_dir
        end
 
+       # Directory where to generate all C files
+       #
+       # By default it is `root_compile_dir` but some platform may require that it is a subdirectory.
+       fun compile_dir: String do return root_compile_dir
+
        # Write all C files and compile them
        fun write_and_make is abstract
 end
@@ -165,12 +158,16 @@ class MakefileToolchain
        do
                var compile_dir = compile_dir
 
+               # Remove the compilation directory unless explicitly set
+               var auto_remove = toolcontext.opt_compile_dir.value == null
+
                # Generate the .h and .c files
                # A single C file regroups many compiled rumtime functions
                # Note that we do not try to be clever an a small change in a Nit source file may change the content of all the generated .c files
                var time0 = get_time
                self.toolcontext.info("*** WRITING C ***", 1)
 
+               root_compile_dir.mkdir
                compile_dir.mkdir
 
                var cfiles = new Array[String]
@@ -192,6 +189,10 @@ class MakefileToolchain
 
                compile_c_code(compile_dir)
 
+               if auto_remove then
+                       sys.system("rm -r -- '{root_compile_dir.escape_to_sh}/'")
+               end
+
                time1 = get_time
                self.toolcontext.info("*** END COMPILING C: {time1-time0} ***", 2)
        end
@@ -200,7 +201,7 @@ class MakefileToolchain
        fun write_files(compile_dir: String, cfiles: Array[String])
        do
                var platform = compiler.target_platform
-               if self.toolcontext.opt_stacktrace.value == "nitstack" and platform.supports_libunwind then compiler.build_c_to_nit_bindings
+               if platform.supports_libunwind then compiler.build_c_to_nit_bindings
                var cc_opt_with_libgc = "-DWITH_LIBGC"
                if not platform.supports_libgc then cc_opt_with_libgc = ""
 
@@ -327,7 +328,7 @@ class MakefileToolchain
                var outpath = real_outpath.escape_to_mk
                if outpath != real_outpath then
                        # If the name is crazy and need escaping, we will do an indirection
-                       # 1. generate the binary in the .nit_compile dir under an escaped name
+                       # 1. generate the binary in the nit_compile dir under an escaped name
                        # 2. copy the binary at the right place in the `all` goal.
                        outpath = mainmodule.c_name
                end
@@ -343,25 +344,50 @@ class MakefileToolchain
 
                makefile.write("CC = ccache cc\nCXX = ccache c++\nCFLAGS = -g -O2 -Wno-unused-value -Wno-switch -Wno-attributes\nCINCL =\nLDFLAGS ?= \nLDLIBS  ?= -lm {linker_options.join(" ")}\n\n")
 
-               var ost = toolcontext.opt_stacktrace.value
-               if (ost == "libunwind" or ost == "nitstack") and platform.supports_libunwind then makefile.write("NEED_LIBUNWIND := YesPlease\n")
+               makefile.write "\n# SPECIAL CONFIGURATION FLAGS\n"
+               if platform.supports_libunwind then
+                       if toolcontext.opt_no_stacktrace.value then
+                               makefile.write "NO_STACKTRACE=True"
+                       else
+                               makefile.write "NO_STACKTRACE= # Set to `True` to enable"
+                       end
+               end
 
                # Dynamic adaptations
                # While `platform` enable complex toolchains, they are statically applied
                # For a dynamic adaptsation of the compilation, the generated Makefile should check and adapt things itself
+               makefile.write "\n\n"
 
                # Check and adapt the targeted system
                makefile.write("uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')\n")
-               makefile.write("ifeq ($(uname_S),Darwin)\n")
-               # remove -lunwind since it is already included on macosx
-               makefile.write("\tNEED_LIBUNWIND :=\n")
-               makefile.write("endif\n\n")
 
                # Check and adapt for the compiler used
                # clang need an additionnal `-Qunused-arguments`
                makefile.write("clang_check := $(shell sh -c '$(CC) -v 2>&1 | grep -q clang; echo $$?')\nifeq ($(clang_check), 0)\n\tCFLAGS += -Qunused-arguments\nendif\n")
 
-               makefile.write("ifdef NEED_LIBUNWIND\n\tLDLIBS += -lunwind\nendif\n")
+               if platform.supports_libunwind then
+                       makefile.write """
+ifneq ($(NO_STACKTRACE), True)
+  # Check and include lib-unwind in a portable way
+  ifneq ($(uname_S),Darwin)
+    # already included on macosx, but need to get the correct flags in other supported platforms.
+    ifeq ($(shell pkg-config --exists 'libunwind'; echo $$?), 0)
+      LDLIBS += `pkg-config --libs libunwind`
+      CFLAGS += `pkg-config --cflags libunwind`
+    else
+      $(warning "[_] stack-traces disabled. Please install libunwind-dev.")
+      CFLAGS += -D NO_STACKTRACE
+    endif
+  endif
+else
+  # Stacktraces disabled
+  CFLAGS += -D NO_STACKTRACE
+endif
+
+"""
+               else
+                       makefile.write("CFLAGS += -D NO_STACKTRACE\n\n")
+               end
 
                makefile.write("all: {outpath}\n")
                if outpath != real_outpath then
@@ -463,16 +489,18 @@ endif
 
                var makeflags = self.toolcontext.opt_make_flags.value
                if makeflags == null then makeflags = ""
-               self.toolcontext.info("make -B -C {compile_dir} -f {makename} -j 4 {makeflags}", 2)
+
+               var command = "make -B -C {compile_dir} -f {makename} -j 4 {makeflags}"
+               self.toolcontext.info(command, 2)
 
                var res
                if self.toolcontext.verbose_level >= 3 then
-                       res = sys.system("make -B -C {compile_dir} -f {makename} -j 4 {makeflags} 2>&1")
+                       res = sys.system("{command} 2>&1")
                else
-                       res = sys.system("make -B -C {compile_dir} -f {makename} -j 4 {makeflags} 2>&1 >/dev/null")
+                       res = sys.system("{command} 2>&1 >/dev/null")
                end
                if res != 0 then
-                       toolcontext.error(null, "make failed! Error code: {res}.")
+                       toolcontext.error(null, "Compilation Error: `make` failed with error code: {res}. The command was `{command}`.")
                end
        end
 end
@@ -494,6 +522,11 @@ abstract class AbstractCompiler
        # The modelbuilder used to know the model and the AST
        var modelbuilder: ModelBuilder is protected writable
 
+       # The associated toolchain
+       #
+       # Set by `modelbuilder.write_and_make` and permit sub-routines to access the current toolchain if required.
+       var toolchain: Toolchain is noinit
+
        # Is hardening asked? (see --hardening)
        fun hardening: Bool do return self.modelbuilder.toolcontext.opt_hardening.value
 
@@ -557,7 +590,7 @@ abstract class AbstractCompiler
        # Binds the generated C function names to Nit function names
        fun build_c_to_nit_bindings
        do
-               var compile_dir = modelbuilder.compile_dir
+               var compile_dir = toolchain.compile_dir
 
                var stream = new FileWriter.open("{compile_dir}/c_functions_hash.c")
                stream.write("#include <string.h>\n")
@@ -604,6 +637,7 @@ abstract class AbstractCompiler
                self.header.add_decl("#include <string.h>")
                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")
                self.header.add_decl("#include \"gc_chooser.h\"")
                self.header.add_decl("#ifdef ANDROID")
                self.header.add_decl("  #include <android/log.h>")
@@ -689,7 +723,7 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref );
                var finalize_meth = mainmodule.try_get_primitive_method("finalize", finalizable_type.mclass)
 
                if finalize_meth == null then
-                       modelbuilder.toolcontext.error(null, "The `Finalizable` class doesn't declare the `finalize` method.")
+                       modelbuilder.toolcontext.error(null, "Error: the `Finalizable` class does not declare the `finalize` method.")
                        return
                end
 
@@ -711,19 +745,16 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref );
        do
                var v = self.new_visitor
                v.add_decl("#include <signal.h>")
-               var ost = modelbuilder.toolcontext.opt_stacktrace.value
                var platform = target_platform
 
-               if not platform.supports_libunwind then ost = "none"
-
                var no_main = platform.no_main or modelbuilder.toolcontext.opt_no_main.value
 
-               if ost == "nitstack" or ost == "libunwind" then
+               if platform.supports_libunwind then
+                       v.add_decl("#ifndef NO_STACKTRACE")
                        v.add_decl("#define UNW_LOCAL_ONLY")
                        v.add_decl("#include <libunwind.h>")
-                       if ost == "nitstack" then
-                               v.add_decl("#include \"c_functions_hash.h\"")
-                       end
+                       v.add_decl("#include \"c_functions_hash.h\"")
+                       v.add_decl("#endif")
                end
                v.add_decl("int glob_argc;")
                v.add_decl("char **glob_argv;")
@@ -757,7 +788,8 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref );
                end
 
                v.add_decl("static void show_backtrace(void) \{")
-               if ost == "nitstack" or ost == "libunwind" then
+               if platform.supports_libunwind then
+                       v.add_decl("#ifndef NO_STACKTRACE")
                        v.add_decl("char* opt = getenv(\"NIT_NO_STACK\");")
                        v.add_decl("unw_cursor_t cursor;")
                        v.add_decl("if(opt==NULL)\{")
@@ -771,20 +803,17 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref );
                        v.add_decl("PRINT_ERROR(\"-------------------------------------------------\\n\");")
                        v.add_decl("while (unw_step(&cursor) > 0) \{")
                        v.add_decl("    unw_get_proc_name(&cursor, procname, 100, &ip);")
-                       if ost == "nitstack" then
                        v.add_decl("    const char* recv = get_nit_name(procname, strlen(procname));")
                        v.add_decl("    if (recv != NULL)\{")
                        v.add_decl("            PRINT_ERROR(\"` %s\\n\", recv);")
                        v.add_decl("    \}else\{")
                        v.add_decl("            PRINT_ERROR(\"` %s\\n\", procname);")
                        v.add_decl("    \}")
-                       else
-                       v.add_decl("    PRINT_ERROR(\"` %s \\n\",procname);")
-                       end
                        v.add_decl("\}")
                        v.add_decl("PRINT_ERROR(\"-------------------------------------------------\\n\");")
                        v.add_decl("free(procname);")
                        v.add_decl("\}")
+                       v.add_decl("#endif /* NO_STACKTRACE */")
                end
                v.add_decl("\}")
 
@@ -1144,40 +1173,45 @@ abstract class AbstractCompilerVisitor
        # 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.
-       fun varargize(mpropdef: MMethodDef, recv: RuntimeVariable, args: SequenceRead[AExpr]): Array[RuntimeVariable]
+       fun varargize(mpropdef: MMethodDef, map: nullable SignatureMap, recv: RuntimeVariable, args: SequenceRead[AExpr]): Array[RuntimeVariable]
        do
                var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null)
                var res = new Array[RuntimeVariable]
                res.add(recv)
 
-               if args.is_empty then return res
+               if msignature.arity == 0 then return res
+
+               if map == null then
+                       assert args.length == msignature.arity
+                       for ne in args do
+                               res.add self.expr(ne, null)
+                       end
+                       return res
+               end
 
-               var vararg_rank = msignature.vararg_rank
-               var vararg_len = args.length - msignature.arity
-               if vararg_len < 0 then vararg_len = 0
+               # Eval in order of arguments, not parameters
+               var exprs = new Array[RuntimeVariable].with_capacity(args.length)
+               for ne in args do
+                       exprs.add self.expr(ne, null)
+               end
 
+               # Fill `res` with the result of the evaluation according to the mapping
                for i in [0..msignature.arity[ do
-                       if i == vararg_rank then
-                               var ne = args[i]
-                               if ne isa AVarargExpr then
-                                       var e = self.expr(ne.n_expr, null)
-                                       res.add(e)
-                                       continue
-                               end
-                               var vararg = new Array[RuntimeVariable]
-                               for j in [vararg_rank..vararg_rank+vararg_len] do
-                                       var e = self.expr(args[j], null)
-                                       vararg.add(e)
-                               end
-                               var elttype = msignature.mparameters[vararg_rank].mtype
+                       var param = msignature.mparameters[i]
+                       var j = map.map.get_or_null(i)
+                       if j == null then
+                               # default value
+                               res.add(null_instance)
+                               continue
+                       end
+                       if param.is_vararg and map.vararg_decl > 0 then
+                               var vararg = exprs.sub(j, map.vararg_decl)
+                               var elttype = param.mtype
                                var arg = self.vararg_instance(mpropdef, recv, vararg, elttype)
                                res.add(arg)
-                       else
-                               var j = i
-                               if i > vararg_rank then j += vararg_len
-                               var e = self.expr(args[j], null)
-                               res.add(e)
+                               continue
                        end
+                       res.add exprs[j]
                end
                return res
        end
@@ -1448,6 +1482,14 @@ abstract class AbstractCompilerVisitor
                return res
        end
 
+       # Generate a byte value
+       fun byte_instance(value: Byte): RuntimeVariable
+       do
+               var t = mmodule.byte_type
+               var res = new RuntimeVariable("((unsigned char){value.to_s})", t, t)
+               return res
+       end
+
        # Generate a char value
        fun char_instance(value: Char): RuntimeVariable
        do
@@ -1628,6 +1670,12 @@ abstract class AbstractCompilerVisitor
        fun stmt(nexpr: nullable AExpr)
        do
                if nexpr == null then return
+               if nexpr.mtype == null and not nexpr.is_typed then
+                       # Untyped expression.
+                       # Might mean dead code
+                       # So just return
+                       return
+               end
 
                var narray = nexpr.comprehension
                if narray != null then
@@ -1647,6 +1695,13 @@ abstract class AbstractCompilerVisitor
        # `mtype` is the expected return type, pass null if no specific type is expected.
        fun expr(nexpr: AExpr, mtype: nullable MType): RuntimeVariable
        do
+               if nexpr.mtype == null then
+                       # Untyped expression.
+                       # Might mean dead code
+                       # so return a placebo result
+                       if mtype == null then mtype = compiler.mainmodule.object_type
+                       return new_var(mtype)
+               end
                var old = self.current_node
                self.current_node = nexpr
                var res = nexpr.expr(self).as(not null)
@@ -1815,11 +1870,13 @@ redef class MClassType
                else if mclass.name == "Bool" then
                        return "short int"
                else if mclass.name == "Char" then
-                       return "char"
+                       return "uint32_t"
                else if mclass.name == "Float" then
                        return "double"
+               else if mclass.name == "Byte" then
+                       return "unsigned char"
                else if mclass.name == "NativeString" then
-                       return "char*"
+                       return "unsigned char*"
                else if mclass.name == "NativeArray" then
                        return "val*"
                else
@@ -1848,6 +1905,8 @@ redef class MClassType
                        return "c"
                else if mclass.name == "Float" then
                        return "d"
+               else if mclass.name == "Byte" then
+                       return "b"
                else if mclass.name == "NativeString" then
                        return "str"
                else if mclass.name == "NativeArray" then
@@ -2038,6 +2097,9 @@ redef class AMethPropdef
                        else if pname == "unary -" then
                                v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
                                return true
+                       else if pname == "unary +" then
+                               v.ret(arguments[0])
+                               return true
                        else if pname == "*" then
                                v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
                                return true
@@ -2075,13 +2137,16 @@ redef class AMethPropdef
                        else if pname == "to_f" then
                                v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
                                return true
+                       else if pname == "to_b" then
+                               v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
+                               return true
                        else if pname == "ascii" then
-                               v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
+                               v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null)))
                                return true
                        end
                else if cname == "Char" then
                        if pname == "output" then
-                               v.add("printf(\"%c\", {arguments.first});")
+                               v.add("printf(\"%c\", ((unsigned char){arguments.first}));")
                                return true
                        else if pname == "object_id" then
                                v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
@@ -2115,7 +2180,70 @@ redef class AMethPropdef
                                v.ret(v.new_expr("{arguments[0]}-'0'", ret.as(not null)))
                                return true
                        else if pname == "ascii" then
-                               v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
+                               v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
+                               return true
+                       end
+               else if cname == "Byte" then
+                       if pname == "output" then
+                               v.add("printf(\"%x\\n\", {arguments.first});")
+                               return true
+                       else if pname == "object_id" then
+                               v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
+                               return true
+                       else if pname == "+" then
+                               v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
+                               return true
+                       else if pname == "-" then
+                               v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
+                               return true
+                       else if pname == "unary -" then
+                               v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
+                               return true
+                       else if pname == "unary +" then
+                               v.ret(arguments[0])
+                               return true
+                       else if pname == "*" then
+                               v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
+                               return true
+                       else if pname == "/" then
+                               v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
+                               return true
+                       else if pname == "%" then
+                               v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null)))
+                               return true
+                       else if pname == "lshift" then
+                               v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null)))
+                               return true
+                       else if pname == "rshift" then
+                               v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null)))
+                               return true
+                       else if pname == "==" then
+                               v.ret(v.equal_test(arguments[0], arguments[1]))
+                               return true
+                       else if pname == "!=" then
+                               var res = v.equal_test(arguments[0], arguments[1])
+                               v.ret(v.new_expr("!{res}", ret.as(not null)))
+                               return true
+                       else if pname == "<" then
+                               v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
+                               return true
+                       else if pname == ">" then
+                               v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
+                               return true
+                       else if pname == "<=" then
+                               v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
+                               return true
+                       else if pname == ">=" then
+                               v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
+                               return true
+                       else if pname == "to_i" then
+                               v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
+                               return true
+                       else if pname == "to_f" then
+                               v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
+                               return true
+                       else if pname == "ascii" then
+                               v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
                                return true
                        end
                else if cname == "Bool" then
@@ -2149,6 +2277,9 @@ redef class AMethPropdef
                        else if pname == "unary -" then
                                v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
                                return true
+                       else if pname == "unary +" then
+                               v.ret(arguments[0])
+                               return true
                        else if pname == "succ" then
                                v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
                                return true
@@ -2183,13 +2314,16 @@ redef class AMethPropdef
                        else if pname == "to_i" then
                                v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
                                return true
+                       else if pname == "to_b" then
+                               v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
+                               return true
                        end
                else if cname == "NativeString" then
                        if pname == "[]" then
-                               v.ret(v.new_expr("{arguments[0]}[{arguments[1]}]", ret.as(not null)))
+                               v.ret(v.new_expr("(uint32_t){arguments[0]}[{arguments[1]}]", ret.as(not null)))
                                return true
                        else if pname == "[]=" then
-                               v.add("{arguments[0]}[{arguments[1]}]={arguments[2]};")
+                               v.add("{arguments[0]}[{arguments[1]}]=(unsigned char){arguments[2]};")
                                return true
                        else if pname == "copy_to" then
                                v.add("memmove({arguments[1]}+{arguments[4]},{arguments[0]}+{arguments[3]},{arguments[2]});")
@@ -2201,7 +2335,7 @@ redef class AMethPropdef
                                v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", 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)))
+                               v.ret(v.new_expr("(unsigned char*)nit_alloc({arguments[1]})", ret.as(not null)))
                                return true
                        end
                else if cname == "NativeArray" then
@@ -2215,7 +2349,7 @@ redef class AMethPropdef
                        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)))
+                       v.ret(v.new_expr("(unsigned 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)
@@ -2370,7 +2504,7 @@ redef class AAttrPropdef
                var oldnode = v.current_node
                v.current_node = self
                var old_frame = v.frame
-               var frame = new StaticFrame(v, self.mpropdef.as(not null), recv.mcasttype.as_notnullable.as(MClassType), [recv])
+               var frame = new StaticFrame(v, self.mpropdef.as(not null), recv.mcasttype.undecorate.as(MClassType), [recv])
                v.frame = frame
 
                var value
@@ -2521,6 +2655,13 @@ redef class ASelfExpr
        redef fun expr(v) do return v.frame.arguments.first
 end
 
+redef class AImplicitSelfExpr
+       redef fun expr(v) do
+               if not is_sys then return super
+               return v.new_expr("glob_sys", mtype.as(not null))
+       end
+end
+
 redef class AEscapeExpr
        redef fun stmt(v) do v.add("goto BREAK_{v.escapemark_name(self.escapemark)};")
 end
@@ -2752,6 +2893,10 @@ redef class AIntExpr
        redef fun expr(v) do return v.int_instance(self.value.as(not null))
 end
 
+redef class AByteExpr
+       redef fun expr(v) do return v.byte_instance(self.value.as(not null))
+end
+
 redef class AFloatExpr
        redef fun expr(v) do return v.float_instance("{self.n_float.text}") # FIXME use value, not n_float
 end
@@ -2947,7 +3092,7 @@ redef class ASendExpr
        do
                var recv = v.expr(self.n_expr, null)
                var callsite = self.callsite.as(not null)
-               var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments)
+               var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.raw_arguments)
                return v.compile_callsite(callsite, args)
        end
 end
@@ -2957,7 +3102,7 @@ redef class ASendReassignFormExpr
        do
                var recv = v.expr(self.n_expr, null)
                var callsite = self.callsite.as(not null)
-               var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments)
+               var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.raw_arguments)
 
                var value = v.expr(self.n_value, null)
 
@@ -2979,26 +3124,33 @@ redef class ASuperExpr
 
                var callsite = self.callsite
                if callsite != null then
-                       var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
+                       var args
 
-                       # Add additional arguments for the super init call
-                       if args.length == 1 then
+                       if self.n_args.n_exprs.is_empty then
+                               # Add automatic arguments for the super init call
+                               args = [recv]
                                for i in [0..callsite.msignature.arity[ do
                                        args.add(v.frame.arguments[i+1])
                                end
+                       else
+                               args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.n_args.n_exprs)
                        end
+
                        # Super init call
                        var res = v.compile_callsite(callsite, args)
                        return res
                end
 
                var mpropdef = self.mpropdef.as(not null)
-               var args = v.varargize(mpropdef, recv, self.n_args.n_exprs)
-               if args.length == 1 then
+
+               var args
+               if self.n_args.n_exprs.is_empty then
                        args = v.frame.arguments
+               else
+                       args = v.varargize(mpropdef, signaturemap, recv, self.n_args.n_exprs)
                end
 
-               # stantard call-next-method
+               # Standard call-next-method
                return v.supercall(mpropdef, recv.mtype.as(MClassType), args)
        end
 end
@@ -3019,8 +3171,10 @@ redef class ANewExpr
 
                var recv = v.init_instance_or_extern(mtype)
 
-               var callsite = self.callsite.as(not null)
-               var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
+               var callsite = self.callsite
+               if callsite == null then return recv
+
+               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
                        #self.debug("got {res2} from {mproperty}. drop {recv}")
@@ -3072,6 +3226,20 @@ redef class AIssetAttrExpr
        end
 end
 
+redef class AVarargExpr
+       redef fun expr(v)
+       do
+               return v.expr(self.n_expr, null)
+       end
+end
+
+redef class ANamedargExpr
+       redef fun expr(v)
+       do
+               return v.expr(self.n_expr, null)
+       end
+end
+
 redef class ADebugTypeExpr
        redef fun stmt(v)
        do
@@ -3137,7 +3305,7 @@ var modelbuilder = new ModelBuilder(model, toolcontext)
 
 var arguments = toolcontext.option_context.rest
 if arguments.length > 1 and toolcontext.opt_output.value != null then
-       print "Error: --output needs a single source file. Do you prefer --dir?"
+       print "Option Error: --output needs a single source file. Do you prefer --dir?"
        exit 1
 end