aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbfredl <bjorn.linse@gmail.com>2024-02-12 20:40:27 +0100
committerbfredl <bjorn.linse@gmail.com>2024-02-15 10:42:06 +0100
commitd60412b18e4e21f301baa2ac3f3fb7be89655e4b (patch)
tree2459531b83b937b6678ee7141badc27d0a331c29
parent0a51e7626a95a068c7bb00d0da28a701fed758da (diff)
downloadrneovim-d60412b18e4e21f301baa2ac3f3fb7be89655e4b.tar.gz
rneovim-d60412b18e4e21f301baa2ac3f3fb7be89655e4b.tar.bz2
rneovim-d60412b18e4e21f301baa2ac3f3fb7be89655e4b.zip
refactor(eval): use arena when converting typvals to Object
Note: this contains two _temporary_ changes which can be reverted once the Arena vs no-Arena distinction in API wrappers has been removed. Both nlua_push_Object and object_to_vim_take_luaref() has been changed to take the object argument as a pointer. This is not going to be necessary once these are only used with arena (or not at all) allocated Objects. The object_to_vim() variant which leaves luaref untouched might need to stay for a little longer.
-rw-r--r--src/nvim/api/buffer.c15
-rw-r--r--src/nvim/api/command.c32
-rw-r--r--src/nvim/api/deprecated.c32
-rw-r--r--src/nvim/api/private/converter.c95
-rw-r--r--src/nvim/api/private/helpers.c11
-rw-r--r--src/nvim/api/private/helpers.h1
-rw-r--r--src/nvim/api/tabpage.c8
-rw-r--r--src/nvim/api/ui.c8
-rw-r--r--src/nvim/api/vim.c29
-rw-r--r--src/nvim/api/vimscript.c16
-rw-r--r--src/nvim/api/window.c15
-rw-r--r--src/nvim/context.c18
-rw-r--r--src/nvim/eval.c2
-rw-r--r--src/nvim/eval/funcs.c42
-rw-r--r--src/nvim/generators/gen_api_dispatch.lua13
-rw-r--r--src/nvim/lua/converter.c18
-rw-r--r--src/nvim/lua/executor.c6
-rw-r--r--src/nvim/main.c2
-rw-r--r--src/nvim/mapping.c13
-rw-r--r--src/nvim/msgpack_rpc/channel.c6
-rw-r--r--src/nvim/msgpack_rpc/helpers.c23
-rw-r--r--src/nvim/terminal.c6
-rw-r--r--test/unit/api/private_helpers_spec.lua8
23 files changed, 227 insertions, 192 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 993e290b2d..110154f8de 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -869,7 +869,7 @@ Integer nvim_buf_get_offset(Buffer buffer, Integer index, Error *err)
/// @param name Variable name
/// @param[out] err Error details, if any
/// @return Variable value
-Object nvim_buf_get_var(Buffer buffer, String name, Error *err)
+Object nvim_buf_get_var(Buffer buffer, String name, Arena *arena, Error *err)
FUNC_API_SINCE(1)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -878,7 +878,7 @@ Object nvim_buf_get_var(Buffer buffer, String name, Error *err)
return (Object)OBJECT_INIT;
}
- return dict_get_value(buf->b_vars, name, err);
+ return dict_get_value(buf->b_vars, name, arena, err);
}
/// Gets a changed tick of a buffer
@@ -957,7 +957,7 @@ void nvim_buf_set_var(Buffer buffer, String name, Object value, Error *err)
return;
}
- dict_set_var(buf->b_vars, name, value, false, false, err);
+ dict_set_var(buf->b_vars, name, value, false, false, NULL, err);
}
/// Removes a buffer-scoped (b:) variable
@@ -974,7 +974,7 @@ void nvim_buf_del_var(Buffer buffer, String name, Error *err)
return;
}
- dict_set_var(buf->b_vars, name, NIL, true, false, err);
+ dict_set_var(buf->b_vars, name, NIL, true, false, NULL, err);
}
/// Gets the full file name for the buffer
@@ -1175,7 +1175,7 @@ Boolean nvim_buf_set_mark(Buffer buffer, String name, Integer line, Integer col,
/// uppercase/file mark set in another buffer.
/// @see |nvim_buf_set_mark()|
/// @see |nvim_buf_del_mark()|
-ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err)
+ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Arena *arena, Error *err)
FUNC_API_SINCE(1)
{
Array rv = ARRAY_DICT_INIT;
@@ -1205,8 +1205,9 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err)
pos = fm->mark;
}
- ADD(rv, INTEGER_OBJ(pos.lnum));
- ADD(rv, INTEGER_OBJ(pos.col));
+ rv = arena_array(arena, 2);
+ ADD_C(rv, INTEGER_OBJ(pos.lnum));
+ ADD_C(rv, INTEGER_OBJ(pos.col));
return rv;
}
diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c
index 0ac3d42231..a21c9e70a7 100644
--- a/src/nvim/api/command.c
+++ b/src/nvim/api/command.c
@@ -305,7 +305,7 @@ end:
/// - output: (boolean, default false) Whether to return command output.
/// @param[out] err Error details, if any.
/// @return Command output (non-error, non-shell |:!|) if `output` is true, else empty string.
-String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error *err)
+String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Arena *arena, Error *err)
FUNC_API_SINCE(10)
{
exarg_T ea;
@@ -343,7 +343,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
goto end;
});
- cmdname = string_to_cstr(cmd->cmd);
+ cmdname = arena_string(arena, cmd->cmd).data;
ea.cmd = cmdname;
char *p = find_ex_command(&ea, NULL);
@@ -352,9 +352,8 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
// autocommands defined, trigger the matching autocommands.
if (p != NULL && ea.cmdidx == CMD_SIZE && ASCII_ISUPPER(*ea.cmd)
&& has_event(EVENT_CMDUNDEFINED)) {
- p = xstrdup(cmdname);
+ p = arena_string(arena, cmd->cmd).data;
int ret = apply_autocmds(EVENT_CMDUNDEFINED, p, p, true, NULL);
- xfree(p);
// If the autocommands did something and didn't cause an error, try
// finding the command again.
p = (ret && !aborting()) ? find_ex_command(&ea, NULL) : ea.cmd;
@@ -383,28 +382,31 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
if (HAS_KEY(cmd, cmd, args)) {
// Process all arguments. Convert non-String arguments to String and check if String arguments
// have non-whitespace characters.
+ args = arena_array(arena, cmd->args.size);
for (size_t i = 0; i < cmd->args.size; i++) {
Object elem = cmd->args.items[i];
char *data_str;
switch (elem.type) {
case kObjectTypeBoolean:
- data_str = xcalloc(2, sizeof(char));
+ data_str = arena_alloc(arena, 2, false);
data_str[0] = elem.data.boolean ? '1' : '0';
data_str[1] = '\0';
+ ADD_C(args, CSTR_AS_OBJ(data_str));
break;
case kObjectTypeBuffer:
case kObjectTypeWindow:
case kObjectTypeTabpage:
case kObjectTypeInteger:
- data_str = xcalloc(NUMBUFLEN, sizeof(char));
+ data_str = arena_alloc(arena, NUMBUFLEN, false);
snprintf(data_str, NUMBUFLEN, "%" PRId64, elem.data.integer);
+ ADD_C(args, CSTR_AS_OBJ(data_str));
break;
case kObjectTypeString:
VALIDATE_EXP(!string_iswhite(elem.data.string), "command arg", "non-whitespace", NULL, {
goto end;
});
- data_str = string_to_cstr(elem.data.string);
+ ADD_C(args, elem);
break;
default:
VALIDATE_EXP(false, "command arg", "valid type", api_typename(elem.type), {
@@ -412,8 +414,6 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
});
break;
}
-
- ADD(args, CSTR_AS_OBJ(data_str));
}
bool argc_valid;
@@ -666,26 +666,20 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
}
if (opts->output && capture_local.ga_len > 1) {
- retv = (String){
- .data = capture_local.ga_data,
- .size = (size_t)capture_local.ga_len,
- };
+ // TODO(bfredl): if there are more cases like this we might want custom xfree-list in arena
+ retv = CBUF_TO_ARENA_STR(arena, capture_local.ga_data, (size_t)capture_local.ga_len);
// redir usually (except :echon) prepends a newline.
if (retv.data[0] == '\n') {
- memmove(retv.data, retv.data + 1, retv.size - 1);
- retv.data[retv.size - 1] = '\0';
- retv.size = retv.size - 1;
+ retv.data++;
+ retv.size--;
}
- goto end;
}
clear_ga:
if (opts->output) {
ga_clear(&capture_local);
}
end:
- api_free_array(args);
xfree(cmdline);
- xfree(cmdname);
xfree(ea.args);
xfree(ea.arglens);
diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c
index c9a6036b8f..9b8cacd7c2 100644
--- a/src/nvim/api/deprecated.c
+++ b/src/nvim/api/deprecated.c
@@ -362,7 +362,7 @@ void buffer_set_line_slice(Buffer buffer, Integer start, Integer end, Boolean in
///
/// @warning It may return nil if there was no previous value
/// or if previous value was `v:null`.
-Object buffer_set_var(Buffer buffer, String name, Object value, Error *err)
+Object buffer_set_var(Buffer buffer, String name, Object value, Arena *arena, Error *err)
FUNC_API_DEPRECATED_SINCE(1)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -371,7 +371,7 @@ Object buffer_set_var(Buffer buffer, String name, Object value, Error *err)
return NIL;
}
- return dict_set_var(buf->b_vars, name, value, false, true, err);
+ return dict_set_var(buf->b_vars, name, value, false, true, arena, err);
}
/// Removes a buffer-scoped (b:) variable
@@ -382,7 +382,7 @@ Object buffer_set_var(Buffer buffer, String name, Object value, Error *err)
/// @param name Variable name
/// @param[out] err Error details, if any
/// @return Old value
-Object buffer_del_var(Buffer buffer, String name, Error *err)
+Object buffer_del_var(Buffer buffer, String name, Arena *arena, Error *err)
FUNC_API_DEPRECATED_SINCE(1)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -391,7 +391,7 @@ Object buffer_del_var(Buffer buffer, String name, Error *err)
return NIL;
}
- return dict_set_var(buf->b_vars, name, NIL, true, true, err);
+ return dict_set_var(buf->b_vars, name, NIL, true, true, arena, err);
}
/// Sets a window-scoped (w:) variable
@@ -406,7 +406,7 @@ Object buffer_del_var(Buffer buffer, String name, Error *err)
///
/// @warning It may return nil if there was no previous value
/// or if previous value was `v:null`.
-Object window_set_var(Window window, String name, Object value, Error *err)
+Object window_set_var(Window window, String name, Object value, Arena *arena, Error *err)
FUNC_API_DEPRECATED_SINCE(1)
{
win_T *win = find_window_by_handle(window, err);
@@ -415,7 +415,7 @@ Object window_set_var(Window window, String name, Object value, Error *err)
return NIL;
}
- return dict_set_var(win->w_vars, name, value, false, true, err);
+ return dict_set_var(win->w_vars, name, value, false, true, arena, err);
}
/// Removes a window-scoped (w:) variable
@@ -426,7 +426,7 @@ Object window_set_var(Window window, String name, Object value, Error *err)
/// @param name variable name
/// @param[out] err Error details, if any
/// @return Old value
-Object window_del_var(Window window, String name, Error *err)
+Object window_del_var(Window window, String name, Arena *arena, Error *err)
FUNC_API_DEPRECATED_SINCE(1)
{
win_T *win = find_window_by_handle(window, err);
@@ -435,7 +435,7 @@ Object window_del_var(Window window, String name, Error *err)
return NIL;
}
- return dict_set_var(win->w_vars, name, NIL, true, true, err);
+ return dict_set_var(win->w_vars, name, NIL, true, true, arena, err);
}
/// Sets a tab-scoped (t:) variable
@@ -450,7 +450,7 @@ Object window_del_var(Window window, String name, Error *err)
///
/// @warning It may return nil if there was no previous value
/// or if previous value was `v:null`.
-Object tabpage_set_var(Tabpage tabpage, String name, Object value, Error *err)
+Object tabpage_set_var(Tabpage tabpage, String name, Object value, Arena *arena, Error *err)
FUNC_API_DEPRECATED_SINCE(1)
{
tabpage_T *tab = find_tab_by_handle(tabpage, err);
@@ -459,7 +459,7 @@ Object tabpage_set_var(Tabpage tabpage, String name, Object value, Error *err)
return NIL;
}
- return dict_set_var(tab->tp_vars, name, value, false, true, err);
+ return dict_set_var(tab->tp_vars, name, value, false, true, arena, err);
}
/// Removes a tab-scoped (t:) variable
@@ -470,7 +470,7 @@ Object tabpage_set_var(Tabpage tabpage, String name, Object value, Error *err)
/// @param name Variable name
/// @param[out] err Error details, if any
/// @return Old value
-Object tabpage_del_var(Tabpage tabpage, String name, Error *err)
+Object tabpage_del_var(Tabpage tabpage, String name, Arena *arena, Error *err)
FUNC_API_DEPRECATED_SINCE(1)
{
tabpage_T *tab = find_tab_by_handle(tabpage, err);
@@ -479,7 +479,7 @@ Object tabpage_del_var(Tabpage tabpage, String name, Error *err)
return NIL;
}
- return dict_set_var(tab->tp_vars, name, NIL, true, true, err);
+ return dict_set_var(tab->tp_vars, name, NIL, true, true, arena, err);
}
/// @deprecated
@@ -487,18 +487,18 @@ Object tabpage_del_var(Tabpage tabpage, String name, Error *err)
/// @warning May return nil if there was no previous value
/// OR if previous value was `v:null`.
/// @return Old value or nil if there was no previous value.
-Object vim_set_var(String name, Object value, Error *err)
+Object vim_set_var(String name, Object value, Arena *arena, Error *err)
FUNC_API_DEPRECATED_SINCE(1)
{
- return dict_set_var(&globvardict, name, value, false, true, err);
+ return dict_set_var(&globvardict, name, value, false, true, arena, err);
}
/// @deprecated
/// @see nvim_del_var
-Object vim_del_var(String name, Error *err)
+Object vim_del_var(String name, Arena *arena, Error *err)
FUNC_API_DEPRECATED_SINCE(1)
{
- return dict_set_var(&globvardict, name, NIL, true, true, err);
+ return dict_set_var(&globvardict, name, NIL, true, true, arena, err);
}
static int64_t convert_index(int64_t index)
diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c
index e7b8934c97..a70ef1e50b 100644
--- a/src/nvim/api/private/converter.c
+++ b/src/nvim/api/private/converter.c
@@ -19,6 +19,8 @@
/// Helper structure for vim_to_object
typedef struct {
kvec_withinit_t(Object, 2) stack; ///< Object stack.
+ Arena *arena; ///< arena where objects will be allocated
+ bool reuse_strdata;
} EncodedData;
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -41,12 +43,21 @@ typedef struct {
#define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \
kvi_push(edata->stack, FLOAT_OBJ((Float)(flt)))
+static Object typval_cbuf_to_obj(EncodedData *edata, const char *data, size_t len)
+{
+ if (edata->reuse_strdata) {
+ return STRING_OBJ(cbuf_as_string((char *)(len ? data : ""), len));
+ } else {
+ return CBUF_TO_ARENA_OBJ(edata->arena, data, len);
+ }
+}
+
#define TYPVAL_ENCODE_CONV_STRING(tv, str, len) \
do { \
const size_t len_ = (size_t)(len); \
const char *const str_ = (str); \
assert(len_ == 0 || str_ != NULL); \
- kvi_push(edata->stack, STRING_OBJ(cbuf_to_string((len_ ? str_ : ""), len_))); \
+ kvi_push(edata->stack, typval_cbuf_to_obj(edata, str_, len_)); \
} while (0)
#define TYPVAL_ENCODE_CONV_STR_STRING TYPVAL_ENCODE_CONV_STRING
@@ -58,10 +69,7 @@ typedef struct {
do { \
const size_t len_ = (size_t)(len); \
const blob_T *const blob_ = (blob); \
- kvi_push(edata->stack, STRING_OBJ(((String) { \
- .data = len_ != 0 ? xmemdupz(blob_->bv_ga.ga_data, len_) : xstrdup(""), \
- .size = len_ \
- }))); \
+ kvi_push(edata->stack, typval_cbuf_to_obj(edata, len_ ? blob_->bv_ga.ga_data : "", len_)); \
} while (0)
#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \
@@ -90,11 +98,7 @@ typedef struct {
static inline void typval_encode_list_start(EncodedData *const edata, const size_t len)
FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
{
- kvi_push(edata->stack, ARRAY_OBJ(((Array) {
- .capacity = len,
- .size = 0,
- .items = xmalloc(len * sizeof(*((Object)OBJECT_INIT).data.array.items)),
- })));
+ kvi_push(edata->stack, ARRAY_OBJ(arena_array(edata->arena, len)));
}
#define TYPVAL_ENCODE_CONV_LIST_START(tv, len) \
@@ -109,7 +113,7 @@ static inline void typval_encode_between_list_items(EncodedData *const edata)
Object *const list = &kv_last(edata->stack);
assert(list->type == kObjectTypeArray);
assert(list->data.array.size < list->data.array.capacity);
- list->data.array.items[list->data.array.size++] = item;
+ ADD_C(list->data.array, item);
}
#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(tv) \
@@ -131,11 +135,7 @@ static inline void typval_encode_list_end(EncodedData *const edata)
static inline void typval_encode_dict_start(EncodedData *const edata, const size_t len)
FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
{
- kvi_push(edata->stack, DICTIONARY_OBJ(((Dictionary) {
- .capacity = len,
- .size = 0,
- .items = xmalloc(len * sizeof(*((Object)OBJECT_INIT).data.dictionary.items)),
- })));
+ kvi_push(edata->stack, DICTIONARY_OBJ(arena_dict(edata->arena, len)));
}
#define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len) \
@@ -156,9 +156,8 @@ static inline void typval_encode_after_key(EncodedData *const edata)
dict->data.dictionary.items[dict->data.dictionary.size].key
= key.data.string;
} else {
- api_free_object(key);
dict->data.dictionary.items[dict->data.dictionary.size].key
- = STATIC_CSTR_TO_STRING("__INVALID_KEY__");
+ = STATIC_CSTR_AS_STRING("__INVALID_KEY__");
}
}
@@ -233,17 +232,22 @@ static inline void typval_encode_dict_end(EncodedData *const edata)
#undef TYPVAL_ENCODE_CONV_RECURSE
#undef TYPVAL_ENCODE_ALLOW_SPECIALS
-/// Convert a vim object to an `Object` instance, recursively expanding
+/// Convert a vim object to an `Object` instance, recursively converting
/// Arrays/Dictionaries.
///
/// @param obj The source object
+/// @param arena if NULL, use direct allocation
+/// @param reuse_strdata when true, don't copy string data to Arena but reference
+/// typval strings directly. takes no effect when arena is
+/// NULL
/// @return The converted value
-Object vim_to_object(typval_T *obj)
+Object vim_to_object(typval_T *obj, Arena *arena, bool reuse_strdata)
{
EncodedData edata;
kvi_init(edata.stack);
- const int evo_ret = encode_vim_to_object(&edata, obj,
- "vim_to_object argument");
+ edata.arena = arena;
+ edata.reuse_strdata = reuse_strdata;
+ const int evo_ret = encode_vim_to_object(&edata, obj, "vim_to_object argument");
(void)evo_ret;
assert(evo_ret == OK);
Object ret = kv_A(edata.stack, 0);
@@ -260,10 +264,18 @@ Object vim_to_object(typval_T *obj)
/// @param err Error object.
void object_to_vim(Object obj, typval_T *tv, Error *err)
{
+ object_to_vim_take_luaref(&obj, tv, false, err);
+}
+
+/// same as object_to_vim but consumes all luarefs (nested) in `obj`
+///
+/// useful when `obj` is allocated on an arena
+void object_to_vim_take_luaref(Object *obj, typval_T *tv, bool take_luaref, Error *err)
+{
tv->v_type = VAR_UNKNOWN;
tv->v_lock = VAR_UNLOCKED;
- switch (obj.type) {
+ switch (obj->type) {
case kObjectTypeNil:
tv->v_type = VAR_SPECIAL;
tv->vval.v_special = kSpecialVarNull;
@@ -271,41 +283,40 @@ void object_to_vim(Object obj, typval_T *tv, Error *err)
case kObjectTypeBoolean:
tv->v_type = VAR_BOOL;
- tv->vval.v_bool = obj.data.boolean ? kBoolVarTrue : kBoolVarFalse;
+ tv->vval.v_bool = obj->data.boolean ? kBoolVarTrue : kBoolVarFalse;
break;
case kObjectTypeBuffer:
case kObjectTypeWindow:
case kObjectTypeTabpage:
case kObjectTypeInteger:
- STATIC_ASSERT(sizeof(obj.data.integer) <= sizeof(varnumber_T),
+ STATIC_ASSERT(sizeof(obj->data.integer) <= sizeof(varnumber_T),
"Integer size must be <= Vimscript number size");
tv->v_type = VAR_NUMBER;
- tv->vval.v_number = (varnumber_T)obj.data.integer;
+ tv->vval.v_number = (varnumber_T)obj->data.integer;
break;
case kObjectTypeFloat:
tv->v_type = VAR_FLOAT;
- tv->vval.v_float = obj.data.floating;
+ tv->vval.v_float = obj->data.floating;
break;
case kObjectTypeString:
tv->v_type = VAR_STRING;
- if (obj.data.string.data == NULL) {
+ if (obj->data.string.data == NULL) {
tv->vval.v_string = NULL;
} else {
- tv->vval.v_string = xmemdupz(obj.data.string.data,
- obj.data.string.size);
+ tv->vval.v_string = xmemdupz(obj->data.string.data,
+ obj->data.string.size);
}
break;
case kObjectTypeArray: {
- list_T *const list = tv_list_alloc((ptrdiff_t)obj.data.array.size);
+ list_T *const list = tv_list_alloc((ptrdiff_t)obj->data.array.size);
- for (uint32_t i = 0; i < obj.data.array.size; i++) {
- Object item = obj.data.array.items[i];
+ for (uint32_t i = 0; i < obj->data.array.size; i++) {
typval_T li_tv;
- object_to_vim(item, &li_tv, err);
+ object_to_vim_take_luaref(&obj->data.array.items[i], &li_tv, take_luaref, err);
tv_list_append_owned_tv(list, li_tv);
}
tv_list_ref(list);
@@ -318,11 +329,11 @@ void object_to_vim(Object obj, typval_T *tv, Error *err)
case kObjectTypeDictionary: {
dict_T *const dict = tv_dict_alloc();
- for (uint32_t i = 0; i < obj.data.dictionary.size; i++) {
- KeyValuePair item = obj.data.dictionary.items[i];
- String key = item.key;
+ for (uint32_t i = 0; i < obj->data.dictionary.size; i++) {
+ KeyValuePair *item = &obj->data.dictionary.items[i];
+ String key = item->key;
dictitem_T *const di = tv_dict_item_alloc(key.data);
- object_to_vim(item.value, &di->di_tv, err);
+ object_to_vim_take_luaref(&item->value, &di->di_tv, take_luaref, err);
tv_dict_add(dict, di);
}
dict->dv_refcount++;
@@ -333,7 +344,13 @@ void object_to_vim(Object obj, typval_T *tv, Error *err)
}
case kObjectTypeLuaRef: {
- char *name = register_luafunc(api_new_luaref(obj.data.luaref));
+ LuaRef ref = obj->data.luaref;
+ if (take_luaref) {
+ obj->data.luaref = LUA_NOREF;
+ } else {
+ ref = api_new_luaref(ref);
+ }
+ char *name = register_luafunc(ref);
tv->v_type = VAR_FUNC;
tv->vval.v_string = xstrdup(name);
break;
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index 7bf0d87603..1446683b0c 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -175,7 +175,7 @@ bool try_end(Error *err)
/// @param dict The vimscript dict
/// @param key The key
/// @param[out] err Details of an error that may have occurred
-Object dict_get_value(dict_T *dict, String key, Error *err)
+Object dict_get_value(dict_T *dict, String key, Arena *arena, Error *err)
{
dictitem_T *const di = tv_dict_find(dict, key.data, (ptrdiff_t)key.size);
@@ -184,7 +184,7 @@ Object dict_get_value(dict_T *dict, String key, Error *err)
return (Object)OBJECT_INIT;
}
- return vim_to_object(&di->di_tv);
+ return vim_to_object(&di->di_tv, arena, true);
}
dictitem_T *dict_check_writable(dict_T *dict, String key, bool del, Error *err)
@@ -221,7 +221,8 @@ dictitem_T *dict_check_writable(dict_T *dict, String key, bool del, Error *err)
/// @param retval If true the old value will be converted and returned.
/// @param[out] err Details of an error that may have occurred
/// @return The old value if `retval` is true and the key was present, else NIL
-Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retval, Error *err)
+Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retval, Arena *arena,
+ Error *err)
{
Object rv = OBJECT_INIT;
dictitem_T *di = dict_check_writable(dict, key, del, err);
@@ -244,7 +245,7 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retva
}
// Return the old value
if (retval) {
- rv = vim_to_object(&di->di_tv);
+ rv = vim_to_object(&di->di_tv, arena, false);
}
// Delete the entry
tv_dict_item_remove(dict, di);
@@ -265,7 +266,7 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retva
} else {
// Return the old value
if (retval) {
- rv = vim_to_object(&di->di_tv);
+ rv = vim_to_object(&di->di_tv, arena, false);
}
bool type_error = false;
if (dict == &vimvardict
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h
index 11abb8f801..395c5a9d1f 100644
--- a/src/nvim/api/private/helpers.h
+++ b/src/nvim/api/private/helpers.h
@@ -35,6 +35,7 @@
#define CSTR_TO_ARENA_STR(arena, s) arena_string(arena, cstr_as_string(s))
#define CSTR_TO_ARENA_OBJ(arena, s) STRING_OBJ(CSTR_TO_ARENA_STR(arena, s))
#define CBUF_TO_ARENA_STR(arena, s, len) arena_string(arena, cbuf_as_string((char *)(s), len))
+#define CBUF_TO_ARENA_OBJ(arena, s, len) STRING_OBJ(CBUF_TO_ARENA_STR(arena, s, len))
#define BUFFER_OBJ(s) ((Object) { \
.type = kObjectTypeBuffer, \
diff --git a/src/nvim/api/tabpage.c b/src/nvim/api/tabpage.c
index fadc03b3e5..109075df8e 100644
--- a/src/nvim/api/tabpage.c
+++ b/src/nvim/api/tabpage.c
@@ -49,7 +49,7 @@ ArrayOf(Window) nvim_tabpage_list_wins(Tabpage tabpage, Error *err)
/// @param name Variable name
/// @param[out] err Error details, if any
/// @return Variable value
-Object nvim_tabpage_get_var(Tabpage tabpage, String name, Error *err)
+Object nvim_tabpage_get_var(Tabpage tabpage, String name, Arena *arena, Error *err)
FUNC_API_SINCE(1)
{
tabpage_T *tab = find_tab_by_handle(tabpage, err);
@@ -58,7 +58,7 @@ Object nvim_tabpage_get_var(Tabpage tabpage, String name, Error *err)
return (Object)OBJECT_INIT;
}
- return dict_get_value(tab->tp_vars, name, err);
+ return dict_get_value(tab->tp_vars, name, arena, err);
}
/// Sets a tab-scoped (t:) variable
@@ -76,7 +76,7 @@ void nvim_tabpage_set_var(Tabpage tabpage, String name, Object value, Error *err
return;
}
- dict_set_var(tab->tp_vars, name, value, false, false, err);
+ dict_set_var(tab->tp_vars, name, value, false, false, NULL, err);
}
/// Removes a tab-scoped (t:) variable
@@ -93,7 +93,7 @@ void nvim_tabpage_del_var(Tabpage tabpage, String name, Error *err)
return;
}
- dict_set_var(tab->tp_vars, name, NIL, true, false, err);
+ dict_set_var(tab->tp_vars, name, NIL, true, false, NULL, err);
}
/// Gets the current window in a tabpage
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index c7280253c2..140b520cb5 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -1029,12 +1029,12 @@ static Array translate_contents(UI *ui, Array contents, Arena *arena)
if (attr) {
Dictionary rgb_attrs = arena_dict(arena, HLATTRS_DICT_SIZE);
hlattrs2dict(&rgb_attrs, NULL, syn_attr2entry(attr), ui->rgb, false);
- ADD(new_item, DICTIONARY_OBJ(rgb_attrs));
+ ADD_C(new_item, DICTIONARY_OBJ(rgb_attrs));
} else {
- ADD(new_item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT));
+ ADD_C(new_item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT));
}
- ADD(new_item, item.items[1]);
- ADD(new_contents, ARRAY_OBJ(new_item));
+ ADD_C(new_item, item.items[1]);
+ ADD_C(new_contents, ARRAY_OBJ(new_item));
}
return new_contents;
}
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 769537ac98..b7cb14867d 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -690,7 +690,7 @@ void nvim_del_current_line(Error *err)
/// @param name Variable name
/// @param[out] err Error details, if any
/// @return Variable value
-Object nvim_get_var(String name, Error *err)
+Object nvim_get_var(String name, Arena *arena, Error *err)
FUNC_API_SINCE(1)
{
dictitem_T *di = tv_dict_find(&globvardict, name.data, (ptrdiff_t)name.size);
@@ -704,7 +704,7 @@ Object nvim_get_var(String name, Error *err)
VALIDATE((di != NULL), "Key not found: %s", name.data, {
return (Object)OBJECT_INIT;
});
- return vim_to_object(&di->di_tv);
+ return vim_to_object(&di->di_tv, arena, true);
}
/// Sets a global (g:) variable.
@@ -715,7 +715,7 @@ Object nvim_get_var(String name, Error *err)
void nvim_set_var(String name, Object value, Error *err)
FUNC_API_SINCE(1)
{
- dict_set_var(&globvardict, name, value, false, false, err);
+ dict_set_var(&globvardict, name, value, false, false, NULL, err);
}
/// Removes a global (g:) variable.
@@ -725,7 +725,7 @@ void nvim_set_var(String name, Object value, Error *err)
void nvim_del_var(String name, Error *err)
FUNC_API_SINCE(1)
{
- dict_set_var(&globvardict, name, NIL, true, false, err);
+ dict_set_var(&globvardict, name, NIL, true, false, NULL, err);
}
/// Gets a v: variable.
@@ -733,10 +733,10 @@ void nvim_del_var(String name, Error *err)
/// @param name Variable name
/// @param[out] err Error details, if any
/// @return Variable value
-Object nvim_get_vvar(String name, Error *err)
+Object nvim_get_vvar(String name, Arena *arena, Error *err)
FUNC_API_SINCE(1)
{
- return dict_get_value(&vimvardict, name, err);
+ return dict_get_value(&vimvardict, name, arena, err);
}
/// Sets a v: variable, if it is not readonly.
@@ -747,7 +747,7 @@ Object nvim_get_vvar(String name, Error *err)
void nvim_set_vvar(String name, Object value, Error *err)
FUNC_API_SINCE(6)
{
- dict_set_var(&vimvardict, name, value, false, false, err);
+ dict_set_var(&vimvardict, name, value, false, false, NULL, err);
}
/// Echo a message.
@@ -1370,7 +1370,7 @@ Dictionary nvim_get_color_map(Arena *arena)
/// @param[out] err Error details, if any
///
/// @return map of global |context|.
-Dictionary nvim_get_context(Dict(context) *opts, Error *err)
+Dictionary nvim_get_context(Dict(context) *opts, Arena *arena, Error *err)
FUNC_API_SINCE(6)
{
Array types = ARRAY_DICT_INIT;
@@ -1406,7 +1406,7 @@ Dictionary nvim_get_context(Dict(context) *opts, Error *err)
Context ctx = CONTEXT_INIT;
ctx_save(&ctx, int_types);
- Dictionary dict = ctx_to_dict(&ctx);
+ Dictionary dict = ctx_to_dict(&ctx, arena);
ctx_free(&ctx);
return dict;
}
@@ -2065,7 +2065,7 @@ Boolean nvim_del_mark(String name, Error *err)
/// not set.
/// @see |nvim_buf_set_mark()|
/// @see |nvim_del_mark()|
-Array nvim_get_mark(String name, Dict(empty) *opts, Error *err)
+Array nvim_get_mark(String name, Dict(empty) *opts, Arena *arena, Error *err)
FUNC_API_SINCE(8)
{
Array rv = ARRAY_DICT_INIT;
@@ -2113,10 +2113,11 @@ Array nvim_get_mark(String name, Dict(empty) *opts, Error *err)
col = pos.col;
}
- ADD(rv, INTEGER_OBJ(row));
- ADD(rv, INTEGER_OBJ(col));
- ADD(rv, INTEGER_OBJ(bufnr));
- ADD(rv, CSTR_TO_OBJ(filename));
+ rv = arena_array(arena, 4);
+ ADD_C(rv, INTEGER_OBJ(row));
+ ADD_C(rv, INTEGER_OBJ(col));
+ ADD_C(rv, INTEGER_OBJ(bufnr));
+ ADD_C(rv, CSTR_TO_ARENA_OBJ(arena, filename));
if (allocated) {
xfree(filename);
diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c
index 56541bb8b8..949356acc6 100644
--- a/src/nvim/api/vimscript.c
+++ b/src/nvim/api/vimscript.c
@@ -148,7 +148,7 @@ void nvim_command(String command, Error *err)
/// @param expr Vimscript expression string
/// @param[out] err Error details, if any
/// @return Evaluation result or expanded object
-Object nvim_eval(String expr, Error *err)
+Object nvim_eval(String expr, Arena *arena, Error *err)
FUNC_API_SINCE(1)
{
static int recursive = 0; // recursion depth
@@ -179,7 +179,7 @@ Object nvim_eval(String expr, Error *err)
api_set_error(err, kErrorTypeException,
"Failed to evaluate expression: '%.*s'", 256, expr.data);
} else {
- rv = vim_to_object(&rettv);
+ rv = vim_to_object(&rettv, arena, false);
}
}
@@ -196,7 +196,7 @@ Object nvim_eval(String expr, Error *err)
/// @param self `self` dict, or NULL for non-dict functions
/// @param[out] err Error details, if any
/// @return Result of the function call
-static Object _call_function(String fn, Array args, dict_T *self, Error *err)
+static Object _call_function(String fn, Array args, dict_T *self, Arena *arena, Error *err)
{
static int recursive = 0; // recursion depth
Object rv = OBJECT_INIT;
@@ -239,7 +239,7 @@ static Object _call_function(String fn, Array args, dict_T *self, Error *err)
});
if (!ERROR_SET(err)) {
- rv = vim_to_object(&rettv);
+ rv = vim_to_object(&rettv, arena, false);
}
tv_clear(&rettv);
@@ -260,10 +260,10 @@ static Object _call_function(String fn, Array args, dict_T *self, Error *err)
/// @param args Function arguments packed in an Array
/// @param[out] err Error details, if any
/// @return Result of the function call
-Object nvim_call_function(String fn, Array args, Error *err)
+Object nvim_call_function(String fn, Array args, Arena *arena, Error *err)
FUNC_API_SINCE(1)
{
- return _call_function(fn, args, NULL, err);
+ return _call_function(fn, args, NULL, arena, err);
}
/// Calls a Vimscript |Dictionary-function| with the given arguments.
@@ -275,7 +275,7 @@ Object nvim_call_function(String fn, Array args, Error *err)
/// @param args Function arguments packed in an Array
/// @param[out] err Error details, if any
/// @return Result of the function call
-Object nvim_call_dict_function(Object dict, String fn, Array args, Error *err)
+Object nvim_call_dict_function(Object dict, String fn, Array args, Arena *arena, Error *err)
FUNC_API_SINCE(4)
{
Object rv = OBJECT_INIT;
@@ -337,7 +337,7 @@ Object nvim_call_dict_function(Object dict, String fn, Array args, Error *err)
goto end;
}
- rv = _call_function(fn, args, self_dict, err);
+ rv = _call_function(fn, args, self_dict, arena, err);
end:
if (mustfree) {
tv_clear(&rettv);
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index 93c9dfa049..ed1ad5b583 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -237,7 +237,7 @@ void nvim_win_set_width(Window window, Integer width, Error *err)
/// @param name Variable name
/// @param[out] err Error details, if any
/// @return Variable value
-Object nvim_win_get_var(Window window, String name, Error *err)
+Object nvim_win_get_var(Window window, String name, Arena *arena, Error *err)
FUNC_API_SINCE(1)
{
win_T *win = find_window_by_handle(window, err);
@@ -246,7 +246,7 @@ Object nvim_win_get_var(Window window, String name, Error *err)
return (Object)OBJECT_INIT;
}
- return dict_get_value(win->w_vars, name, err);
+ return dict_get_value(win->w_vars, name, arena, err);
}
/// Sets a window-scoped (w:) variable
@@ -264,7 +264,7 @@ void nvim_win_set_var(Window window, String name, Object value, Error *err)
return;
}
- dict_set_var(win->w_vars, name, value, false, false, err);
+ dict_set_var(win->w_vars, name, value, false, false, NULL, err);
}
/// Removes a window-scoped (w:) variable
@@ -281,7 +281,7 @@ void nvim_win_del_var(Window window, String name, Error *err)
return;
}
- dict_set_var(win->w_vars, name, NIL, true, false, err);
+ dict_set_var(win->w_vars, name, NIL, true, false, NULL, err);
}
/// Gets the window position in display cells. First position is zero.
@@ -289,15 +289,16 @@ void nvim_win_del_var(Window window, String name, Error *err)
/// @param window Window handle, or 0 for current window
/// @param[out] err Error details, if any
/// @return (row, col) tuple with the window position
-ArrayOf(Integer, 2) nvim_win_get_position(Window window, Error *err)
+ArrayOf(Integer, 2) nvim_win_get_position(Window window, Arena *arena, Error *err)
FUNC_API_SINCE(1)
{
Array rv = ARRAY_DICT_INIT;
win_T *win = find_window_by_handle(window, err);
if (win) {
- ADD(rv, INTEGER_OBJ(win->w_winrow));
- ADD(rv, INTEGER_OBJ(win->w_wincol));
+ rv = arena_array(arena, 2);
+ ADD_C(rv, INTEGER_OBJ(win->w_winrow));
+ ADD_C(rv, INTEGER_OBJ(win->w_wincol));
}
return rv;
diff --git a/src/nvim/context.c b/src/nvim/context.c
index 7ce906b244..95e2618f62 100644
--- a/src/nvim/context.c
+++ b/src/nvim/context.c
@@ -296,7 +296,7 @@ static inline void ctx_restore_funcs(Context *ctx)
/// @param[in] sbuf msgpack_sbuffer to convert.
///
/// @return readfile()-style array representation of "sbuf".
-static inline Array sbuf_to_array(msgpack_sbuffer sbuf)
+static inline Array sbuf_to_array(msgpack_sbuffer sbuf, Arena *arena)
{
list_T *const list = tv_list_alloc(kListLenMayKnow);
tv_list_append_string(list, "", 0);
@@ -310,7 +310,7 @@ static inline Array sbuf_to_array(msgpack_sbuffer sbuf)
.vval.v_list = list
};
- Array array = vim_to_object(&list_tv).data.array;
+ Array array = vim_to_object(&list_tv, arena, false).data.array;
tv_clear(&list_tv);
return array;
}
@@ -346,18 +346,18 @@ static inline msgpack_sbuffer array_to_sbuf(Array array, Error *err)
/// @param[in] ctx Context to convert.
///
/// @return Dictionary representing "ctx".
-Dictionary ctx_to_dict(Context *ctx)
+Dictionary ctx_to_dict(Context *ctx, Arena *arena)
FUNC_ATTR_NONNULL_ALL
{
assert(ctx != NULL);
- Dictionary rv = ARRAY_DICT_INIT;
+ Dictionary rv = arena_dict(arena, 5);
- PUT(rv, "regs", ARRAY_OBJ(sbuf_to_array(ctx->regs)));
- PUT(rv, "jumps", ARRAY_OBJ(sbuf_to_array(ctx->jumps)));
- PUT(rv, "bufs", ARRAY_OBJ(sbuf_to_array(ctx->bufs)));
- PUT(rv, "gvars", ARRAY_OBJ(sbuf_to_array(ctx->gvars)));
- PUT(rv, "funcs", ARRAY_OBJ(copy_array(ctx->funcs, NULL)));
+ PUT_C(rv, "regs", ARRAY_OBJ(sbuf_to_array(ctx->regs, arena)));
+ PUT_C(rv, "jumps", ARRAY_OBJ(sbuf_to_array(ctx->jumps, arena)));
+ PUT_C(rv, "bufs", ARRAY_OBJ(sbuf_to_array(ctx->bufs, arena)));
+ PUT_C(rv, "gvars", ARRAY_OBJ(sbuf_to_array(ctx->gvars, arena)));
+ PUT_C(rv, "funcs", ARRAY_OBJ(copy_array(ctx->funcs, arena)));
return rv;
}
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index a4da582dca..4734e46362 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -1355,7 +1355,7 @@ Object eval_foldtext(win_T *wp)
retval = STRING_OBJ(NULL_STRING);
} else {
if (tv.v_type == VAR_LIST) {
- retval = vim_to_object(&tv);
+ retval = vim_to_object(&tv, NULL, false);
} else {
retval = STRING_OBJ(cstr_to_string(tv_get_string(&tv)));
}
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 726b9ce758..28365e16df 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -359,15 +359,15 @@ static void api_wrapper(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
MsgpackRpcRequestHandler handler = *fptr.api_handler;
- Array args = ARRAY_DICT_INIT;
+ MAXSIZE_TEMP_ARRAY(args, MAX_FUNC_ARGS);
+ Arena arena = ARENA_EMPTY;
for (typval_T *tv = argvars; tv->v_type != VAR_UNKNOWN; tv++) {
- ADD(args, vim_to_object(tv));
+ ADD_C(args, vim_to_object(tv, &arena, false));
}
Error err = ERROR_INIT;
- Arena res_arena = ARENA_EMPTY;
- Object result = handler.fn(VIML_INTERNAL_CALL, args, &res_arena, &err);
+ Object result = handler.fn(VIML_INTERNAL_CALL, args, &arena, &err);
if (ERROR_SET(&err)) {
semsg_multiline(e_api_error, err.msg);
@@ -377,12 +377,10 @@ static void api_wrapper(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
object_to_vim(result, rettv, &err);
end:
- api_free_array(args);
- if (handler.arena_return) {
- arena_mem_free(arena_finish(&res_arena));
- } else {
+ if (!handler.arena_return) {
api_free_object(result);
}
+ arena_mem_free(arena_finish(&arena));
api_clear_error(&err);
}
@@ -1037,10 +1035,11 @@ static void f_ctxget(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
return;
}
- Dictionary ctx_dict = ctx_to_dict(ctx);
+ Arena arena = ARENA_EMPTY;
+ Dictionary ctx_dict = ctx_to_dict(ctx, &arena);
Error err = ERROR_INIT;
object_to_vim(DICTIONARY_OBJ(ctx_dict), rettv, &err);
- api_free_dictionary(ctx_dict);
+ arena_mem_free(arena_finish(&arena));
api_clear_error(&err);
}
@@ -1108,7 +1107,8 @@ static void f_ctxset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
const int save_did_emsg = did_emsg;
did_emsg = false;
- Dictionary dict = vim_to_object(&argvars[0]).data.dictionary;
+ Arena arena = ARENA_EMPTY;
+ Dictionary dict = vim_to_object(&argvars[0], &arena, true).data.dictionary;
Context tmp = CONTEXT_INIT;
Error err = ERROR_INIT;
ctx_from_dict(dict, &tmp, &err);
@@ -1121,7 +1121,7 @@ static void f_ctxset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
*ctx = tmp;
}
- api_free_dictionary(dict);
+ arena_mem_free(arena_finish(&arena));
api_clear_error(&err);
did_emsg = save_did_emsg;
}
@@ -6883,16 +6883,17 @@ static void f_rpcnotify(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
return;
}
- Array args = ARRAY_DICT_INIT;
+ MAXSIZE_TEMP_ARRAY(args, MAX_FUNC_ARGS);
+ Arena arena = ARENA_EMPTY;
for (typval_T *tv = argvars + 2; tv->v_type != VAR_UNKNOWN; tv++) {
- ADD(args, vim_to_object(tv));
+ ADD_C(args, vim_to_object(tv, &arena, true));
}
bool ok = rpc_send_event((uint64_t)argvars[0].vval.v_number,
tv_get_string(&argvars[1]), args);
- api_free_array(args);
+ arena_mem_free(arena_finish(&arena));
if (!ok) {
semsg(_(e_invarg2), "Channel doesn't exist");
@@ -6922,10 +6923,11 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
return;
}
- Array args = ARRAY_DICT_INIT;
+ MAXSIZE_TEMP_ARRAY(args, MAX_FUNC_ARGS);
+ Arena arena = ARENA_EMPTY;
for (typval_T *tv = argvars + 2; tv->v_type != VAR_UNKNOWN; tv++) {
- ADD(args, vim_to_object(tv));
+ ADD_C(args, vim_to_object(tv, &arena, true));
}
sctx_T save_current_sctx;
@@ -6961,7 +6963,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
ArenaMem res_mem = NULL;
Object result = rpc_send_call(chan_id, method, args, &res_mem, &err);
- api_free_array(args);
+ arena_mem_free(arena_finish(&arena));
if (l_provider_call_nesting) {
current_sctx = save_current_sctx;
@@ -8868,10 +8870,10 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
Error err = ERROR_INIT;
// deprecated: use 'channel' buffer option
dict_set_var(curbuf->b_vars, cstr_as_string("terminal_job_id"),
- INTEGER_OBJ((Integer)chan->id), false, false, &err);
+ INTEGER_OBJ((Integer)chan->id), false, false, NULL, &err);
api_clear_error(&err);
dict_set_var(curbuf->b_vars, cstr_as_string("terminal_job_pid"),
- INTEGER_OBJ(pid), false, false, &err);
+ INTEGER_OBJ(pid), false, false, NULL, &err);
api_clear_error(&err);
channel_incref(chan);
diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua
index c16ea29a01..90ed90d2bc 100644
--- a/src/nvim/generators/gen_api_dispatch.lua
+++ b/src/nvim/generators/gen_api_dispatch.lua
@@ -845,15 +845,17 @@ exit_0:
write_shifted_output(' %s ret = %s(%s);\n', fn.return_type, fn.name, cparams)
local ret_type = real_type(fn.return_type)
+ local ret_mode = (ret_type == 'Object') and '&' or ''
if fn.has_lua_imp then
-- only push onto the Lua stack if we haven't already
write_shifted_output(string.format(
[[
if (lua_gettop(lstate) == 0) {
- nlua_push_%s(lstate, ret, true);
+ nlua_push_%s(lstate, %sret, true);
}
]],
- return_type
+ return_type,
+ ret_mode
))
elseif string.match(ret_type, '^KeyDict_') then
write_shifted_output(
@@ -862,7 +864,12 @@ exit_0:
)
else
local special = (fn.since ~= nil and fn.since < 11)
- write_shifted_output(' nlua_push_%s(lstate, ret, %s);\n', return_type, tostring(special))
+ write_shifted_output(
+ ' nlua_push_%s(lstate, %sret, %s);\n',
+ return_type,
+ ret_mode,
+ tostring(special)
+ )
end
-- NOTE: we currently assume err_throw needs nothing from arena
diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c
index 423d2fa775..0b7f58cec6 100644
--- a/src/nvim/lua/converter.c
+++ b/src/nvim/lua/converter.c
@@ -719,7 +719,7 @@ void nlua_push_Dictionary(lua_State *lstate, const Dictionary dict, bool special
}
for (size_t i = 0; i < dict.size; i++) {
nlua_push_String(lstate, dict.items[i].key, special);
- nlua_push_Object(lstate, dict.items[i].value, special);
+ nlua_push_Object(lstate, &dict.items[i].value, special);
lua_rawset(lstate, -3);
}
}
@@ -732,7 +732,7 @@ void nlua_push_Array(lua_State *lstate, const Array array, bool special)
{
lua_createtable(lstate, (int)array.size, 0);
for (size_t i = 0; i < array.size; i++) {
- nlua_push_Object(lstate, array.items[i], special);
+ nlua_push_Object(lstate, &array.items[i], special);
lua_rawseti(lstate, -2, (int)i + 1);
}
}
@@ -753,10 +753,10 @@ GENERATE_INDEX_FUNCTION(Tabpage)
/// Convert given Object to lua value
///
/// Leaves converted value on top of the stack.
-void nlua_push_Object(lua_State *lstate, const Object obj, bool special)
+void nlua_push_Object(lua_State *lstate, Object *obj, bool special)
FUNC_ATTR_NONNULL_ALL
{
- switch (obj.type) {
+ switch (obj->type) {
case kObjectTypeNil:
if (special) {
lua_pushnil(lstate);
@@ -765,12 +765,14 @@ void nlua_push_Object(lua_State *lstate, const Object obj, bool special)
}
break;
case kObjectTypeLuaRef: {
- nlua_pushref(lstate, obj.data.luaref);
+ nlua_pushref(lstate, obj->data.luaref);
+ api_free_luaref(obj->data.luaref);
+ obj->data.luaref = LUA_NOREF;
break;
}
#define ADD_TYPE(type, data_key) \
case kObjectType##type: { \
- nlua_push_##type(lstate, obj.data.data_key, special); \
+ nlua_push_##type(lstate, obj->data.data_key, special); \
break; \
}
ADD_TYPE(Boolean, boolean)
@@ -782,7 +784,7 @@ void nlua_push_Object(lua_State *lstate, const Object obj, bool special)
#undef ADD_TYPE
#define ADD_REMOTE_TYPE(type) \
case kObjectType##type: { \
- nlua_push_##type(lstate, (type)obj.data.integer, special); \
+ nlua_push_##type(lstate, (type)obj->data.integer, special); \
break; \
}
ADD_REMOTE_TYPE(Buffer)
@@ -1378,7 +1380,7 @@ void nlua_push_keydict(lua_State *L, void *value, KeySetLink *table)
lua_pushstring(L, field->str);
if (field->type == kObjectTypeNil) {
- nlua_push_Object(L, *(Object *)mem, false);
+ nlua_push_Object(L, (Object *)mem, false);
} else if (field->type == kObjectTypeInteger || field->type == kObjectTypeBuffer
|| field->type == kObjectTypeWindow || field->type == kObjectTypeTabpage) {
lua_pushinteger(L, *(Integer *)mem);
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index be55bde202..db44288b16 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -1260,7 +1260,7 @@ static int nlua_rpc(lua_State *lstate, bool request)
ArenaMem res_mem = NULL;
Object result = rpc_send_call(chan_id, name, args, &res_mem, &err);
if (!ERROR_SET(&err)) {
- nlua_push_Object(lstate, result, false);
+ nlua_push_Object(lstate, &result, false);
arena_mem_free(res_mem);
}
} else {
@@ -1563,7 +1563,7 @@ Object nlua_exec(const String str, const Array args, LuaRetMode mode, Arena *are
}
for (size_t i = 0; i < args.size; i++) {
- nlua_push_Object(lstate, args.items[i], false);
+ nlua_push_Object(lstate, &args.items[i], false);
}
if (nlua_pcall(lstate, (int)args.size, 1)) {
@@ -1610,7 +1610,7 @@ Object nlua_call_ref(LuaRef ref, const char *name, Array args, LuaRetMode mode,
nargs++;
}
for (size_t i = 0; i < args.size; i++) {
- nlua_push_Object(lstate, args.items[i], false);
+ nlua_push_Object(lstate, &args.items[i], false);
}
if (nlua_pcall(lstate, nargs, 1)) {
diff --git a/src/nvim/main.c b/src/nvim/main.c
index d712a45b81..1c4457ed9a 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -1102,7 +1102,7 @@ static void command_line_scan(mparm_T *parmp)
}
Object md = DICTIONARY_OBJ(api_metadata());
- msgpack_rpc_from_object(md, p);
+ msgpack_rpc_from_object(&md, p);
msgpack_packer_free(p);
const int ff_ret = file_flush(&fp);
diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c
index 59022e8be6..963f65148d 100644
--- a/src/nvim/mapping.c
+++ b/src/nvim/mapping.c
@@ -22,6 +22,7 @@
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
+#include "nvim/eval/userfunc.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_session.h"
#include "nvim/garray.h"
@@ -2305,13 +2306,13 @@ void f_mapset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
LuaRef rhs_lua = LUA_NOREF;
dictitem_T *callback_di = tv_dict_find(d, S_LEN("callback"));
if (callback_di != NULL) {
- Object callback_obj = vim_to_object(&callback_di->di_tv);
- if (callback_obj.type == kObjectTypeLuaRef && callback_obj.data.luaref != LUA_NOREF) {
- rhs_lua = callback_obj.data.luaref;
- orig_rhs = "";
- callback_obj.data.luaref = LUA_NOREF;
+ if (callback_di->di_tv.v_type == VAR_FUNC) {
+ ufunc_T *fp = find_func(callback_di->di_tv.vval.v_string);
+ if (fp != NULL && (fp->uf_flags & FC_LUAREF)) {
+ rhs_lua = api_new_luaref(fp->uf_luaref);
+ orig_rhs = "";
+ }
}
- api_free_object(callback_obj);
}
if (lhs == NULL || lhsraw == NULL || orig_rhs == NULL) {
emsg(_(e_entries_missing_in_mapset_dict_argument));
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index 2224403fa2..b411854387 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -449,7 +449,7 @@ static void request_event(void **argv)
e->type,
e->request_id,
&error,
- result,
+ &result,
&out_buffer));
}
if (!handler.arena_return) {
@@ -538,7 +538,7 @@ static void send_error(Channel *chan, MsgpackRpcRequestHandler handler, MessageT
type,
id,
&e,
- NIL,
+ &NIL,
&out_buffer));
api_clear_error(&e);
}
@@ -669,7 +669,7 @@ static WBuffer *serialize_request(uint64_t channel_id, uint32_t request_id, cons
}
static WBuffer *serialize_response(uint64_t channel_id, MsgpackRpcRequestHandler handler,
- MessageType type, uint32_t response_id, Error *err, Object arg,
+ MessageType type, uint32_t response_id, Error *err, Object *arg,
msgpack_sbuffer *sbuffer)
{
msgpack_packer pac;
diff --git a/src/nvim/msgpack_rpc/helpers.c b/src/nvim/msgpack_rpc/helpers.c
index 3162269df6..6caf50d319 100644
--- a/src/nvim/msgpack_rpc/helpers.c
+++ b/src/nvim/msgpack_rpc/helpers.c
@@ -10,6 +10,7 @@
#include "msgpack/pack.h"
#include "nvim/api/private/helpers.h"
#include "nvim/assert_defs.h"
+#include "nvim/lua/executor.h"
#include "nvim/memory.h"
#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/types_defs.h"
@@ -309,34 +310,40 @@ static void msgpack_rpc_from_handle(ObjectType type, Integer o, msgpack_packer *
}
typedef struct {
- const Object *aobj;
+ Object *aobj;
bool container;
size_t idx;
} APIToMPObjectStackItem;
/// Convert type used by Nvim API to msgpack type.
///
+/// consumes (frees) any luaref inside `result`, even though they are not used
+/// (just represented as NIL)
+///
/// @param[in] result Object to convert.
/// @param[out] res Structure that defines where conversion results are saved.
///
/// @return true in case of success, false otherwise.
-void msgpack_rpc_from_object(const Object result, msgpack_packer *const res)
+void msgpack_rpc_from_object(Object *result, msgpack_packer *const res)
FUNC_ATTR_NONNULL_ARG(2)
{
kvec_withinit_t(APIToMPObjectStackItem, 2) stack = KV_INITIAL_VALUE;
kvi_init(stack);
- kvi_push(stack, ((APIToMPObjectStackItem) { &result, false, 0 }));
+ kvi_push(stack, ((APIToMPObjectStackItem) { result, false, 0 }));
while (kv_size(stack)) {
APIToMPObjectStackItem cur = kv_last(stack);
STATIC_ASSERT(kObjectTypeWindow == kObjectTypeBuffer + 1
&& kObjectTypeTabpage == kObjectTypeWindow + 1,
"Buffer, window and tabpage enum items are in order");
switch (cur.aobj->type) {
- case kObjectTypeNil:
case kObjectTypeLuaRef:
// TODO(bfredl): could also be an error. Though kObjectTypeLuaRef
// should only appear when the caller has opted in to handle references,
// see nlua_pop_Object.
+ api_free_luaref(cur.aobj->data.luaref);
+ cur.aobj->data.luaref = LUA_NOREF;
+ FALLTHROUGH;
+ case kObjectTypeNil:
msgpack_pack_nil(res);
break;
case kObjectTypeBoolean:
@@ -415,7 +422,7 @@ void msgpack_rpc_from_array(Array result, msgpack_packer *res)
msgpack_pack_array(res, result.size);
for (size_t i = 0; i < result.size; i++) {
- msgpack_rpc_from_object(result.items[i], res);
+ msgpack_rpc_from_object(&result.items[i], res);
}
}
@@ -426,7 +433,7 @@ void msgpack_rpc_from_dictionary(Dictionary result, msgpack_packer *res)
for (size_t i = 0; i < result.size; i++) {
msgpack_rpc_from_string(result.items[i].key, res);
- msgpack_rpc_from_object(result.items[i].value, res);
+ msgpack_rpc_from_object(&result.items[i].value, res);
}
}
@@ -447,9 +454,9 @@ void msgpack_rpc_serialize_request(uint32_t request_id, const String method, Arr
}
/// Serializes a msgpack-rpc response
-void msgpack_rpc_serialize_response(uint32_t response_id, Error *err, Object arg,
+void msgpack_rpc_serialize_response(uint32_t response_id, Error *err, Object *arg,
msgpack_packer *pac)
- FUNC_ATTR_NONNULL_ARG(2, 4)
+ FUNC_ATTR_NONNULL_ALL
{
msgpack_pack_array(pac, 4);
msgpack_pack_int(pac, 1);
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 499f31454e..5e023c10d1 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -343,7 +343,6 @@ void terminal_open(Terminal **termpp, buf_T *buf, TerminalOptions opts)
if (name) {
int dummy;
RgbValue color_val = name_to_color(name, &dummy);
- xfree(name);
if (color_val != -1) {
VTermColor color;
@@ -1003,6 +1002,7 @@ static void buf_set_term_title(buf_T *buf, const char *title, size_t len)
STRING_OBJ(((String){ .data = (char *)title, .size = len })),
false,
false,
+ NULL,
&err);
api_clear_error(&err);
status_redraw_buf(buf);
@@ -1883,10 +1883,10 @@ static char *get_config_string(char *key)
{
Error err = ERROR_INIT;
// Only called from terminal_open where curbuf->terminal is the context.
- Object obj = dict_get_value(curbuf->b_vars, cstr_as_string(key), &err);
+ Object obj = dict_get_value(curbuf->b_vars, cstr_as_string(key), NULL, &err);
api_clear_error(&err);
if (obj.type == kObjectTypeNil) {
- obj = dict_get_value(&globvardict, cstr_as_string(key), &err);
+ obj = dict_get_value(&globvardict, cstr_as_string(key), NULL, &err);
api_clear_error(&err);
}
if (obj.type == kObjectTypeString) {
diff --git a/test/unit/api/private_helpers_spec.lua b/test/unit/api/private_helpers_spec.lua
index 80ca9ddc5b..9843bd5c9e 100644
--- a/test/unit/api/private_helpers_spec.lua
+++ b/test/unit/api/private_helpers_spec.lua
@@ -22,7 +22,7 @@ local api = cimport('./src/nvim/api/private/helpers.h', './src/nvim/api/private/
describe('vim_to_object', function()
local vim_to_object = function(l)
- return obj2lua(api.vim_to_object(lua2typvalt(l)))
+ return obj2lua(api.vim_to_object(lua2typvalt(l), nil, false))
end
local different_output_test = function(name, input, output)
@@ -92,13 +92,13 @@ describe('vim_to_object', function()
itp('outputs empty list for NULL list', function()
local tt = typvalt('VAR_LIST', { v_list = NULL })
eq(nil, tt.vval.v_list)
- eq({ [type_key] = list_type }, obj2lua(api.vim_to_object(tt)))
+ eq({ [type_key] = list_type }, obj2lua(api.vim_to_object(tt, nil, false)))
end)
itp('outputs empty dict for NULL dict', function()
local tt = typvalt('VAR_DICT', { v_dict = NULL })
eq(nil, tt.vval.v_dict)
- eq({}, obj2lua(api.vim_to_object(tt)))
+ eq({}, obj2lua(api.vim_to_object(tt, nil, false)))
end)
itp('regression: partials in a list', function()
@@ -113,6 +113,6 @@ describe('vim_to_object', function()
}
local list = lua2typvalt(llist)
eq(llist, typvalt2lua(list))
- eq({ nil_value, {} }, obj2lua(api.vim_to_object(list)))
+ eq({ nil_value, {} }, obj2lua(api.vim_to_object(list, nil, false)))
end)
end)