From e21c8f87b49688e33bd29eaa1177e1b3a82829f5 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 28 Aug 2015 10:33:26 -0600 Subject: [PATCH 1/7] Add profile test for cpp call perf --- contrib/codeanalysis/profile_cpp_calls.chai | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 contrib/codeanalysis/profile_cpp_calls.chai diff --git a/contrib/codeanalysis/profile_cpp_calls.chai b/contrib/codeanalysis/profile_cpp_calls.chai new file mode 100644 index 00000000..8b7d484d --- /dev/null +++ b/contrib/codeanalysis/profile_cpp_calls.chai @@ -0,0 +1,21 @@ + +var test_str = "bob was a string"; + +for( var i = 0; i < 200000; ++i) +{ + test_str.size(); +// test_str.find("a", i); + test_str.c_str(); + test_str.erase_at(1); + test_str.erase_at(1); + test_str.erase_at(1); + test_str.erase_at(1); + test_str.erase_at(1); + test_str.erase_at(1); + test_str.erase_at(1); + test_str.erase_at(1); + test_str.erase_at(1); + test_str.erase_at(1); + test_str.erase_at(1); + test_str = "bob was a string"; +} From 9f362608b7324533d3e0de575f9c03b60e70de5a Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 28 Aug 2015 21:19:00 -0600 Subject: [PATCH 2/7] Eliminate extra unneeded scope --- contrib/codeanalysis/profile_cpp_calls.chai | 15 ++++++++++----- include/chaiscript/language/chaiscript_eval.hpp | 5 +++-- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/contrib/codeanalysis/profile_cpp_calls.chai b/contrib/codeanalysis/profile_cpp_calls.chai index 8b7d484d..011f9a19 100644 --- a/contrib/codeanalysis/profile_cpp_calls.chai +++ b/contrib/codeanalysis/profile_cpp_calls.chai @@ -12,10 +12,15 @@ for( var i = 0; i < 200000; ++i) test_str.erase_at(1); test_str.erase_at(1); test_str.erase_at(1); - test_str.erase_at(1); - test_str.erase_at(1); - test_str.erase_at(1); - test_str.erase_at(1); - test_str.erase_at(1); + + size(test_str); +// test_str.find("a", i); + c_str(test_str); + erase_at(test_str, 1); + erase_at(test_str, 1); + erase_at(test_str, 1); + erase_at(test_str, 1); + erase_at(test_str, 1); + erase_at(test_str, 1); test_str = "bob was a string"; } diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 53d8e416..6f28008d 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -60,7 +60,6 @@ namespace chaiscript chaiscript::eval::detail::Stack_Push_Pop tpp(state); if (thisobj) state.add_object("this", *thisobj); - chaiscript::eval::detail::Scope_Push_Pop spp(state); if (t_locals) { for (const auto &local : *t_locals) { @@ -69,7 +68,9 @@ namespace chaiscript } for (size_t i = 0; i < t_param_names.size(); ++i) { - state.add_object(t_param_names[i], t_vals[i]); + if (t_param_names[i] != "this") { + state.add_object(t_param_names[i], t_vals[i]); + } } try { From 15eb78bd8f9fd85b235506412c17975d73bccbff Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 31 Aug 2015 08:41:47 -0600 Subject: [PATCH 3/7] Move to indexed function storage --- .../chaiscript/dispatchkit/dispatchkit.hpp | 141 +++++++++++------- 1 file changed, 87 insertions(+), 54 deletions(-) diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 45578703..3ded2df6 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -417,9 +417,9 @@ namespace chaiscript struct State { - std::map > m_functions; - std::map m_function_objects; - std::map m_boxed_functions; + std::vector>>> m_functions; + std::vector> m_function_objects; + std::vector> m_boxed_functions; std::map m_global_objects; Type_Name_Map m_types; std::set m_reserved_words; @@ -518,7 +518,7 @@ namespace chaiscript throw chaiscript::exception::global_non_const(); } - chaiscript::detail::threading::unique_lock l(m_global_object_mutex); + chaiscript::detail::threading::unique_lock l(m_mutex); if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end()) { @@ -533,7 +533,7 @@ namespace chaiscript { validate_object_name(name); - chaiscript::detail::threading::unique_lock l(m_global_object_mutex); + chaiscript::detail::threading::unique_lock l(m_mutex); const auto itr = m_state.m_global_objects.find(name); if (itr == m_state.m_global_objects.end()) @@ -551,7 +551,7 @@ namespace chaiscript { validate_object_name(name); - chaiscript::detail::threading::unique_lock l(m_global_object_mutex); + chaiscript::detail::threading::unique_lock l(m_mutex); if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end()) { @@ -648,19 +648,18 @@ namespace chaiscript return stack[stack.size() - 1 - ((loc & static_cast(Loc::stack_mask)) >> 16)][loc & static_cast(Loc::loc_mask)].second; } - // Is the value we are looking for a global? - { - chaiscript::detail::threading::shared_lock l(m_global_object_mutex); + // Is the value we are looking for a global or function? + chaiscript::detail::threading::shared_lock l(m_mutex); - const auto itr = m_state.m_global_objects.find(name); - if (itr != m_state.m_global_objects.end()) - { - return itr->second; - } + const auto itr = m_state.m_global_objects.find(name); + if (itr != m_state.m_global_objects.end()) + { + return itr->second; } - // If all that failed, then check to see if it's a function - return get_function_object(name); + // no? is it a function object? + return get_function_object_int(name); + } /// Registers a new named type @@ -719,19 +718,19 @@ namespace chaiscript } /// Return a function by name - std::vector< Proxy_Function > get_function(const std::string &t_name) const + std::shared_ptr> get_function(const std::string &t_name) const { chaiscript::detail::threading::shared_lock l(m_mutex); const auto &funs = get_functions_int(); - auto itr = funs.find(t_name); + auto itr = find_keyed_value(funs, t_name); if (itr != funs.end()) { return itr->second; } else { - return std::vector(); + return std::make_shared>(); } } @@ -739,12 +738,19 @@ namespace chaiscript /// \throws std::range_error if it does not Boxed_Value get_function_object(const std::string &t_name) const { -// std::cout << "Getting function object: " << t_name << '\n'; chaiscript::detail::threading::shared_lock l(m_mutex); + return get_function_object_int(t_name); + } + + /// \returns a function object (Boxed_Value wrapper) if it exists + /// \throws std::range_error if it does not + /// \warn does not obtain a mutex lock. \sa get_function_object for public version + Boxed_Value get_function_object_int(const std::string &t_name) const + { const auto &funs = get_boxed_functions_int(); - auto itr = funs.find(t_name); + auto itr = find_keyed_value(funs, t_name); if (itr != funs.end()) { @@ -754,13 +760,14 @@ namespace chaiscript } } + /// Return true if a function exists bool function_exists(const std::string &name) const { chaiscript::detail::threading::shared_lock l(m_mutex); const auto &functions = get_functions_int(); - return functions.find(name) != functions.end(); + return find_keyed_value(functions, name) != functions.end(); } /// \returns All values in the local thread state in the parent scope, or if it doesn't exist, @@ -817,11 +824,8 @@ namespace chaiscript } // add the global values - { - chaiscript::detail::threading::shared_lock l(m_global_object_mutex); - - retval.insert(m_state.m_global_objects.begin(), m_state.m_global_objects.end()); - } + chaiscript::detail::threading::shared_lock l(m_mutex); + retval.insert(m_state.m_global_objects.begin(), m_state.m_global_objects.end()); return retval; } @@ -858,7 +862,7 @@ namespace chaiscript for (const auto & function : functions) { - for (const auto & internal_func : function.second) + for (const auto & internal_func : *function.second) { rets.emplace_back(function.first, internal_func); } @@ -941,14 +945,14 @@ namespace chaiscript } }; - if (is_attribute_call(funs, params, t_has_params)) { - return do_attribute_call(1, params, funs, m_conversions); + if (is_attribute_call(*funs, params, t_has_params)) { + return do_attribute_call(1, params, *funs, m_conversions); } else { std::exception_ptr except; - if (!funs.empty()) { + if (!funs->empty()) { try { - return dispatch::dispatch(funs, params, m_conversions); + return dispatch::dispatch(*funs, params, m_conversions); } catch(chaiscript::exception::dispatch_error&) { except = std::current_exception(); } @@ -960,7 +964,8 @@ namespace chaiscript const auto functions = [&]()->std::vector { std::vector fs; - for (const auto &f : get_function("method_missing")) + const auto method_missing_funs = get_function("method_missing"); + for (const auto &f : *method_missing_funs) { if(f->compare_first_type(params[0], m_conversions)) { fs.push_back(f); @@ -996,7 +1001,7 @@ namespace chaiscript if (except) { std::rethrow_exception(except); } else { - throw chaiscript::exception::dispatch_error(params, std::vector(funs.begin(), funs.end())); + throw chaiscript::exception::dispatch_error(params, std::vector(funs->begin(), funs->end())); } } } @@ -1008,7 +1013,8 @@ namespace chaiscript Boxed_Value call_function(const std::string &t_name, const std::vector ¶ms) const { - Boxed_Value bv = dispatch::dispatch(get_function(t_name), params, m_conversions); + const auto funs = get_function(t_name); + Boxed_Value bv = dispatch::dispatch(*funs, params, m_conversions); // the result of a clone is never to be marked as a return_value if (t_name == "clone") { bv.reset_return_value(); @@ -1140,7 +1146,6 @@ namespace chaiscript State get_state() const { chaiscript::detail::threading::shared_lock l(m_mutex); - chaiscript::detail::threading::shared_lock l2(m_global_object_mutex); return m_state; } @@ -1148,7 +1153,6 @@ namespace chaiscript void set_state(const State &t_state) { chaiscript::detail::threading::unique_lock l(m_mutex); - chaiscript::detail::threading::unique_lock l2(m_global_object_mutex); m_state = t_state; } @@ -1245,32 +1249,32 @@ namespace chaiscript private: - const std::map &get_boxed_functions_int() const + const std::vector> &get_boxed_functions_int() const { return m_state.m_boxed_functions; } - std::map &get_boxed_functions_int() + std::vector> &get_boxed_functions_int() { return m_state.m_boxed_functions; } - const std::map &get_function_objects_int() const + const std::vector> &get_function_objects_int() const { return m_state.m_function_objects; } - std::map &get_function_objects_int() + std::vector> &get_function_objects_int() { return m_state.m_function_objects; } - const std::map > &get_functions_int() const + const std::vector>>> &get_functions_int() const { return m_state.m_functions; } - std::map > &get_functions_int() + std::vector>>> &get_functions_int() { return m_state.m_functions; } @@ -1384,6 +1388,38 @@ namespace chaiscript } } + template + static void add_keyed_value(Container &t_c, const Key &t_key, Value &&t_value) + { + auto itr = find_keyed_value(t_c, t_key); + + if (itr == t_c.end()) { + t_c.emplace_back(t_key, std::forward(t_value)); + } else { + typedef typename Container::value_type value_type; + *itr = value_type(t_key, std::forward(t_value)); + } + } + + template + static typename Container::iterator find_keyed_value(Container &t_c, const Key &t_key) + { + return std::find_if(t_c.begin(), t_c.end(), + [&t_key](const typename Container::value_type &o) { + return o.first == t_key; + }); + } + + template + static typename Container::const_iterator find_keyed_value(const Container &t_c, const Key &t_key) + { + return std::find_if(t_c.begin(), t_c.end(), + [&t_key](const typename Container::value_type &o) { + return o.first == t_key; + }); + } + + /// Implementation detail for adding a function. /// \throws exception::name_conflict_error if there's a function matching the given one being added void add_function(const Proxy_Function &t_f, const std::string &t_name) @@ -1392,16 +1428,13 @@ namespace chaiscript auto &funcs = get_functions_int(); - auto itr = funcs.find(t_name); - - auto &func_objs = get_function_objects_int(); - auto &boxed_funcs = get_boxed_functions_int(); + auto itr = find_keyed_value(funcs, t_name); Proxy_Function new_func = [&]() -> Proxy_Function { if (itr != funcs.end()) { - auto &vec = itr->second; + auto vec = *itr->second; for (const auto &func : vec) { if ((*t_f) == *(func)) @@ -1412,26 +1445,26 @@ namespace chaiscript vec.push_back(t_f); std::stable_sort(vec.begin(), vec.end(), &function_less_than); - return std::make_shared(vec); + itr->second = std::make_shared>(vec); + return std::make_shared(std::move(vec)); } else if (t_f->has_arithmetic_param()) { // if the function is the only function but it also contains // arithmetic operators, we must wrap it in a dispatch function // to allow for automatic arithmetic type conversions std::vector vec({t_f}); - funcs.insert(std::make_pair(t_name, vec)); + funcs.emplace_back(t_name, std::make_shared>(vec)); return std::make_shared(std::move(vec)); } else { - funcs.insert(std::make_pair(t_name, std::vector{t_f})); + funcs.emplace_back(t_name, std::make_shared>(std::initializer_list({t_f}))); return t_f; } }(); - boxed_funcs[t_name] = const_var(new_func); - func_objs[t_name] = std::move(new_func); + add_keyed_value(get_boxed_functions_int(), t_name, const_var(new_func)); + add_keyed_value(get_function_objects_int(), t_name, std::move(new_func)); } mutable chaiscript::detail::threading::shared_mutex m_mutex; - mutable chaiscript::detail::threading::shared_mutex m_global_object_mutex; Type_Conversions m_conversions; From f06e5cdcd6b044dc8b7e0571ff3d58c278abfc4c Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 31 Aug 2015 09:44:47 -0600 Subject: [PATCH 4/7] Cache function lookups --- .../chaiscript/dispatchkit/dispatchkit.hpp | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 3ded2df6..14571cf4 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -658,7 +658,10 @@ namespace chaiscript } // no? is it a function object? - return get_function_object_int(name); + auto obj = get_function_object_int(name, loc); + if (obj.first != loc) t_loc.store(obj.first); + return obj.second; + } @@ -740,21 +743,21 @@ namespace chaiscript { chaiscript::detail::threading::shared_lock l(m_mutex); - return get_function_object_int(t_name); + return get_function_object_int(t_name, 0).second; } /// \returns a function object (Boxed_Value wrapper) if it exists /// \throws std::range_error if it does not /// \warn does not obtain a mutex lock. \sa get_function_object for public version - Boxed_Value get_function_object_int(const std::string &t_name) const + std::pair get_function_object_int(const std::string &t_name, const size_t t_hint) const { const auto &funs = get_boxed_functions_int(); - auto itr = find_keyed_value(funs, t_name); + auto itr = find_keyed_value(funs, t_name, t_hint); if (itr != funs.end()) { - return itr->second; + return std::make_pair(std::distance(funs.begin(), itr), itr->second); } else { throw std::range_error("Object not found: " + t_name); } @@ -1419,6 +1422,16 @@ namespace chaiscript }); } + template + static typename Container::const_iterator find_keyed_value(const Container &t_c, const Key &t_key, const size_t t_hint) + { + if (t_c.size() > t_hint && t_c[t_hint].first == t_key) { + return t_c.begin() + t_hint; + } else { + return find_keyed_value(t_c, t_key); + } + } + /// Implementation detail for adding a function. /// \throws exception::name_conflict_error if there's a function matching the given one being added From 52e11bf0015b5835dde38a6863702b06364c53a6 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 31 Aug 2015 11:00:56 -0600 Subject: [PATCH 5/7] Fun location caching phase2 This shows ~25% performance over develop --- .../chaiscript/dispatchkit/dispatchkit.hpp | 61 ++++++++++--------- .../chaiscript/language/chaiscript_eval.hpp | 39 ++++++++---- 2 files changed, 57 insertions(+), 43 deletions(-) diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 14571cf4..b1cef9a6 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -659,7 +659,7 @@ namespace chaiscript // no? is it a function object? auto obj = get_function_object_int(name, loc); - if (obj.first != loc) t_loc.store(obj.first); + if (obj.first != loc) t_loc.store(obj.first, std::memory_order_relaxed); return obj.second; @@ -720,20 +720,29 @@ namespace chaiscript return std::vector >(m_state.m_types.begin(), m_state.m_types.end()); } + std::shared_ptr> get_method_missing_functions() const + { + uint_fast32_t method_missing_loc = m_method_missing_loc.load(std::memory_order_relaxed); + auto method_missing_funs = get_function("method_missing", method_missing_loc); + if (method_missing_funs.first != method_missing_loc) m_method_missing_loc.store(method_missing_funs.first, std::memory_order_relaxed); + return std::move(method_missing_funs.second); + } + + /// Return a function by name - std::shared_ptr> get_function(const std::string &t_name) const + std::pair>> get_function(const std::string &t_name, const size_t t_hint) const { chaiscript::detail::threading::shared_lock l(m_mutex); const auto &funs = get_functions_int(); - auto itr = find_keyed_value(funs, t_name); + auto itr = find_keyed_value(funs, t_name, t_hint); if (itr != funs.end()) { - return itr->second; + return std::make_pair(std::distance(funs.begin(), itr), itr->second); } else { - return std::make_shared>(); + return std::make_pair(size_t(0), std::make_shared>()); } } @@ -910,9 +919,11 @@ namespace chaiscript #pragma warning(push) #pragma warning(disable : 4715) #endif - Boxed_Value call_member(const std::string &t_name, const std::vector ¶ms, bool t_has_params) + Boxed_Value call_member(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector ¶ms, bool t_has_params) { - const auto funs = get_function(t_name); + uint_fast32_t loc = t_loc.load(std::memory_order_relaxed); + const auto funs = get_function(t_name, loc); + if (funs.first != loc) t_loc.store(funs.first, std::memory_order_relaxed); const auto do_attribute_call = [this](int l_num_params, const std::vector &l_params, const std::vector &l_funs, const Type_Conversions &l_conversions)->Boxed_Value @@ -948,14 +959,14 @@ namespace chaiscript } }; - if (is_attribute_call(*funs, params, t_has_params)) { - return do_attribute_call(1, params, *funs, m_conversions); + if (is_attribute_call(*funs.second, params, t_has_params)) { + return do_attribute_call(1, params, *funs.second, m_conversions); } else { std::exception_ptr except; - if (!funs->empty()) { + if (!funs.second->empty()) { try { - return dispatch::dispatch(*funs, params, m_conversions); + return dispatch::dispatch(*funs.second, params, m_conversions); } catch(chaiscript::exception::dispatch_error&) { except = std::current_exception(); } @@ -967,7 +978,8 @@ namespace chaiscript const auto functions = [&]()->std::vector { std::vector fs; - const auto method_missing_funs = get_function("method_missing"); + const auto method_missing_funs = get_method_missing_functions(); + for (const auto &f : *method_missing_funs) { if(f->compare_first_type(params[0], m_conversions)) { @@ -1004,7 +1016,7 @@ namespace chaiscript if (except) { std::rethrow_exception(except); } else { - throw chaiscript::exception::dispatch_error(params, std::vector(funs->begin(), funs->end())); + throw chaiscript::exception::dispatch_error(params, std::vector(funs.second->begin(), funs.second->end())); } } } @@ -1014,10 +1026,12 @@ namespace chaiscript - Boxed_Value call_function(const std::string &t_name, const std::vector ¶ms) const + Boxed_Value call_function(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector ¶ms) const { - const auto funs = get_function(t_name); - Boxed_Value bv = dispatch::dispatch(*funs, params, m_conversions); + uint_fast32_t loc = t_loc.load(std::memory_order_relaxed); + const auto funs = get_function(t_name, loc); + if (funs.first != loc) t_loc.store(funs.first, std::memory_order_relaxed); + Boxed_Value bv = dispatch::dispatch(*funs.second, params, m_conversions); // the result of a clone is never to be marked as a return_value if (t_name == "clone") { bv.reset_return_value(); @@ -1025,20 +1039,6 @@ namespace chaiscript return bv; } - Boxed_Value call_function(const std::string &t_name) const - { - return call_function(t_name, std::vector()); - } - - Boxed_Value call_function(const std::string &t_name, Boxed_Value p1) const - { - return call_function(t_name, std::vector({std::move(p1)})); - } - - Boxed_Value call_function(const std::string &t_name, Boxed_Value p1, Boxed_Value p2) const - { - return call_function(t_name, std::vector({std::move(p1), std::move(p2)})); - } /// Dump object info to stdout void dump_object(const Boxed_Value &o) const @@ -1483,6 +1483,7 @@ namespace chaiscript Type_Conversions m_conversions; chaiscript::detail::threading::Thread_Storage m_stack_holder; + mutable std::atomic_uint_fast32_t m_method_missing_loc; State m_state; }; diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 6f28008d..f6fde402 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -118,7 +118,7 @@ namespace chaiscript } else { chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); fpp.save_params({t_lhs, t_rhs}); - return t_ss->call_function(t_oper_string, t_lhs, t_rhs); + return t_ss->call_function(t_oper_string, m_loc, {t_lhs, t_rhs}); } } catch(const exception::dispatch_error &e){ @@ -128,6 +128,7 @@ namespace chaiscript private: Operators::Opers m_oper; + mutable std::atomic_uint_fast32_t m_loc; }; struct Int_AST_Node : public AST_Node { @@ -396,6 +397,8 @@ namespace chaiscript { assert(children.size() == 3); } Operators::Opers m_oper; + mutable std::atomic_uint_fast32_t m_loc; + mutable std::atomic_uint_fast32_t m_clone_loc; virtual ~Equation_AST_Node() {} virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE { @@ -431,14 +434,14 @@ namespace chaiscript } else { if (!rhs.is_return_value()) { - rhs = t_ss->call_function("clone", rhs); + rhs = t_ss->call_function("clone", m_clone_loc, {rhs}); } rhs.reset_return_value(); } } try { - return t_ss->call_function(this->children[1]->text, std::move(lhs), rhs); + return t_ss->call_function(this->children[1]->text, m_loc, {std::move(lhs), rhs}); } catch(const exception::dispatch_error &e){ throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, *t_ss); @@ -458,7 +461,7 @@ namespace chaiscript } else { try { - return t_ss->call_function(this->children[1]->text, std::move(lhs), rhs); + return t_ss->call_function(this->children[1]->text, m_loc, {std::move(lhs), rhs}); } catch(const exception::dispatch_error &e){ throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, *t_ss); } @@ -541,7 +544,7 @@ namespace chaiscript try { fpp.save_params(params); - return t_ss->call_function("[]", params); + return t_ss->call_function("[]", m_loc, params); } catch(const exception::dispatch_error &e){ throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, false, *t_ss ); @@ -563,6 +566,8 @@ namespace chaiscript return oss.str(); } + + mutable std::atomic_uint_fast32_t m_loc; }; struct Dot_Access_AST_Node : public AST_Node { @@ -592,7 +597,7 @@ namespace chaiscript fpp.save_params(params); try { - retval = t_ss->call_member(m_fun_name, std::move(params), has_function_params); + retval = t_ss->call_member(m_fun_name, m_loc, std::move(params), has_function_params); } catch(const exception::dispatch_error &e){ if (e.functions.empty()) @@ -608,7 +613,7 @@ namespace chaiscript if (this->children[2]->identifier == AST_Node_Type::Array_Call) { try { - retval = t_ss->call_function("[]", retval, this->children[2]->children[1]->eval(t_ss)); + retval = t_ss->call_function("[]", m_array_loc, {retval, this->children[2]->children[1]->eval(t_ss)}); } catch(const exception::dispatch_error &e){ throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, true, *t_ss); @@ -619,6 +624,8 @@ namespace chaiscript } private: + mutable std::atomic_uint_fast32_t m_loc; + mutable std::atomic_uint_fast32_t m_array_loc; std::string m_fun_name; }; @@ -932,7 +939,7 @@ namespace chaiscript if (this->children[currentCase]->identifier == AST_Node_Type::Case) { //This is a little odd, but because want to see both the switch and the case simultaneously, I do a downcast here. try { - if (hasMatched || boxed_cast(t_ss->call_function("==", match_value, this->children[currentCase]->children[0]->eval(t_ss)))) { + if (hasMatched || boxed_cast(t_ss->call_function("==", m_loc, {match_value, this->children[currentCase]->children[0]->eval(t_ss)}))) { this->children[currentCase]->eval(t_ss); hasMatched = true; } @@ -953,6 +960,8 @@ namespace chaiscript } return Boxed_Value(); } + + mutable std::atomic_uint_fast32_t m_loc; }; struct Case_AST_Node : public AST_Node { @@ -999,7 +1008,7 @@ namespace chaiscript for (const auto &child : children[0]->children) { auto obj = child->eval(t_ss); if (!obj.is_return_value()) { - vec.push_back(t_ss->call_function("clone", obj)); + vec.push_back(t_ss->call_function("clone", m_loc, {obj})); } else { vec.push_back(std::move(obj)); } @@ -1016,6 +1025,8 @@ namespace chaiscript { return "[" + AST_Node::pretty_print() + "]"; } + + mutable std::atomic_uint_fast32_t m_loc; }; struct Inline_Map_AST_Node : public AST_Node { @@ -1030,7 +1041,7 @@ namespace chaiscript for (const auto &child : children[0]->children) { auto obj = child->children[1]->eval(t_ss); if (!obj.is_return_value()) { - obj = t_ss->call_function("clone", obj); + obj = t_ss->call_function("clone", m_loc, {obj}); } retval[t_ss->boxed_cast(child->children[0]->eval(t_ss))] = std::move(obj); @@ -1043,6 +1054,7 @@ namespace chaiscript } } + mutable std::atomic_uint_fast32_t m_loc; }; struct Return_AST_Node : public AST_Node { @@ -1125,7 +1137,7 @@ namespace chaiscript } else { chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); fpp.save_params({bv}); - return t_ss->call_function(children[0]->text, std::move(bv)); + return t_ss->call_function(children[0]->text, m_loc, {std::move(bv)}); } } catch (const exception::dispatch_error &e) { throw exception::eval_error("Error with prefix operator evaluation: '" + children[0]->text + "'", e.parameters, e.functions, false, *t_ss); @@ -1134,6 +1146,7 @@ namespace chaiscript private: Operators::Opers m_oper; + mutable std::atomic_uint_fast32_t m_loc; }; struct Break_AST_Node : public AST_Node { @@ -1196,14 +1209,14 @@ namespace chaiscript try { auto oper1 = children[0]->children[0]->children[0]->eval(t_ss); auto oper2 = children[0]->children[0]->children[1]->eval(t_ss); - return t_ss->call_function("generate_range", - oper1, oper2); + return t_ss->call_function("generate_range", m_loc, {oper1, oper2}); } catch (const exception::dispatch_error &e) { throw exception::eval_error("Unable to generate range vector, while calling 'generate_range'", e.parameters, e.functions, false, *t_ss); } } + mutable std::atomic_uint_fast32_t m_loc; }; struct Annotation_AST_Node : public AST_Node { From f3dbb7ed8738b592e64f8c4d64fd49a3305e450f Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 31 Aug 2015 11:09:03 -0600 Subject: [PATCH 6/7] Control how fast global vectors grow --- include/chaiscript/dispatchkit/dispatchkit.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index b1cef9a6..47988764 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -1397,6 +1397,7 @@ namespace chaiscript auto itr = find_keyed_value(t_c, t_key); if (itr == t_c.end()) { + t_c.reserve(t_c.size() + 1); // tightly control growth of memory usage here t_c.emplace_back(t_key, std::forward(t_value)); } else { typedef typename Container::value_type value_type; @@ -1456,6 +1457,7 @@ namespace chaiscript } } + vec.reserve(vec.size() + 1); // tightly control vec growth vec.push_back(t_f); std::stable_sort(vec.begin(), vec.end(), &function_less_than); itr->second = std::make_shared>(vec); From e1a80fb5ceec23af39cdee27c568469a2579175d Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 16 Sep 2015 10:28:05 -0600 Subject: [PATCH 7/7] A couple of MSVC fixes --- include/chaiscript/chaiscript_defines.hpp | 2 +- include/chaiscript/dispatchkit/dispatchkit.hpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/chaiscript/chaiscript_defines.hpp b/include/chaiscript/chaiscript_defines.hpp index c28e9a56..5c54051e 100644 --- a/include/chaiscript/chaiscript_defines.hpp +++ b/include/chaiscript/chaiscript_defines.hpp @@ -52,7 +52,7 @@ #define CHAISCRIPT_MODULE_EXPORT extern "C" #endif -#ifdef CHAISCRIPT_MSVC +#ifdef CHAISCRIPT_MSVC_12 #define CHAISCRIPT_NOEXCEPT throw() #define CHAISCRIPT_CONSTEXPR #else diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 47988764..de2caa04 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -659,7 +659,7 @@ namespace chaiscript // no? is it a function object? auto obj = get_function_object_int(name, loc); - if (obj.first != loc) t_loc.store(obj.first, std::memory_order_relaxed); + if (obj.first != loc) t_loc.store(uint_fast32_t(obj.first), std::memory_order_relaxed); return obj.second; @@ -724,7 +724,7 @@ namespace chaiscript { uint_fast32_t method_missing_loc = m_method_missing_loc.load(std::memory_order_relaxed); auto method_missing_funs = get_function("method_missing", method_missing_loc); - if (method_missing_funs.first != method_missing_loc) m_method_missing_loc.store(method_missing_funs.first, std::memory_order_relaxed); + if (method_missing_funs.first != method_missing_loc) m_method_missing_loc.store(uint_fast32_t(method_missing_funs.first), std::memory_order_relaxed); return std::move(method_missing_funs.second); } @@ -923,7 +923,7 @@ namespace chaiscript { uint_fast32_t loc = t_loc.load(std::memory_order_relaxed); const auto funs = get_function(t_name, loc); - if (funs.first != loc) t_loc.store(funs.first, std::memory_order_relaxed); + if (funs.first != loc) t_loc.store(uint_fast32_t(funs.first), std::memory_order_relaxed); const auto do_attribute_call = [this](int l_num_params, const std::vector &l_params, const std::vector &l_funs, const Type_Conversions &l_conversions)->Boxed_Value @@ -1030,7 +1030,7 @@ namespace chaiscript { uint_fast32_t loc = t_loc.load(std::memory_order_relaxed); const auto funs = get_function(t_name, loc); - if (funs.first != loc) t_loc.store(funs.first, std::memory_order_relaxed); + if (funs.first != loc) t_loc.store(uint_fast32_t(funs.first), std::memory_order_relaxed); Boxed_Value bv = dispatch::dispatch(*funs.second, params, m_conversions); // the result of a clone is never to be marked as a return_value if (t_name == "clone") {