diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/nvim/api/buffer.c | 6 | ||||
| -rw-r--r-- | src/nvim/api/private/helpers.c | 27 | ||||
| -rw-r--r-- | src/nvim/api/vim.c | 20 | ||||
| -rw-r--r-- | src/nvim/buffer_updates.c | 13 | ||||
| -rw-r--r-- | src/nvim/decoration.c | 50 | ||||
| -rw-r--r-- | src/nvim/eval.c | 2 | ||||
| -rw-r--r-- | src/nvim/eval/funcs.c | 5 | ||||
| -rw-r--r-- | src/nvim/eval/typval.c | 7 | ||||
| -rw-r--r-- | src/nvim/highlight.c | 4 | ||||
| -rw-r--r-- | src/nvim/lua/converter.c | 2 | ||||
| -rw-r--r-- | src/nvim/lua/converter.h | 1 | ||||
| -rw-r--r-- | src/nvim/lua/executor.c | 188 | ||||
| -rw-r--r-- | src/nvim/lua/executor.h | 2 | ||||
| -rw-r--r-- | src/nvim/memory.c | 6 | 
14 files changed, 178 insertions, 155 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 66c4454f7b..6142db049d 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -222,11 +222,7 @@ Boolean nvim_buf_attach(uint64_t channel_id,    return buf_updates_register(buf, channel_id, cb, send_buffer);  error: -  // TODO(bfredl): ASAN build should check that the ref table is empty? -  api_free_luaref(cb.on_lines); -  api_free_luaref(cb.on_bytes); -  api_free_luaref(cb.on_changedtick); -  api_free_luaref(cb.on_detach); +  buffer_update_callbacks_free(cb);    return false;  } diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index d2b787a6f5..382244d6b3 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -1708,33 +1708,6 @@ const char *describe_ns(NS ns_id)    return "(UNKNOWN PLUGIN)";  } -DecorProvider *get_provider(NS ns_id, bool force) -{ -  ssize_t i; -  for (i = 0; i < (ssize_t)kv_size(decor_providers); i++) { -    DecorProvider *item = &kv_A(decor_providers, i); -    if (item->ns_id == ns_id) { -      return item; -    } else if (item->ns_id > ns_id) { -      break; -    } -  } - -  if (!force) { -    return NULL; -  } - -  for (ssize_t j = (ssize_t)kv_size(decor_providers)-1; j >= i; j++) { -    // allocates if needed: -    (void)kv_a(decor_providers, (size_t)j+1); -    kv_A(decor_providers, (size_t)j+1) = kv_A(decor_providers, j); -  } -  DecorProvider *item = &kv_a(decor_providers, (size_t)i); -  *item = DECORATION_PROVIDER_INIT(ns_id); - -  return item; -} -  static bool parse_float_anchor(String anchor, FloatAnchor *out)  {    if (anchor.size == 0) { diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 787b6addc9..3ae944de4d 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -2708,6 +2708,7 @@ Dictionary nvim__stats(void)    Dictionary rv = ARRAY_DICT_INIT;    PUT(rv, "fsync", INTEGER_OBJ(g_stats.fsync));    PUT(rv, "redraw", INTEGER_OBJ(g_stats.redraw)); +  PUT(rv, "lua_refcount", INTEGER_OBJ(nlua_refcount));    return rv;  } @@ -2880,19 +2881,6 @@ void nvim__screenshot(String path)    ui_call_screenshot(path);  } -static void clear_provider(DecorProvider *p) -{ -  if (p == NULL) { -    return; -  } -  NLUA_CLEAR_REF(p->redraw_start); -  NLUA_CLEAR_REF(p->redraw_buf); -  NLUA_CLEAR_REF(p->redraw_win); -  NLUA_CLEAR_REF(p->redraw_line); -  NLUA_CLEAR_REF(p->redraw_end); -  p->active = false; -} -  /// Set or change decoration provider for a namespace  ///  /// This is a very general purpose interface for having lua callbacks @@ -2937,8 +2925,8 @@ void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts,                                    Error *err)    FUNC_API_SINCE(7) FUNC_API_LUA_ONLY  { -  DecorProvider *p = get_provider((NS)ns_id, true); -  clear_provider(p); +  DecorProvider *p = get_decor_provider((NS)ns_id, true); +  decor_provider_clear(p);    // regardless of what happens, it seems good idea to redraw    redraw_all_later(NOT_VALID);  // TODO(bfredl): too soon? @@ -2981,5 +2969,5 @@ void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts,    p->active = true;    return;  error: -  clear_provider(p); +  decor_provider_clear(p);  } diff --git a/src/nvim/buffer_updates.c b/src/nvim/buffer_updates.c index 97562eace6..5c573530d1 100644 --- a/src/nvim/buffer_updates.c +++ b/src/nvim/buffer_updates.c @@ -176,7 +176,7 @@ void buf_updates_unload(buf_T *buf, bool can_reload)      if (keep) {        kv_A(buf->update_callbacks, j++) = kv_A(buf->update_callbacks, i);      } else { -      free_update_callbacks(cb); +      buffer_update_callbacks_free(cb);      }    }    kv_size(buf->update_callbacks) = j; @@ -290,7 +290,7 @@ void buf_updates_send_changes(buf_T *buf,        textlock--;        if (res.type == kObjectTypeBoolean && res.data.boolean == true) { -        free_update_callbacks(cb); +        buffer_update_callbacks_free(cb);          keep = false;        }        api_free_object(res); @@ -342,7 +342,7 @@ void buf_updates_send_splice(        textlock--;        if (res.type == kObjectTypeBoolean && res.data.boolean == true) { -        free_update_callbacks(cb); +        buffer_update_callbacks_free(cb);          keep = false;        }      } @@ -378,7 +378,7 @@ void buf_updates_changedtick(buf_T *buf)        textlock--;        if (res.type == kObjectTypeBoolean && res.data.boolean == true) { -        free_update_callbacks(cb); +        buffer_update_callbacks_free(cb);          keep = false;        }        api_free_object(res); @@ -406,8 +406,11 @@ void buf_updates_changedtick_single(buf_T *buf, uint64_t channel_id)      rpc_send_event(channel_id, "nvim_buf_changedtick_event", args);  } -static void free_update_callbacks(BufUpdateCallbacks cb) +void buffer_update_callbacks_free(BufUpdateCallbacks cb)  {    api_free_luaref(cb.on_lines); +  api_free_luaref(cb.on_bytes);    api_free_luaref(cb.on_changedtick); +  api_free_luaref(cb.on_reload); +  api_free_luaref(cb.on_detach);  } diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c index e16598e7d2..52a48ae6fb 100644 --- a/src/nvim/decoration.c +++ b/src/nvim/decoration.c @@ -2,6 +2,7 @@  // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com  #include "nvim/vim.h" +#include "nvim/lua/executor.h"  #include "nvim/extmark.h"  #include "nvim/decoration.h"  #include "nvim/screen.h" @@ -365,3 +366,52 @@ void decor_add_ephemeral(int start_row, int start_col, int end_row, int end_col,    decor_add(&decor_state, start_row, start_col, end_row, end_col, decor, true,              priority);  } + + +DecorProvider *get_decor_provider(NS ns_id, bool force) +{ +  ssize_t i; +  for (i = 0; i < (ssize_t)kv_size(decor_providers); i++) { +    DecorProvider *item = &kv_A(decor_providers, i); +    if (item->ns_id == ns_id) { +      return item; +    } else if (item->ns_id > ns_id) { +      break; +    } +  } + +  if (!force) { +    return NULL; +  } + +  for (ssize_t j = (ssize_t)kv_size(decor_providers)-1; j >= i; j++) { +    // allocates if needed: +    (void)kv_a(decor_providers, (size_t)j+1); +    kv_A(decor_providers, (size_t)j+1) = kv_A(decor_providers, j); +  } +  DecorProvider *item = &kv_a(decor_providers, (size_t)i); +  *item = DECORATION_PROVIDER_INIT(ns_id); + +  return item; +} + +void decor_provider_clear(DecorProvider *p) +{ +  if (p == NULL) { +    return; +  } +  NLUA_CLEAR_REF(p->redraw_start); +  NLUA_CLEAR_REF(p->redraw_buf); +  NLUA_CLEAR_REF(p->redraw_win); +  NLUA_CLEAR_REF(p->redraw_line); +  NLUA_CLEAR_REF(p->redraw_end); +  p->active = false; +} + +void decor_free_all_mem(void) +{ +  for (size_t i = 0; i < kv_size(decor_providers); i++) { +    decor_provider_clear(&kv_A(decor_providers, i)); +  } +  kv_destroy(decor_providers); +} diff --git a/src/nvim/eval.c b/src/nvim/eval.c index c9366b3bd3..550fe8ab65 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -6263,6 +6263,7 @@ void common_function(typval_T *argvars, typval_T *rettv,      // function(dict.MyFunc, [arg])      arg_pt = argvars[0].vval.v_partial;      s = partial_name(arg_pt); +    // TODO(bfredl): do the entire nlua_is_table_from_lua dance    } else {      // function('MyFunc', [arg], dict)      s = (char_u *)tv_get_string(&argvars[0]); @@ -7362,7 +7363,6 @@ bool callback_from_typval(Callback *const callback, typval_T *const arg)      char_u *name = nlua_register_table_as_callable(arg);      if (name != NULL) { -      func_ref(name);        callback->data.funcref = vim_strsave(name);        callback->type = kCallbackFuncref;      } else { diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 38002474af..51e5a27348 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -810,6 +810,7 @@ static void f_call(typval_T *argvars, typval_T *rettv, FunPtr fptr)      return;    } +  bool owned = false;    char_u      *func;    partial_T   *partial = NULL;    dict_T      *selfdict = NULL; @@ -820,6 +821,7 @@ static void f_call(typval_T *argvars, typval_T *rettv, FunPtr fptr)      func = partial_name(partial);    } else if (nlua_is_table_from_lua(&argvars[0])) {      func = nlua_register_table_as_callable(&argvars[0]); +    owned = true;    } else {      func = (char_u *)tv_get_string(&argvars[0]);    } @@ -837,6 +839,9 @@ static void f_call(typval_T *argvars, typval_T *rettv, FunPtr fptr)    }    func_call(func, &argvars[1], partial, selfdict, rettv); +  if (owned) { +    func_unref(func); +  }  }  /* diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index fe3d147040..71e4edc667 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -219,6 +219,7 @@ list_T *tv_list_alloc(const ptrdiff_t len)    list->lv_used_next = gc_first_list;    gc_first_list = list;    list_log(list, NULL, (void *)(uintptr_t)len, "alloc"); +  list->lua_table_ref = LUA_NOREF;    return list;  } @@ -302,7 +303,7 @@ void tv_list_free_list(list_T *const l)    }    list_log(l, NULL, NULL, "freelist"); -  nlua_free_typval_list(l); +  NLUA_CLEAR_REF(l->lua_table_ref);    xfree(l);  } @@ -1404,6 +1405,8 @@ dict_T *tv_dict_alloc(void)    d->dv_copyID = 0;    QUEUE_INIT(&d->watchers); +  d->lua_table_ref = LUA_NOREF; +    return d;  } @@ -1454,7 +1457,7 @@ void tv_dict_free_dict(dict_T *const d)      d->dv_used_next->dv_used_prev = d->dv_used_prev;    } -  nlua_free_typval_dict(d); +  NLUA_CLEAR_REF(d->lua_table_ref);    xfree(d);  } diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c index f03382bea7..329c448cf0 100644 --- a/src/nvim/highlight.c +++ b/src/nvim/highlight.c @@ -151,7 +151,7 @@ int hl_get_syn_attr(int ns_id, int idx, HlAttrs at_en)  void ns_hl_def(NS ns_id, int hl_id, HlAttrs attrs, int link_id)  { -  DecorProvider *p = get_provider(ns_id, true); +  DecorProvider *p = get_decor_provider(ns_id, true);    if ((attrs.rgb_ae_attr & HL_DEFAULT)        && map_has(ColorKey, ColorItem)(ns_hl, ColorKey(ns_id, hl_id))) {      return; @@ -175,7 +175,7 @@ int ns_get_hl(NS ns_id, int hl_id, bool link, bool nodefault)      ns_id = ns_hl_active;    } -  DecorProvider *p = get_provider(ns_id, true); +  DecorProvider *p = get_decor_provider(ns_id, true);    ColorItem it = map_get(ColorKey, ColorItem)(ns_hl, ColorKey(ns_id, hl_id));    // TODO(bfredl): map_ref true even this?    bool valid_cache = it.version >= p->hl_valid; diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index 83b3729ad3..ce8c9b0d06 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -400,7 +400,6 @@ nlua_pop_typval_table_processing_end:        case LUA_TFUNCTION: {          LuaCFunctionState *state = xmalloc(sizeof(LuaCFunctionState));          state->lua_callable.func_ref = nlua_ref(lstate, -1); -        state->lua_callable.table_ref = LUA_NOREF;          char_u *name = register_cfunc(              &nlua_CFunction_func_call, @@ -412,6 +411,7 @@ nlua_pop_typval_table_processing_end:          break;        }        case LUA_TUSERDATA: { +        // TODO(bfredl): check mt.__call and convert to function?          nlua_pushref(lstate, nlua_nil_ref);          bool is_nil = lua_rawequal(lstate, -2, -1);          lua_pop(lstate, 1); diff --git a/src/nvim/lua/converter.h b/src/nvim/lua/converter.h index 8601a32418..43a7e06019 100644 --- a/src/nvim/lua/converter.h +++ b/src/nvim/lua/converter.h @@ -11,7 +11,6 @@  typedef struct {    LuaRef func_ref; -  LuaRef table_ref;  } LuaCallable;  typedef struct { diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 03d178467b..9b8e9ff8cc 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -5,6 +5,7 @@  #include <lualib.h>  #include <lauxlib.h> +#include "nvim/assert.h"  #include "nvim/version.h"  #include "nvim/misc1.h"  #include "nvim/getchar.h" @@ -18,6 +19,7 @@  #include "nvim/vim.h"  #include "nvim/ex_getln.h"  #include "nvim/ex_cmds2.h" +#include "nvim/map.h"  #include "nvim/message.h"  #include "nvim/memline.h"  #include "nvim/buffer_defs.h" @@ -32,9 +34,7 @@  #include "nvim/event/time.h"  #include "nvim/event/loop.h" -#ifdef WIN32  #include "nvim/os/os.h" -#endif  #include "nvim/lua/converter.h"  #include "nvim/lua/executor.h" @@ -63,6 +63,11 @@ typedef struct {      } \    } +#if __has_feature(address_sanitizer) +  PMap(handle_T) *nlua_ref_markers = NULL; +# define NLUA_TRACK_REFS +#endif +  /// Convert lua error into a Vim error message  ///  /// @param  lstate  Lua interpreter state. @@ -547,6 +552,13 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL  static lua_State *nlua_init(void)    FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT  { +#ifdef NLUA_TRACK_REFS +  const char *env = os_getenv("NVIM_LUA_NOTRACK"); +  if (!env || !*env) { +    nlua_ref_markers = pmap_new(handle_T)(); +  } +#endif +    lua_State *lstate = luaL_newstate();    if (lstate == NULL) {      EMSG(_("E970: Failed to initialize lua interpreter")); @@ -554,9 +566,13 @@ static lua_State *nlua_init(void)    }    luaL_openlibs(lstate);    nlua_state_init(lstate); +    return lstate;  } +// only to be used by nlua_enter and nlua_free_all_mem! +static lua_State *global_lstate = NULL; +  /// Enter lua interpreter  ///  /// Calls nlua_init() if needed. Is responsible for pre-lua call initalization @@ -567,26 +583,39 @@ static lua_State *nlua_init(void)  static lua_State *nlua_enter(void)    FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT  { -  static lua_State *global_lstate = NULL;    if (global_lstate == NULL) {      global_lstate = nlua_init();    }    lua_State *const lstate = global_lstate; -  // Last used p_rtp value. Must not be dereferenced because value pointed to -  // may already be freed. Used to check whether &runtimepath option value -  // changed. -  static const void *last_p_rtp = NULL; -  if (last_p_rtp != (const void *)p_rtp) { -    // stack: (empty) -    lua_getglobal(lstate, "vim"); -    // stack: vim -    lua_pop(lstate, 1); -    // stack: (empty) -    last_p_rtp = (const void *)p_rtp; -  }    return lstate;  } +void nlua_free_all_mem(void) +{ +  if (!global_lstate) { +    return; +  } +  lua_State *lstate = global_lstate; + +  nlua_unref(lstate, nlua_nil_ref); +  nlua_unref(lstate, nlua_empty_dict_ref); + +#ifdef NLUA_TRACK_REFS +  if (nlua_refcount) { +    fprintf(stderr, "%d lua references were leaked!", nlua_refcount); +  } + +  if (nlua_ref_markers) { +    // in case there are leaked luarefs, leak the associated memory +    // to get LeakSanitizer stacktraces on exit +    pmap_free(handle_T)(nlua_ref_markers); +  } +#endif + +  nlua_refcount = 0; +  lua_close(lstate); +} +  static void nlua_print_event(void **argv)  {    char *str = argv[0]; @@ -866,17 +895,35 @@ static int nlua_getenv(lua_State *lstate)  }  #endif +  /// add the value to the registry  LuaRef nlua_ref(lua_State *lstate, int index)  {    lua_pushvalue(lstate, index); -  return luaL_ref(lstate, LUA_REGISTRYINDEX); +  LuaRef ref = luaL_ref(lstate, LUA_REGISTRYINDEX); +  if (ref > 0) { +    nlua_refcount++; +#ifdef NLUA_TRACK_REFS +  if (nlua_ref_markers) { +    // dummy allocation to make LeakSanitizer track our luarefs +    pmap_put(handle_T)(nlua_ref_markers, ref, xmalloc(3)); +  } +#endif +  } +  return ref;  }  /// remove the value from the registry  void nlua_unref(lua_State *lstate, LuaRef ref)  {    if (ref > 0) { +    nlua_refcount--; +#ifdef NLUA_TRACK_REFS +    // NB: don't remove entry from map to track double-unref +    if (nlua_ref_markers) { +      xfree(pmap_get(handle_T)(nlua_ref_markers, ref)); +    } +#endif      luaL_unref(lstate, LUA_REGISTRYINDEX, ref);    }  } @@ -893,19 +940,11 @@ void nlua_pushref(lua_State *lstate, LuaRef ref)    lua_rawgeti(lstate, LUA_REGISTRYINDEX, ref);  } +  /// Gets a new reference to an object stored at original_ref  ///  /// NOTE: It does not copy the value, it creates a new ref to the lua object.  ///       Leaves the stack unchanged. -LuaRef nlua_newref(lua_State *lstate, LuaRef original_ref) -{ -  nlua_pushref(lstate, original_ref); -  LuaRef new_ref = nlua_ref(lstate, -1); -  lua_pop(lstate, 1); - -  return new_ref; -} -  LuaRef api_new_luaref(LuaRef original_ref)  {    if (original_ref == LUA_NOREF) { @@ -913,7 +952,10 @@ LuaRef api_new_luaref(LuaRef original_ref)    }    lua_State *const lstate = nlua_enter(); -  return nlua_newref(lstate, original_ref); +  nlua_pushref(lstate, original_ref); +  LuaRef new_ref = nlua_ref(lstate, -1); +  lua_pop(lstate, 1); +  return new_ref;  } @@ -1023,25 +1065,13 @@ int typval_exec_lua_callable(      typval_T *rettv  )  { -  int offset = 0;    LuaRef cb = lua_cb.func_ref; -  if (cb == LUA_NOREF) { -    // This shouldn't happen. -    luaL_error(lstate, "Invalid function passed to VimL"); -    return ERROR_OTHER; -  } -    nlua_pushref(lstate, cb); -  if (lua_cb.table_ref != LUA_NOREF) { -    offset += 1; -    nlua_pushref(lstate, lua_cb.table_ref); -  } -    PUSH_ALL_TYPVALS(lstate, argvars, argcount, false); -  if (lua_pcall(lstate, argcount + offset, 1, 0)) { +  if (lua_pcall(lstate, argcount, 1, 0)) {      nlua_print(lstate);      return ERROR_OTHER;    } @@ -1508,6 +1538,8 @@ static int regex_match_line(lua_State *lstate)    return nret;  } +// Required functions for lua c functions as VimL callbacks +  int nlua_CFunction_func_call(      int argcount,      typval_T *argvars, @@ -1517,53 +1549,40 @@ int nlua_CFunction_func_call(      lua_State *const lstate = nlua_enter();      LuaCFunctionState *funcstate = (LuaCFunctionState *)state; -    return typval_exec_lua_callable( -        lstate, -        funcstate->lua_callable, -        argcount, -        argvars, -        rettv); +    return typval_exec_lua_callable(lstate, funcstate->lua_callable, +                                    argcount, argvars, rettv);  } -/// Required functions for lua c functions as VimL callbacks +  void nlua_CFunction_func_free(void *state)  {      lua_State *const lstate = nlua_enter();      LuaCFunctionState *funcstate = (LuaCFunctionState *)state;      nlua_unref(lstate, funcstate->lua_callable.func_ref); -    nlua_unref(lstate, funcstate->lua_callable.table_ref);      xfree(funcstate);  }  bool nlua_is_table_from_lua(typval_T *const arg)  { -  if (arg->v_type != VAR_DICT && arg->v_type != VAR_LIST) { -    return false; -  } -    if (arg->v_type == VAR_DICT) { -    return arg->vval.v_dict->lua_table_ref > 0 -      && arg->vval.v_dict->lua_table_ref != LUA_NOREF; +    return arg->vval.v_dict->lua_table_ref != LUA_NOREF;    } else if (arg->v_type == VAR_LIST) { -    return arg->vval.v_list->lua_table_ref > 0 -      && arg->vval.v_list->lua_table_ref != LUA_NOREF; +    return arg->vval.v_list->lua_table_ref != LUA_NOREF; +  } else { +    return false;    } - -  return false;  }  char_u *nlua_register_table_as_callable(typval_T *const arg)  { -  if (!nlua_is_table_from_lua(arg)) { -    return NULL; -  } - -  LuaRef table_ref; +  LuaRef table_ref = LUA_NOREF;    if (arg->v_type == VAR_DICT) {      table_ref = arg->vval.v_dict->lua_table_ref;    } else if (arg->v_type == VAR_LIST) {      table_ref = arg->vval.v_list->lua_table_ref; -  } else { +  } + +  if (table_ref == LUA_NOREF) {      return NULL;    } @@ -1573,55 +1592,34 @@ char_u *nlua_register_table_as_callable(typval_T *const arg)    int top = lua_gettop(lstate);  #endif -  nlua_pushref(lstate, table_ref); +  nlua_pushref(lstate, table_ref);  // [table]    if (!lua_getmetatable(lstate, -1)) { +    lua_pop(lstate, 1); +    assert(top == lua_gettop(lstate));      return NULL; -  } +  }  // [table, mt] -  lua_getfield(lstate, -1, "__call"); +  lua_getfield(lstate, -1, "__call");  // [table, mt, mt.__call]    if (!lua_isfunction(lstate, -1)) { +    lua_pop(lstate, 3); +    assert(top == lua_gettop(lstate));      return NULL;    } - -  LuaRef new_table_ref = nlua_newref(lstate, table_ref); +  lua_pop(lstate, 2);  // [table]    LuaCFunctionState *state = xmalloc(sizeof(LuaCFunctionState));    state->lua_callable.func_ref = nlua_ref(lstate, -1); -  state->lua_callable.table_ref = new_table_ref; -  char_u *name = register_cfunc( -      &nlua_CFunction_func_call, -      &nlua_CFunction_func_free, -      state); +  char_u *name = register_cfunc(&nlua_CFunction_func_call, +                                &nlua_CFunction_func_free, state); -  lua_pop(lstate, 3); +  lua_pop(lstate, 1);  // []    assert(top == lua_gettop(lstate));    return name;  } -/// Helper function to free a list_T -void nlua_free_typval_list(list_T *const l) -{ -  if (l->lua_table_ref != LUA_NOREF && l->lua_table_ref > 0) { -    lua_State *const lstate = nlua_enter(); -    nlua_unref(lstate, l->lua_table_ref); -    l->lua_table_ref = LUA_NOREF; -  } -} - - -/// Helper function to free a dict_T -void nlua_free_typval_dict(dict_T *const d) -{ -  if (d->lua_table_ref != LUA_NOREF && d->lua_table_ref > 0) { -    lua_State *const lstate = nlua_enter(); -    nlua_unref(lstate, d->lua_table_ref); -    d->lua_table_ref = LUA_NOREF; -  } -} -  void nlua_execute_log_keystroke(int c)  {    char_u buf[NUMBUFLEN]; diff --git a/src/nvim/lua/executor.h b/src/nvim/lua/executor.h index 1d7a15d9aa..ea774ac2e3 100644 --- a/src/nvim/lua/executor.h +++ b/src/nvim/lua/executor.h @@ -16,6 +16,8 @@ void nlua_add_api_functions(lua_State *lstate) REAL_FATTR_NONNULL_ALL;  EXTERN LuaRef nlua_nil_ref INIT(= LUA_NOREF);  EXTERN LuaRef nlua_empty_dict_ref INIT(= LUA_NOREF); +EXTERN int nlua_refcount INIT(= 0); +  #define set_api_error(s, err) \      do { \        Error *err_ = (err); \ diff --git a/src/nvim/memory.c b/src/nvim/memory.c index 9bc6b23ce3..7a8fc4da75 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -19,6 +19,8 @@  #include "nvim/ui.h"  #include "nvim/sign.h"  #include "nvim/api/vim.h" +#include "nvim/lua/executor.h" +#include "nvim/decoration.h"  #ifdef UNIT_TESTING  # define malloc(size) mem_malloc(size) @@ -695,6 +697,10 @@ void free_all_mem(void)    list_free_log();    check_quickfix_busy(); + +  decor_free_all_mem(); + +  nlua_free_all_mem();  }  #endif  | 
