diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 5af927f5f..6828dd8f9 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -378,6 +378,10 @@ class Component: def require_def_file(self): return False + # Return true if the component needs builder to generate a mem_initializer.cpp file with mem_initialize() and mem_finalize() functions. + def require_mem_initializer(self): + return False + def mk_install(self, out): return @@ -490,6 +494,9 @@ class ExeComponent(Component): def require_install_tactics(self): return ('tactic' in self.deps) and ('cmd_context' in self.deps) + def require_mem_initializer(self): + return True + # All executables are included in the all: rule def main_component(self): return True @@ -601,6 +608,9 @@ class DLLComponent(Component): def require_install_tactics(self): return ('tactic' in self.deps) and ('cmd_context' in self.deps) + def require_mem_initializer(self): + return True + def require_def_file(self): return IS_WINDOWS and self.export_files @@ -927,6 +937,7 @@ def mk_auto_src(): if not ONLY_MAKEFILES: mk_pat_db() mk_all_install_tactic_cpps() + mk_all_mem_initializer_cpps() # TODO: delete after src/ast/pattern/expr_pattern_match # database.smt ==> database.h @@ -1099,6 +1110,60 @@ def mk_all_install_tactic_cpps(): cnames.append(c.name) mk_install_tactic_cpp(cnames, c.src_dir) +# Generate an mem_initializer.cpp at path. +# This file implements the procedures +# void mem_initialize() +# void mem_finalize() +# This procedures are invoked by the Z3 memory_manager +def mk_mem_initializer_cpp(cnames, path): + initializer_cmds = [] + finalizer_cmds = [] + fullname = '%s/mem_initializer.cpp' % path + fout = open(fullname, 'w') + fout.write('// Automatically generated file.\n') + initializer_pat = re.compile('[ \t]*ADD_INITIALIZER\(\'([^\']*)\'\)') + finalizer_pat = re.compile('[ \t]*ADD_FINALIZER\(\'([^\']*)\'\)') + for cname in cnames: + c = get_component(cname) + h_files = filter(lambda f: f.endswith('.h'), os.listdir(c.src_dir)) + for h_file in h_files: + added_include = False + fin = open("%s/%s" % (c.src_dir, h_file), 'r') + for line in fin: + m = initializer_pat.match(line) + if m: + if not added_include: + added_include = True + fout.write('#include"%s"\n' % h_file) + initializer_cmds.append(m.group(1)) + m = finalizer_pat.match(line) + if m: + if not added_include: + added_include = True + fout.write('#include"%s"\n' % h_file) + finalizer_cmds.append(m.group(1)) + fout.write('void mem_initialize() {\n') + for cmd in initializer_cmds: + fout.write(cmd) + fout.write('\n') + fout.write('}\n') + fout.write('void mem_finalize() {\n') + for cmd in finalizer_cmds: + fout.write(cmd) + fout.write('\n') + fout.write('}\n') + if VERBOSE: + print "Generated '%s'" % fullname + +def mk_all_mem_initializer_cpps(): + if not ONLY_MAKEFILES: + for c in get_components(): + if c.require_mem_initializer(): + cnames = [] + cnames.extend(c.deps) + cnames.append(c.name) + mk_mem_initializer_cpp(cnames, c.src_dir) + # Generate a .def based on the files at c.export_files slot. def mk_def_file(c): pat1 = re.compile(".*Z3_API.*") diff --git a/src/util/debug.h b/src/util/debug.h index ab9fdd57b..64cc35fcf 100644 --- a/src/util/debug.h +++ b/src/util/debug.h @@ -98,6 +98,9 @@ private: }; void finalize_debug(); +/* + ADD_FINALIZER('finalize_debug();') +*/ #endif /* _DEBUG_H_ */ diff --git a/src/util/memory_manager.cpp b/src/util/memory_manager.cpp index 3aeb65d3b..b6eb648d9 100644 --- a/src/util/memory_manager.cpp +++ b/src/util/memory_manager.cpp @@ -1,13 +1,27 @@ +#include #include +#include"trace.h" #include"memory_manager.h" -#include"rational.h" -#include"prime_generator.h" -#include"debug.h" +#include"error_codes.h" + +// The following two function are automatically generated by the mk_make.py script. +// The script collects ADD_INITIALIZER and ADD_FINALIZER commands in the .h files. +// For example, rational.h contains +// ADD_INITIALIZER('rational::initialize();') +// ADD_FINALIZER('rational::finalize();') +// Thus, any executable or shared object (DLL) that depends on rational.h +// will have an automalically generated file mem_initializer.cpp containing +// mem_initialize() +// mem_finalize() +// and these functions will include the statements: +// rational::initialize(); +// +// rational::finalize(); +void mem_initialize(); +void mem_finalize(); // If PROFILE_MEMORY is defined, Z3 will display the amount of memory used, and the number of synchronization steps during finalization // #define PROFILE_MEMORY -void initialize_symbols(); -void finalize_symbols(); out_of_memory_error::out_of_memory_error():z3_error(ERR_MEMOUT) { } @@ -58,8 +72,7 @@ mem_usage_report g_info; void memory::initialize(size_t max_size) { g_memory_out_of_memory = false; g_memory_max_size = max_size; - rational::initialize(); - initialize_symbols(); + mem_initialize(); } bool memory::is_out_of_memory() { @@ -96,14 +109,9 @@ static bool g_finalizing = false; void memory::finalize() { g_finalizing = true; - finalize_debug(); - finalize_trace(); - finalize_symbols(); - rational::finalize(); - prime_iterator::finalize(); + mem_finalize(); } - unsigned long long memory::get_allocation_size() { long long r; #pragma omp critical (z3_memory_manager) diff --git a/src/util/prime_generator.h b/src/util/prime_generator.h index efb675737..d63fdb224 100644 --- a/src/util/prime_generator.h +++ b/src/util/prime_generator.h @@ -48,6 +48,9 @@ public: prime_iterator(prime_generator * g = 0); uint64 next(); static void finalize(); + /* + ADD_FINALIZER('prime_iterator::finalize();') + */ }; #endif diff --git a/src/util/rational.h b/src/util/rational.h index 4aa2f5fc6..f0406f30a 100644 --- a/src/util/rational.h +++ b/src/util/rational.h @@ -35,7 +35,10 @@ public: static void initialize(); static void finalize(); - + /* + ADD_INITIALIZER('rational::initialize();') + ADD_FINALIZER('rational::finalize();') + */ rational() {} rational(rational const & r) { m().set(m_val, r.m_val); } diff --git a/src/util/symbol.h b/src/util/symbol.h index e32eeb55b..65325b461 100644 --- a/src/util/symbol.h +++ b/src/util/symbol.h @@ -141,6 +141,10 @@ struct symbol_eq_proc { void initialize_symbols(); void finalize_symbols(); +/* + ADD_INITIALIZER('initialize_symbols();') + ADD_FINALIZER('finalize_symbols();') +*/ // total order on symbols... I did not overloaded '<' to avoid misunderstandings. // numerical symbols are smaller than non numerical symbols. diff --git a/src/util/trace.h b/src/util/trace.h index 941520f87..0c8c2e5b6 100644 --- a/src/util/trace.h +++ b/src/util/trace.h @@ -40,6 +40,9 @@ bool is_trace_enabled(const char * tag); void close_trace(); void open_trace(); void finalize_trace(); +/* + ADD_FINALIZER('finalize_trace();') +*/ #define TRACE(TAG, CODE) TRACE_CODE(if (is_trace_enabled(TAG)) { tout << "-------- [" << TAG << "] " << __FUNCTION__ << " " << __FILE__ << ":" << __LINE__ << " ---------\n"; CODE tout << "------------------------------------------------\n"; tout.flush(); })