add the trace system with a first test which is instance tracing
[nit.git] / src / compiler / abstract_compiler.nit
index 72f1f5f..cff93bd 100644 (file)
@@ -24,6 +24,8 @@ import c_tools
 private import annotation
 import mixin
 import counter
+import pkgconfig
+private import explain_assert_api
 
 # Add compiling options
 redef class ToolContext
@@ -73,6 +75,8 @@ redef class ToolContext
        var opt_release = new OptionBool("Compile in release mode and finalize application", "--release")
        # -g
        var opt_debug = new OptionBool("Compile in debug mode (no C-side optimization)", "-g", "--debug")
+       # --trace
+       var opt_trace = new OptionBool("Compile with lttng's instrumentation", "--trace")
 
        redef init
        do
@@ -85,6 +89,7 @@ redef class ToolContext
                self.option_context.add_option(self.opt_release)
                self.option_context.add_option(self.opt_max_c_lines, self.opt_group_c_files)
                self.option_context.add_option(self.opt_debug)
+               self.option_context.add_option(self.opt_trace)
 
                opt_no_main.hidden = true
        end
@@ -188,6 +193,8 @@ class MakefileToolchain
                var time1 = get_time
                self.toolcontext.info("*** END WRITING C: {time1-time0} ***", 2)
 
+               if not toolcontext.check_errors then return
+
                # Execute the Makefile
 
                if self.toolcontext.opt_no_cc.value then return
@@ -229,6 +236,16 @@ class MakefileToolchain
                compiler.files_to_copy.add "{clib}/gc_chooser.c"
                compiler.files_to_copy.add "{clib}/gc_chooser.h"
 
+               # Add lttng traces provider to external bodies
+               if toolcontext.opt_trace.value then
+                       #-I. is there in order to make the TRACEPOINT_INCLUDE directive in clib/traces.h refer to the directory in which gcc was invoked.
+                       var traces = new ExternCFile("traces.c", "-I.")
+                       traces.pkgconfigs.add "lttng-ust"
+                       compiler.extern_bodies.add(traces)
+                       compiler.files_to_copy.add "{clib}/traces.c"
+                       compiler.files_to_copy.add "{clib}/traces.h"
+               end
+
                # FFI
                for m in compiler.mainmodule.in_importation.greaters do
                        compiler.finalize_ffi_for_module(m)
@@ -372,6 +389,8 @@ LDFLAGS ?=
 LDLIBS  ?= -lm {{{linker_options.join(" ")}}}
 \n"""
 
+               if self.toolcontext.opt_trace.value then makefile.write "LDLIBS += -llttng-ust -ldl\n"
+
                makefile.write "\n# SPECIAL CONFIGURATION FLAGS\n"
                if platform.supports_libunwind then
                        if toolcontext.opt_no_stacktrace.value then
@@ -466,14 +485,19 @@ endif
                        f.close
                end
 
-               var java_files = new Array[ExternFile]
-
+               # pkg-config annotation support
                var pkgconfigs = new Array[String]
                for f in compiler.extern_bodies do
                        pkgconfigs.add_all f.pkgconfigs
                end
-               # Protect pkg-config
+
+               # Only test if pkg-config is used
                if not pkgconfigs.is_empty then
+
+                       # Check availability of pkg-config, silence the proc output
+                       toolcontext.check_pkgconfig_packages pkgconfigs
+
+                       # Double the check in the Makefile in case it's distributed
                        makefile.write """
 # does pkg-config exists?
 ifneq ($(shell which pkg-config >/dev/null; echo $$?), 0)
@@ -491,6 +515,7 @@ endif
                end
 
                # Compile each required extern body into a specific .o
+               var java_files = new Array[ExternFile]
                for f in compiler.extern_bodies do
                        var o = f.makefile_rule_name
                        var ff = f.filename.basename
@@ -696,6 +721,7 @@ abstract class AbstractCompiler
                self.header.add_decl("#endif")
                self.header.add_decl("#include <inttypes.h>\n")
                self.header.add_decl("#include \"gc_chooser.h\"")
+               if modelbuilder.toolcontext.opt_trace.value then self.header.add_decl("#include \"traces.h\"")
                self.header.add_decl("#ifdef __APPLE__")
                self.header.add_decl("  #include <TargetConditionals.h>")
                self.header.add_decl("  #include <syslog.h>")
@@ -705,10 +731,6 @@ abstract class AbstractCompiler
                self.header.add_decl("#ifdef _WIN32")
                self.header.add_decl("  #define be32toh(val) _byteswap_ulong(val)")
                self.header.add_decl("#endif")
-               self.header.add_decl("#ifdef __pnacl__")
-               self.header.add_decl("  #define be16toh(val) (((val) >> 8) | ((val) << 8))")
-               self.header.add_decl("  #define be32toh(val) ((be16toh((val) << 16) | (be16toh((val) >> 16))))")
-               self.header.add_decl("#endif")
                self.header.add_decl("#ifdef ANDROID")
                self.header.add_decl("  #ifndef be32toh")
                self.header.add_decl("          #define be32toh(val) betoh32(val)")
@@ -1382,6 +1404,11 @@ abstract class AbstractCompilerVisitor
                mtype = self.anchor(mtype)
                var valmtype = value.mcasttype
 
+               # CPrimitive is the best you can do
+               if valmtype.is_c_primitive then
+                       return value
+               end
+
                # Do nothing if useless autocast
                if valmtype.is_subtype(self.compiler.mainmodule, null, mtype) then
                        return value
@@ -3614,6 +3641,9 @@ redef class AAssertExpr
                var cond = v.expr_bool(self.n_expr)
                v.add("if (unlikely(!{cond})) \{")
                v.stmt(self.n_else)
+
+               explain_assert v
+
                var nid = self.n_id
                if nid != null then
                        v.add_abort("Assert '{nid.text}' failed")
@@ -3622,6 +3652,27 @@ redef class AAssertExpr
                end
                v.add("\}")
        end
+
+       # Explain assert if it fails
+       private fun explain_assert(v: AbstractCompilerVisitor)
+       do
+               var explain_assert_str = explain_assert_str
+               if explain_assert_str == null then return
+
+               var nas = v.compiler.modelbuilder.model.get_mclasses_by_name("NativeArray")
+               if nas == null then return
+
+               nas = v.compiler.modelbuilder.model.get_mclasses_by_name("Array")
+               if nas == null or nas.is_empty then return
+
+               var expr = explain_assert_str.expr(v)
+               if expr == null then return
+
+               var cstr = v.send(v.get_property("to_cstring", expr.mtype), [expr])
+               if cstr == null then return
+
+               v.add "PRINT_ERROR(\"Runtime assert: %s\\n\", {cstr});"
+       end
 end
 
 redef class AOrExpr