Merge: Simplify management of primitive types
authorJean Privat <jean@pryen.org>
Mon, 23 Mar 2015 15:16:10 +0000 (22:16 +0700)
committerJean Privat <jean@pryen.org>
Mon, 23 Mar 2015 15:16:10 +0000 (22:16 +0700)
Add direct methods to access primitive types

Simplify and improve the generation of primitive values in the compiler.

More (and improved) `*_instance` methods are now available in AbstractCompilerVisitor.
One of the point is the simplification of the generated C so that less local variables are generated, maybe this will also help the C compiler to work faster.

Pull-Request: #1213
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>

contrib/header_keeper/Makefile [new file with mode: 0644]
contrib/header_keeper/src/header_keeper.nit [new file with mode: 0644]
lib/standard/exec_nit.c
lib/standard/exec_nit.h
src/compiler/abstract_compiler.nit
src/compiler/global_compiler.nit
src/compiler/separate_compiler.nit
src/compiler/separate_erasure_compiler.nit

diff --git a/contrib/header_keeper/Makefile b/contrib/header_keeper/Makefile
new file mode 100644 (file)
index 0000000..76d36c6
--- /dev/null
@@ -0,0 +1,7 @@
+bin/header_keeper:
+       mkdir -p bin
+       ../../bin/nitc --dir bin src/header_keeper.nit
+
+tests: bin/header_keeper
+       gcc -E /usr/include/SDL/SDL_image.h | bin/header_keeper SDL_image.h
+       gcc -E /usr/include/GLES2/gl2.h | bin/header_keeper gl2.h
diff --git a/contrib/header_keeper/src/header_keeper.nit b/contrib/header_keeper/src/header_keeper.nit
new file mode 100644 (file)
index 0000000..adf6b77
--- /dev/null
@@ -0,0 +1,57 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Filters preprocessed C-like header files to remove included files
+#
+# This tool is used in the process of parsing header files to extract
+# information on the declared services (the functions and structures).
+# This information is then used to generate bindings for Nit code
+# to access these services.
+#
+# The C preprocessor extends macros, inline files marked with `#include`,
+# and more. This tool acts after the C preprocessor, in a way to keep
+# everything but the included files. It searches for line pragmas
+# to identify the source of each line. The result is printed to stdout.
+#
+# Typical usage on the output of `gcc -E` (it would be the same with `clang`):
+#
+# ~~~sh
+# gcc -E /usr/include/SDL/SDL_image.h | header_keeper SDL_image.h > preprocessed_header.h
+# ~~~
+#
+# This module can also be used as a library.
+# The main service is the method `header_keeper`.
+module header_keeper
+
+# Filters the preprocessed `input` to keep only files from `target` and write to the `output`
+fun header_keeper(input: Reader, output: Writer, target: String)
+do
+       var in_target = false
+       while not input.eof do
+               var line = input.read_line
+               if not line.is_empty and line[0] == '#' then
+                       in_target = line.has(target)
+                       continue
+               end
+
+               if in_target then output.write line + "\n"
+       end
+end
+
+if args.length != 1 then
+       print "Usage: header_keeper header_name.h"
+       exit 1
+end
+
+header_keeper(sys.stdin, sys.stdout, args.first)
index 317e909..5b5ffbb 100644 (file)
@@ -142,3 +142,11 @@ void exec_NativeProcess_NativeProcess_wait_0(void*d) {
                data->running = 0;
        }
 }
+
+int string_NativeString_NativeString_system_0(const char *cmd) {
+       int status = system(cmd);
+       if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT) {
+               // cmd exited on SIGINT: in my opinion the user wants the main to be discontinued
+               kill(getpid(), SIGINT);
+       }
+}
index c6a59d4..fbd040a 100644 (file)
@@ -31,7 +31,7 @@ struct se_exec_data {
 
 se_exec_data_t* exec_Process_Process_basic_exec_execute_4(void *, char *, char *, int, int);
 
-#define string_NativeString_NativeString_system_0(self) (system(self))
+int string_NativeString_NativeString_system_0(const char*);
 
 #define exec_NativeProcess_NativeProcess_id_0(self) (((se_exec_data_t*)self)->id)
 #define exec_NativeProcess_NativeProcess_status_0(self) (((se_exec_data_t*)self)->status)
index 4dc34c8..5800bad 100644 (file)
@@ -603,9 +603,9 @@ abstract class AbstractCompiler
                var gccd_disable = modelbuilder.toolcontext.opt_no_gcc_directive.value
                if gccd_disable.has("noreturn") or gccd_disable.has("all") then
                        # Signal handler function prototype
-                       self.header.add_decl("void show_backtrace(int);")
+                       self.header.add_decl("void fatal_exit(int);")
                else
-                       self.header.add_decl("void show_backtrace(int) __attribute__ ((noreturn));")
+                       self.header.add_decl("void fatal_exit(int) __attribute__ ((noreturn));")
                end
 
                if gccd_disable.has("likely") or gccd_disable.has("all") then
@@ -741,12 +741,7 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref );
                        v.compiler.header.add_decl("extern long count_isset_checks;")
                end
 
-               v.add_decl("void sig_handler(int signo)\{")
-               v.add_decl("PRINT_ERROR(\"Caught signal : %s\\n\", strsignal(signo));")
-               v.add_decl("show_backtrace(signo);")
-               v.add_decl("\}")
-
-               v.add_decl("void show_backtrace (int signo) \{")
+               v.add_decl("static void show_backtrace(void) \{")
                if ost == "nitstack" or ost == "libunwind" then
                        v.add_decl("char* opt = getenv(\"NIT_NO_STACK\");")
                        v.add_decl("unw_cursor_t cursor;")
@@ -776,7 +771,19 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref );
                        v.add_decl("free(procname);")
                        v.add_decl("\}")
                end
-               v.add_decl("exit(signo);")
+               v.add_decl("\}")
+
+               v.add_decl("void sig_handler(int signo)\{")
+               v.add_decl("PRINT_ERROR(\"Caught signal : %s\\n\", strsignal(signo));")
+               v.add_decl("show_backtrace();")
+               # rethrows
+               v.add_decl("signal(signo, SIG_DFL);")
+               v.add_decl("kill(getpid(), signo);")
+               v.add_decl("\}")
+
+               v.add_decl("void fatal_exit(int status) \{")
+               v.add_decl("show_backtrace();")
+               v.add_decl("exit(status);")
                v.add_decl("\}")
 
                if no_main then
@@ -1581,7 +1588,7 @@ abstract class AbstractCompilerVisitor
                else
                        self.add("PRINT_ERROR(\"\\n\");")
                end
-               self.add("show_backtrace(1);")
+               self.add("fatal_exit(1);")
        end
 
        # Add a dynamic cast
index 53aef53..6b67611 100644 (file)
@@ -312,7 +312,7 @@ class GlobalCompilerVisitor
                        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} */")
@@ -323,7 +323,7 @@ class GlobalCompilerVisitor
                        # 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
@@ -349,7 +349,7 @@ class GlobalCompilerVisitor
                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\"); 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}); /* boxing {value.mtype} */")
@@ -630,7 +630,7 @@ class GlobalCompilerVisitor
        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)
index f94951e..4d26aa3 100644 (file)
@@ -456,14 +456,9 @@ class SeparateCompiler
                # Collect types to colorize
                var live_types = runtime_type_analysis.live_types
                var live_cast_types = runtime_type_analysis.live_cast_types
-               var mtypes = new HashSet[MType]
-               mtypes.add_all(live_types)
-               for c in self.box_kinds.keys do
-                       mtypes.add(c.mclass_type)
-               end
 
                # Compute colors
-               var poset = poset_from_mtypes(mtypes, live_cast_types)
+               var poset = poset_from_mtypes(live_types, live_cast_types)
                var colorer = new POSetColorer[MType]
                colorer.colorize(poset)
                type_ids = colorer.ids
@@ -471,20 +466,42 @@ class SeparateCompiler
                type_tables = build_type_tables(poset)
 
                # VT and FT are stored with other unresolved types in the big resolution_tables
-               self.compile_resolution_tables(mtypes)
+               self.compute_resolution_tables(live_types)
 
                return poset
        end
 
        private fun poset_from_mtypes(mtypes, cast_types: Set[MType]): POSet[MType] do
                var poset = new POSet[MType]
+
+               # Instead of doing the full matrix mtypes X cast_types,
+               # a grouping is done by the base classes of the type so
+               # that we compare only types whose base classes are in inheritance.
+
+               var mtypes_by_class = new MultiHashMap[MClass, MType]
                for e in mtypes do
+                       var c = e.as_notnullable.as(MClassType).mclass
+                       mtypes_by_class[c].add(e)
+                       poset.add_node(e)
+               end
+
+               var casttypes_by_class = new MultiHashMap[MClass, MType]
+               for e in cast_types do
+                       var c = e.as_notnullable.as(MClassType).mclass
+                       casttypes_by_class[c].add(e)
                        poset.add_node(e)
-                       for o in cast_types do
-                               if e == o then continue
-                               poset.add_node(o)
-                               if e.is_subtype(mainmodule, null, o) then
-                                       poset.add_edge(e, o)
+               end
+
+               for c1, ts1 in mtypes_by_class do
+                       for c2 in c1.in_hierarchy(mainmodule).greaters do
+                               var ts2 = casttypes_by_class[c2]
+                               for e in ts1 do
+                                       for o in ts2 do
+                                               if e == o then continue
+                                               if e.is_subtype(mainmodule, null, o) then
+                                                       poset.add_edge(e, o)
+                                               end
+                                       end
                                end
                        end
                end
@@ -510,9 +527,8 @@ class SeparateCompiler
                return tables
        end
 
-       protected fun compile_resolution_tables(mtypes: Set[MType]) do
-               # resolution_tables is used to perform a type resolution at runtime in O(1)
-
+       # resolution_tables is used to perform a type resolution at runtime in O(1)
+       private fun compute_resolution_tables(mtypes: Set[MType]) do
                # During the visit of the body of classes, live_unresolved_types are collected
                # and associated to
                # Collect all live_unresolved_types (visited in the body of classes)
@@ -973,6 +989,7 @@ class SeparateCompiler
                                v.add_decl("NULL,")
                        else
                                var s = "type_{t.c_name}"
+                               undead_types.add(t.mclass_type)
                                v.require_declaration(s)
                                v.add_decl("&{s},")
                        end
@@ -1170,7 +1187,7 @@ class SeparateCompilerVisitor
                        var res = self.new_var(mtype)
                        if compiler.runtime_type_analysis != null and 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.require_declaration("BOX_{valtype.c_name}")
@@ -1184,7 +1201,7 @@ class SeparateCompilerVisitor
                        # 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
@@ -1210,7 +1227,7 @@ class SeparateCompilerVisitor
                        var res = self.new_var(mtype)
                        if compiler.runtime_type_analysis != null and 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\"); show_backtrace(1);")
+                               self.add("PRINT_ERROR(\"Dead code executed!\\n\"); fatal_exit(1);")
                                return res
                        end
                        self.require_declaration("BOX_{valtype.c_name}")
@@ -1770,7 +1787,7 @@ class SeparateCompilerVisitor
                                self.add("count_type_test_resolved_{tag}++;")
                        end
                else
-                       self.add("PRINT_ERROR(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{value.inspect}\"); show_backtrace(1);")
+                       self.add("PRINT_ERROR(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{value.inspect}\"); fatal_exit(1);")
                end
 
                # check color is in table
index ada0bbf..31d424b 100644 (file)
@@ -615,7 +615,7 @@ class SeparateErasureCompilerVisitor
                        var res = self.new_var(mtype)
                        if compiler.runtime_type_analysis != null and 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\"); show_backtrace(1);")
+                               self.add("PRINT_ERROR(\"Dead code executed!\\n\"); fatal_exit(1);")
                                return res
                        end
                        self.require_declaration("BOX_{valtype.c_name}")