Merge: Make the `do catch` great again
authorJean Privat <jean@pryen.org>
Thu, 29 Mar 2018 00:11:33 +0000 (20:11 -0400)
committerJean Privat <jean@pryen.org>
Thu, 29 Mar 2018 00:11:33 +0000 (20:11 -0400)
This PR removes some of the limitations of the `do catch` :
* Hard-coded limit of 100 jumping environments is gone, the array is now dynamic
* The structure for managing jump environments is now lazy initialized
* Now using gcc's `__thread` specifier so that each thread has it's own jumping stack

Pull-Request: #2612
Reviewed-by: Jean Privat <jean@pryen.org>
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>

1  2 
src/compiler/abstract_compiler.nit

@@@ -24,8 -24,6 +24,8 @@@ import c_tool
  private import annotation
  import mixin
  import counter
 +import pkgconfig
 +private import explain_assert_api
  
  # Add compiling options
  redef class ToolContext
@@@ -190,8 -188,6 +190,8 @@@ class MakefileToolchai
                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
@@@ -470,19 -466,14 +470,19 @@@ endi
                        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)
@@@ -500,7 -491,6 +500,7 @@@ endi
                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
@@@ -767,9 -757,10 +767,10 @@@ abstract class AbstractCompile
                self.header.add_decl """
  struct catch_stack_t {
        int cursor;
-       jmp_buf envs[100];
+       int currentSize;
+       jmp_buf *envs;
  };
- extern struct catch_stack_t catchStack;
+ extern __thread struct catch_stack_t catchStack;
  """
        end
  
@@@ -870,7 -861,7 +871,7 @@@ extern void nitni_global_ref_decr( stru
                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;")
+               v.add_decl("__thread struct catch_stack_t catchStack = \{-1, 0, NULL\};")
  
                if self.modelbuilder.toolcontext.opt_typing_test_metrics.value then
                        for tag in count_type_test_tags do
                v.add "#endif"
  
                v.add("glob_argc = argc; glob_argv = argv;")
-               v.add("catchStack.cursor = -1;")
                v.add("initialize_gc_option();")
  
                v.add "initialize_nitni_global_refs();"
@@@ -3504,6 -3494,14 +3504,14 @@@ redef class ADoExp
        redef fun stmt(v)
        do
                if self.n_catch != null then
+                       v.add("if(catchStack.currentSize == 0) \{")
+                       v.add("         catchStack.cursor = -1;")
+                       v.add("         catchStack.currentSize = 100;")
+                       v.add("         catchStack.envs = malloc(sizeof(jmp_buf)*100);")
+                       v.add("\} else if(catchStack.cursor == catchStack.currentSize - 1) \{")
+                       v.add("         catchStack.currentSize *= 2;")
+                       v.add("         catchStack.envs = realloc(catchStack.envs, sizeof(jmp_buf)*catchStack.currentSize);")
+                       v.add("\}")
                        v.add("catchStack.cursor += 1;")
                        v.add("if(!setjmp(catchStack.envs[catchStack.cursor]))\{")
                        v.stmt(self.n_block)
@@@ -3616,9 -3614,6 +3624,9 @@@ redef class AAssertExp
                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")
                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