perf(api): allow to use an arena for return values

This commit is contained in:
bfredl
2022-08-23 09:33:08 +02:00
parent baaaa1f2b3
commit c0d6052654
36 changed files with 584 additions and 497 deletions

View File

@@ -801,7 +801,7 @@ def extract_from_xml(filename, target, width, fmt_vimhelp):
prefix = '%s(' % name prefix = '%s(' % name
suffix = '%s)' % ', '.join('{%s}' % a[1] for a in params suffix = '%s)' % ', '.join('{%s}' % a[1] for a in params
if a[0] not in ('void', 'Error')) if a[0] not in ('void', 'Error', 'Arena'))
if not fmt_vimhelp: if not fmt_vimhelp:
c_decl = '%s %s(%s);' % (return_type, name, ', '.join(c_args)) c_decl = '%s %s(%s);' % (return_type, name, ', '.join(c_args))

View File

@@ -1021,7 +1021,7 @@ void nvim_buf_del_var(Buffer buffer, String name, Error *err)
/// @param buffer Buffer handle, or 0 for current buffer /// @param buffer Buffer handle, or 0 for current buffer
/// @param[out] err Error details, if any /// @param[out] err Error details, if any
/// @return Buffer name /// @return Buffer name
String nvim_buf_get_name(Buffer buffer, Error *err) String nvim_buf_get_name(Buffer buffer, Arena *arena, Error *err)
FUNC_API_SINCE(1) FUNC_API_SINCE(1)
{ {
String rv = STRING_INIT; String rv = STRING_INIT;
@@ -1031,7 +1031,7 @@ String nvim_buf_get_name(Buffer buffer, Error *err)
return rv; return rv;
} }
return cstr_to_string((char *)buf->b_ffname); return cstr_as_string((char *)buf->b_ffname);
} }
/// Sets the full file name for a buffer /// Sets the full file name for a buffer

View File

@@ -5,18 +5,23 @@
typedef Object (*ApiDispatchWrapper)(uint64_t channel_id, typedef Object (*ApiDispatchWrapper)(uint64_t channel_id,
Array args, Array args,
Arena *arena,
Error *error); Error *error);
/// The rpc_method_handlers table, used in msgpack_rpc_dispatch(), stores /// The rpc_method_handlers table, used in msgpack_rpc_dispatch(), stores
/// functions of this type. /// functions of this type.
typedef struct { struct MsgpackRpcRequestHandler {
const char *name; const char *name;
ApiDispatchWrapper fn; ApiDispatchWrapper fn;
bool fast; // Function is safe to be executed immediately while running the bool fast; // Function is safe to be executed immediately while running the
// uv loop (the loop is run very frequently due to breakcheck). // uv loop (the loop is run very frequently due to breakcheck).
// If "fast" is false, the function is deferred, i e the call will // If "fast" is false, the function is deferred, i e the call will
// be put in the event queue, for safe handling later. // be put in the event queue, for safe handling later.
} MsgpackRpcRequestHandler; bool arena_return; // return value is allocated in the arena (or statically)
// and should not be freed as such.
};
extern const MsgpackRpcRequestHandler method_handlers[];
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/private/dispatch.h.generated.h" # include "api/private/dispatch.h.generated.h"

View File

@@ -1629,11 +1629,11 @@ Array nvim_list_chans(void)
/// an error, it is a three-element array with the zero-based index of the call /// an error, it is a three-element array with the zero-based index of the call
/// which resulted in an error, the error type and the error message. If an /// which resulted in an error, the error type and the error message. If an
/// error occurred, the values from all preceding calls will still be returned. /// error occurred, the values from all preceding calls will still be returned.
Array nvim_call_atomic(uint64_t channel_id, Array calls, Error *err) Array nvim_call_atomic(uint64_t channel_id, Array calls, Arena *arena, Error *err)
FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
{ {
Array rv = ARRAY_DICT_INIT; Array rv = arena_array(arena, 2);
Array results = ARRAY_DICT_INIT; Array results = arena_array(arena, calls.size);
Error nested_error = ERROR_INIT; Error nested_error = ERROR_INIT;
size_t i; // also used for freeing the variables size_t i; // also used for freeing the variables
@@ -1676,29 +1676,32 @@ Array nvim_call_atomic(uint64_t channel_id, Array calls, Error *err)
if (ERROR_SET(&nested_error)) { if (ERROR_SET(&nested_error)) {
break; break;
} }
Object result = handler.fn(channel_id, args, &nested_error);
Object result = handler.fn(channel_id, args, arena, &nested_error);
if (ERROR_SET(&nested_error)) { if (ERROR_SET(&nested_error)) {
// error handled after loop // error handled after loop
break; break;
} }
if (!handler.arena_return && result.type != kObjectTypeNil) {
ADD(results, result); // TODO: fix to not leak memory as fuck
} }
ADD(rv, ARRAY_OBJ(results)); ADD_C(results, result);
}
ADD_C(rv, ARRAY_OBJ(results));
if (ERROR_SET(&nested_error)) { if (ERROR_SET(&nested_error)) {
Array errval = ARRAY_DICT_INIT; Array errval = arena_array(arena, 3);
ADD(errval, INTEGER_OBJ((Integer)i)); ADD_C(errval, INTEGER_OBJ((Integer)i));
ADD(errval, INTEGER_OBJ(nested_error.type)); ADD_C(errval, INTEGER_OBJ(nested_error.type));
ADD(errval, STRING_OBJ(cstr_to_string(nested_error.msg))); ADD_C(errval, STRING_OBJ(cstr_to_string(nested_error.msg))); // TODO
ADD(rv, ARRAY_OBJ(errval)); ADD_C(rv, ARRAY_OBJ(errval));
} else { } else {
ADD(rv, NIL); ADD_C(rv, NIL);
} }
goto theend; goto theend;
validation_error: validation_error:
api_free_array(results);
theend: theend:
api_clear_error(&nested_error); api_clear_error(&nested_error);
return rv; return rv;
@@ -1803,6 +1806,7 @@ Dictionary nvim__stats(void)
PUT(rv, "log_skip", INTEGER_OBJ(g_stats.log_skip)); PUT(rv, "log_skip", INTEGER_OBJ(g_stats.log_skip));
PUT(rv, "lua_refcount", INTEGER_OBJ(nlua_get_global_ref_count())); PUT(rv, "lua_refcount", INTEGER_OBJ(nlua_get_global_ref_count()));
PUT(rv, "redraw", INTEGER_OBJ(g_stats.redraw)); PUT(rv, "redraw", INTEGER_OBJ(g_stats.redraw));
PUT(rv, "arena_alloc_count", INTEGER_OBJ((Integer)arena_alloc_count));
return rv; return rv;
} }

View File

@@ -1074,7 +1074,7 @@ char *arg_all(void)
} }
/// "argc([window id])" function /// "argc([window id])" function
void f_argc(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_argc(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
if (argvars[0].v_type == VAR_UNKNOWN) { if (argvars[0].v_type == VAR_UNKNOWN) {
// use the current window // use the current window
@@ -1095,13 +1095,13 @@ void f_argc(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "argidx()" function /// "argidx()" function
void f_argidx(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_argidx(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
rettv->vval.v_number = curwin->w_arg_idx; rettv->vval.v_number = curwin->w_arg_idx;
} }
/// "arglistid()" function /// "arglistid()" function
void f_arglistid(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_arglistid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
rettv->vval.v_number = -1; rettv->vval.v_number = -1;
win_T *wp = find_tabwin(&argvars[0], &argvars[1]); win_T *wp = find_tabwin(&argvars[0], &argvars[1]);
@@ -1123,7 +1123,7 @@ static void get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rett
} }
/// "argv(nr)" function /// "argv(nr)" function
void f_argv(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_argv(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
aentry_T *arglist = NULL; aentry_T *arglist = NULL;
int argcount = -1; int argcount = -1;

View File

@@ -2751,7 +2751,7 @@ void wildmenu_cleanup(CmdlineInfo *cclp)
} }
/// "getcompletion()" function /// "getcompletion()" function
void f_getcompletion(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_getcompletion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
char_u *pat; char_u *pat;
expand_T xpc; expand_T xpc;

View File

@@ -494,7 +494,7 @@ static int del_history_idx(int histype, int idx)
} }
/// "histadd()" function /// "histadd()" function
void f_histadd(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_histadd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
HistoryType histype; HistoryType histype;
@@ -517,7 +517,7 @@ void f_histadd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "histdel()" function /// "histdel()" function
void f_histdel(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_histdel(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
int n; int n;
const char *const str = tv_get_string_chk(&argvars[0]); // NULL on type error const char *const str = tv_get_string_chk(&argvars[0]); // NULL on type error
@@ -540,7 +540,7 @@ void f_histdel(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "histget()" function /// "histget()" function
void f_histget(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_histget(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
HistoryType type; HistoryType type;
int idx; int idx;
@@ -562,7 +562,7 @@ void f_histget(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "histnr()" function /// "histnr()" function
void f_histnr(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_histnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
const char *const histname = tv_get_string_chk(&argvars[0]); const char *const histname = tv_get_string_chk(&argvars[0]);
HistoryType i = histname == NULL HistoryType i = histname == NULL

View File

@@ -1917,7 +1917,7 @@ static bool digraph_set_common(const typval_T *argchars, const typval_T *argdigr
} }
/// "digraph_get()" function /// "digraph_get()" function
void f_digraph_get(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_digraph_get(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
rettv->v_type = VAR_STRING; rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL; // Return empty string for failure rettv->vval.v_string = NULL; // Return empty string for failure
@@ -1938,7 +1938,7 @@ void f_digraph_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "digraph_getlist()" function /// "digraph_getlist()" function
void f_digraph_getlist(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_digraph_getlist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
bool flag_list_all; bool flag_list_all;
@@ -1957,7 +1957,7 @@ void f_digraph_getlist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "digraph_set()" function /// "digraph_set()" function
void f_digraph_set(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_digraph_set(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
rettv->v_type = VAR_BOOL; rettv->v_type = VAR_BOOL;
rettv->vval.v_bool = kBoolVarFalse; rettv->vval.v_bool = kBoolVarFalse;
@@ -1970,7 +1970,7 @@ void f_digraph_set(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "digraph_setlist()" function /// "digraph_setlist()" function
void f_digraph_setlist(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_digraph_setlist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
rettv->v_type = VAR_BOOL; rettv->v_type = VAR_BOOL;
rettv->vval.v_bool = kBoolVarFalse; rettv->vval.v_bool = kBoolVarFalse;

View File

@@ -4968,7 +4968,7 @@ theend:
return retval; return retval;
} }
void common_function(typval_T *argvars, typval_T *rettv, bool is_funcref, FunPtr fptr) void common_function(typval_T *argvars, typval_T *rettv, bool is_funcref)
{ {
char *s; char *s;
char *name; char *name;

View File

@@ -23,7 +23,7 @@ end
return { return {
funcs={ funcs={
abs={args=1, base=1}, abs={args=1, base=1},
acos={args=1, base=1, func="float_op_wrapper", data="&acos"}, -- WJMc acos={args=1, base=1, float_func="acos"}, -- WJMc
add={args=2, base=1}, add={args=2, base=1},
['and']={args=2, base=1}, ['and']={args=2, base=1},
api_info={}, api_info={},
@@ -33,7 +33,7 @@ return {
argidx={}, argidx={},
arglistid={args={0, 2}}, arglistid={args={0, 2}},
argv={args={0, 2}}, argv={args={0, 2}},
asin={args=1, base=1, func="float_op_wrapper", data="&asin"}, -- WJMc asin={args=1, base=1, float_func="asin"}, -- WJMc
assert_beeps={args=1, base=1}, assert_beeps={args=1, base=1},
assert_equal={args={2, 3}, base=2}, assert_equal={args={2, 3}, base=2},
assert_equalfile={args={2, 3}, base=1}, assert_equalfile={args={2, 3}, base=1},
@@ -47,7 +47,7 @@ return {
assert_notmatch={args={2, 3}, base=2}, assert_notmatch={args={2, 3}, base=2},
assert_report={args=1, base=1}, assert_report={args=1, base=1},
assert_true={args={1, 2}, base=1}, assert_true={args={1, 2}, base=1},
atan={args=1, base=1, func="float_op_wrapper", data="&atan"}, atan={args=1, base=1, float_func="atan"},
atan2={args=2, base=1}, atan2={args=2, base=1},
browse={args=4}, browse={args=4},
browsedir={args=2}, browsedir={args=2},
@@ -67,7 +67,7 @@ return {
byteidx={args=2, base=1}, byteidx={args=2, base=1},
byteidxcomp={args=2, base=1}, byteidxcomp={args=2, base=1},
call={args={2, 3}, base=1}, call={args={2, 3}, base=1},
ceil={args=1, base=1, func="float_op_wrapper", data="&ceil"}, ceil={args=1, base=1, float_func="ceil"},
changenr={}, changenr={},
chanclose={args={1, 2}}, chanclose={args={1, 2}},
chansend={args=2}, chansend={args=2},
@@ -85,8 +85,8 @@ return {
complete_info={args={0, 1}, base=1}, complete_info={args={0, 1}, base=1},
confirm={args={1, 4}, base=1}, confirm={args={1, 4}, base=1},
copy={args=1, base=1}, copy={args=1, base=1},
cos={args=1, base=1, func="float_op_wrapper", data="&cos"}, cos={args=1, base=1, float_func="cos"},
cosh={args=1, base=1, func="float_op_wrapper", data="&cosh"}, cosh={args=1, base=1, float_func="cosh"},
count={args={2, 4}, base=1}, count={args={2, 4}, base=1},
cscope_connection={args={0, 3}}, cscope_connection={args={0, 3}},
ctxget={args={0, 1}}, ctxget={args={0, 1}},
@@ -117,7 +117,7 @@ return {
execute={args={1, 2}, base=1}, execute={args={1, 2}, base=1},
exepath={args=1, base=1}, exepath={args=1, base=1},
exists={args=1, base=1}, exists={args=1, base=1},
exp={args=1, base=1, func="float_op_wrapper", data="&exp"}, exp={args=1, base=1, float_func="exp"},
expand={args={1, 3}, base=1}, expand={args={1, 3}, base=1},
expandcmd={args=1, base=1}, expandcmd={args=1, base=1},
extend={args={2, 3}, base=1}, extend={args={2, 3}, base=1},
@@ -130,7 +130,7 @@ return {
findfile={args={1, 3}, base=1}, findfile={args={1, 3}, base=1},
flatten={args={1, 2}, base=1}, flatten={args={1, 2}, base=1},
float2nr={args=1, base=1}, float2nr={args=1, base=1},
floor={args=1, base=1, func="float_op_wrapper", data="&floor"}, floor={args=1, base=1, float_func="floor"},
fmod={args=2, base=1}, fmod={args=2, base=1},
fnameescape={args=1, base=1}, fnameescape={args=1, base=1},
fnamemodify={args=2, base=1}, fnamemodify={args=2, base=1},
@@ -245,8 +245,8 @@ return {
lispindent={args=1, base=1}, lispindent={args=1, base=1},
list2str={args={1, 2}, base=1}, list2str={args={1, 2}, base=1},
localtime={}, localtime={},
log={args=1, base=1, func="float_op_wrapper", data="&log"}, log={args=1, base=1, float_func="log"},
log10={args=1, base=1, func="float_op_wrapper", data="&log10"}, log10={args=1, base=1, float_func="log10"},
luaeval={args={1, 2}, base=1}, luaeval={args={1, 2}, base=1},
map={args=2, base=1}, map={args=2, base=1},
maparg={args={1, 4}, base=1}, maparg={args={1, 4}, base=1},
@@ -304,7 +304,7 @@ return {
['repeat']={args=2, base=1}, ['repeat']={args=2, base=1},
resolve={args=1, base=1}, resolve={args=1, base=1},
reverse={args=1, base=1}, reverse={args=1, base=1},
round={args=1, base=1, func="float_op_wrapper", data="&round"}, round={args=1, base=1, float_func="round"},
rpcnotify={args=varargs(2)}, rpcnotify={args=varargs(2)},
rpcrequest={args=varargs(2)}, rpcrequest={args=varargs(2)},
rpcstart={args={1, 2}}, rpcstart={args={1, 2}},
@@ -358,8 +358,8 @@ return {
sign_unplace={args={1, 2}, base=1}, sign_unplace={args={1, 2}, base=1},
sign_unplacelist={args=1, base=1}, sign_unplacelist={args=1, base=1},
simplify={args=1, base=1}, simplify={args=1, base=1},
sin={args=1, base=1, func="float_op_wrapper", data="&sin"}, sin={args=1, base=1, float_func="sin"},
sinh={args=1, base=1, func="float_op_wrapper", data="&sinh"}, sinh={args=1, base=1, float_func="sinh"},
sockconnect={args={2,3}}, sockconnect={args={2,3}},
sort={args={1, 3}, base=1}, sort={args={1, 3}, base=1},
soundfold={args=1, base=1}, soundfold={args=1, base=1},
@@ -367,7 +367,7 @@ return {
spellbadword={args={0, 1}, base=1}, spellbadword={args={0, 1}, base=1},
spellsuggest={args={1, 3}, base=1}, spellsuggest={args={1, 3}, base=1},
split={args={1, 3}, base=1}, split={args={1, 3}, base=1},
sqrt={args=1, base=1, func="float_op_wrapper", data="&sqrt"}, sqrt={args=1, base=1, float_func="sqrt"},
srand={args={0, 1}, base=1}, srand={args={0, 1}, base=1},
stdpath={args=1}, stdpath={args=1},
str2float={args=1, base=1}, str2float={args=1, base=1},
@@ -402,8 +402,8 @@ return {
tabpagewinnr={args={1, 2}, base=1}, tabpagewinnr={args={1, 2}, base=1},
tagfiles={}, tagfiles={},
taglist={args={1, 2}, base=1}, taglist={args={1, 2}, base=1},
tan={args=1, base=1, func="float_op_wrapper", data="&tan"}, tan={args=1, base=1, float_func="tan"},
tanh={args=1, base=1, func="float_op_wrapper", data="&tanh"}, tanh={args=1, base=1, float_func="tanh"},
tempname={}, tempname={},
termopen={args={1, 2}}, termopen={args={1, 2}},
test_garbagecollect_now={}, test_garbagecollect_now={},
@@ -417,7 +417,7 @@ return {
toupper={args=1, base=1}, toupper={args=1, base=1},
tr={args=3, base=1}, tr={args=3, base=1},
trim={args={1, 3}, base=1}, trim={args={1, 3}, base=1},
trunc={args=1, base=1, func="float_op_wrapper", data="&trunc"}, trunc={args=1, base=1, float_func="trunc"},
type={args=1, base=1}, type={args=1, base=1},
undofile={args=1, base=1}, undofile={args=1, base=1},
undotree={}, undotree={},

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,12 @@
#ifndef NVIM_EVAL_FUNCS_H #ifndef NVIM_EVAL_FUNCS_H
#define NVIM_EVAL_FUNCS_H #define NVIM_EVAL_FUNCS_H
#include "nvim/api/private/dispatch.h"
#include "nvim/buffer_defs.h" #include "nvim/buffer_defs.h"
#include "nvim/eval/typval.h" #include "nvim/eval/typval.h"
/// Prototype of C function that implements VimL function /// Prototype of C function that implements VimL function
typedef void (*VimLFunc)(typval_T *args, typval_T *rvar, FunPtr data); typedef void (*VimLFunc)(typval_T *args, typval_T *rvar, EvalFuncData data);
/// Special flags for base_arg @see EvalFuncDef /// Special flags for base_arg @see EvalFuncDef
#define BASE_NONE 0 ///< Not a method (no base argument). #define BASE_NONE 0 ///< Not a method (no base argument).
@@ -19,7 +20,7 @@ typedef struct {
uint8_t base_arg; ///< Method base arg # (1-indexed), BASE_NONE or BASE_LAST. uint8_t base_arg; ///< Method base arg # (1-indexed), BASE_NONE or BASE_LAST.
bool fast; ///< Can be run in |api-fast| events bool fast; ///< Can be run in |api-fast| events
VimLFunc func; ///< Function implementation. VimLFunc func; ///< Function implementation.
FunPtr data; ///< Userdata for function implementation. EvalFuncData data; ///< Userdata for function implementation.
} EvalFuncDef; } EvalFuncDef;
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS

View File

@@ -831,7 +831,7 @@ int tv_list_join(garray_T *const gap, list_T *const l, const char *const sep)
} }
/// "join()" function /// "join()" function
void f_join(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_join(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
if (argvars[0].v_type != VAR_LIST) { if (argvars[0].v_type != VAR_LIST) {
emsg(_(e_listreq)); emsg(_(e_listreq));
@@ -855,7 +855,7 @@ void f_join(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "list2str()" function /// "list2str()" function
void f_list2str(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_list2str(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
garray_T ga; garray_T ga;
@@ -1267,13 +1267,13 @@ theend:
} }
/// "sort"({list})" function /// "sort"({list})" function
void f_sort(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_sort(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
do_sort_uniq(argvars, rettv, true); do_sort_uniq(argvars, rettv, true);
} }
/// "uniq({list})" function /// "uniq({list})" function
void f_uniq(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_uniq(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
do_sort_uniq(argvars, rettv, false); do_sort_uniq(argvars, rettv, false);
} }
@@ -2806,25 +2806,25 @@ static void tv_dict_list(typval_T *const tv, typval_T *const rettv, const DictLi
} }
/// "items(dict)" function /// "items(dict)" function
void f_items(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_items(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
tv_dict_list(argvars, rettv, 2); tv_dict_list(argvars, rettv, 2);
} }
/// "keys()" function /// "keys()" function
void f_keys(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_keys(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
tv_dict_list(argvars, rettv, 0); tv_dict_list(argvars, rettv, 0);
} }
/// "values(dict)" function /// "values(dict)" function
void f_values(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_values(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
tv_dict_list(argvars, rettv, 1); tv_dict_list(argvars, rettv, 1);
} }
/// "has_key()" function /// "has_key()" function
void f_has_key(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_has_key(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
if (argvars[0].v_type != VAR_DICT) { if (argvars[0].v_type != VAR_DICT) {
emsg(_(e_dictreq)); emsg(_(e_dictreq));

View File

@@ -25,9 +25,6 @@
typedef int64_t varnumber_T; typedef int64_t varnumber_T;
typedef uint64_t uvarnumber_T; typedef uint64_t uvarnumber_T;
/// Type used for VimL VAR_FLOAT values
typedef double float_T;
/// Refcount for dict or list that should not be freed /// Refcount for dict or list that should not be freed
enum { DO_NOT_FREE_CNT = (INT_MAX / 2), }; enum { DO_NOT_FREE_CNT = (INT_MAX / 2), };

View File

@@ -1702,7 +1702,7 @@ bool var_exists(const char *var)
} }
/// "gettabvar()" function /// "gettabvar()" function
void f_gettabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_gettabvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
const char *const varname = tv_get_string_chk(&argvars[1]); const char *const varname = tv_get_string_chk(&argvars[1]);
tabpage_T *const tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL)); tabpage_T *const tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
@@ -1716,19 +1716,19 @@ void f_gettabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "gettabwinvar()" function /// "gettabwinvar()" function
void f_gettabwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_gettabwinvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
getwinvar(argvars, rettv, 1); getwinvar(argvars, rettv, 1);
} }
/// "getwinvar()" function /// "getwinvar()" function
void f_getwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_getwinvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
getwinvar(argvars, rettv, 0); getwinvar(argvars, rettv, 0);
} }
/// "getbufvar()" function /// "getbufvar()" function
void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_getbufvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
const char *const varname = tv_get_string_chk(&argvars[1]); const char *const varname = tv_get_string_chk(&argvars[1]);
buf_T *const buf = tv_get_buf_from_arg(&argvars[0]); buf_T *const buf = tv_get_buf_from_arg(&argvars[0]);
@@ -1737,7 +1737,7 @@ void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "settabvar()" function /// "settabvar()" function
void f_settabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_settabvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
rettv->vval.v_number = 0; rettv->vval.v_number = 0;
@@ -1768,19 +1768,19 @@ void f_settabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "settabwinvar()" function /// "settabwinvar()" function
void f_settabwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_settabwinvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
setwinvar(argvars, rettv, 1); setwinvar(argvars, rettv, 1);
} }
/// "setwinvar()" function /// "setwinvar()" function
void f_setwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_setwinvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
setwinvar(argvars, rettv, 0); setwinvar(argvars, rettv, 0);
} }
/// "setbufvar()" function /// "setbufvar()" function
void f_setbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_setbufvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
if (check_secure() if (check_secure()
|| !tv_check_str_or_nr(&argvars[0])) { || !tv_check_str_or_nr(&argvars[0])) {

View File

@@ -3047,7 +3047,7 @@ int cmd_exists(const char *const name)
} }
/// "fullcommand" function /// "fullcommand" function
void f_fullcommand(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_fullcommand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
char *name = argvars[0].vval.v_string; char *name = argvars[0].vval.v_string;

View File

@@ -3212,19 +3212,19 @@ static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end)
} }
/// "foldclosed()" function /// "foldclosed()" function
void f_foldclosed(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_foldclosed(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
foldclosed_both(argvars, rettv, false); foldclosed_both(argvars, rettv, false);
} }
/// "foldclosedend()" function /// "foldclosedend()" function
void f_foldclosedend(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_foldclosedend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
foldclosed_both(argvars, rettv, true); foldclosed_both(argvars, rettv, true);
} }
/// "foldlevel()" function /// "foldlevel()" function
void f_foldlevel(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_foldlevel(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
const linenr_T lnum = tv_get_lnum(argvars); const linenr_T lnum = tv_get_lnum(argvars);
if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) { if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) {
@@ -3233,7 +3233,7 @@ void f_foldlevel(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "foldtext()" function /// "foldtext()" function
void f_foldtext(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_foldtext(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
rettv->v_type = VAR_STRING; rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL; rettv->vval.v_string = NULL;
@@ -3279,7 +3279,7 @@ void f_foldtext(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "foldtextresult(lnum)" function /// "foldtextresult(lnum)" function
void f_foldtextresult(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_foldtextresult(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
char_u buf[FOLD_TEXT_LEN]; char_u buf[FOLD_TEXT_LEN];
static bool entered = false; static bool entered = false;

View File

@@ -26,6 +26,7 @@ local c_id = (
local c_void = P('void') local c_void = P('void')
local c_param_type = ( local c_param_type = (
((P('Error') * fill * P('*') * fill) * Cc('error')) + ((P('Error') * fill * P('*') * fill) * Cc('error')) +
((P('Arena') * fill * P('*') * fill) * Cc('arena')) +
C((P('const ') ^ -1) * (c_id) * (ws ^ 1) * P('*')) + C((P('const ') ^ -1) * (c_id) * (ws ^ 1) * P('*')) +
(C(c_id) * (ws ^ 1)) (C(c_id) * (ws ^ 1))
) )

View File

@@ -17,6 +17,7 @@ local nvimdir = arg[1]
package.path = nvimdir .. '/?.lua;' .. package.path package.path = nvimdir .. '/?.lua;' .. package.path
_G.vim = loadfile(nvimdir..'/../../runtime/lua/vim/shared.lua')() _G.vim = loadfile(nvimdir..'/../../runtime/lua/vim/shared.lua')()
_G.vim.inspect = loadfile(nvimdir..'/../../runtime/lua/vim/inspect.lua')()
local hashy = require'generators.hashy' local hashy = require'generators.hashy'
@@ -72,6 +73,11 @@ for i = 6, #arg do
-- for specifying errors -- for specifying errors
fn.parameters[#fn.parameters] = nil fn.parameters[#fn.parameters] = nil
end end
if #fn.parameters ~= 0 and fn.parameters[#fn.parameters][1] == 'arena' then
-- return value is allocated in an arena
fn.arena_return = true
fn.parameters[#fn.parameters] = nil
end
end end
end end
input:close() input:close()
@@ -210,7 +216,7 @@ for i = 1, #functions do
if fn.impl_name == nil and fn.remote then if fn.impl_name == nil and fn.remote then
local args = {} local args = {}
output:write('Object handle_'..fn.name..'(uint64_t channel_id, Array args, Error *error)') output:write('Object handle_'..fn.name..'(uint64_t channel_id, Array args, Arena* arena, Error *error)')
output:write('\n{') output:write('\n{')
output:write('\n#if MIN_LOG_LEVEL <= LOGLVL_DBG') output:write('\n#if MIN_LOG_LEVEL <= LOGLVL_DBG')
output:write('\n logmsg(LOGLVL_DBG, "RPC: ", NULL, -1, true, "ch %" PRIu64 ": invoke ' output:write('\n logmsg(LOGLVL_DBG, "RPC: ", NULL, -1, true, "ch %" PRIu64 ": invoke '
@@ -319,6 +325,10 @@ for i = 1, #functions do
output:write(call_args) output:write(call_args)
end end
if fn.arena_return then
output:write(', arena')
end
if fn.can_fail then if fn.can_fail then
-- if the function can fail, also pass a pointer to the local error object -- if the function can fail, also pass a pointer to the local error object
if #args > 0 then if #args > 0 then
@@ -355,11 +365,12 @@ local hashorder, hashfun = hashy.hashy_hash("msgpack_rpc_get_handler_for", vim.t
return "method_handlers["..idx.."].name" return "method_handlers["..idx.."].name"
end) end)
output:write("static const MsgpackRpcRequestHandler method_handlers[] = {\n") output:write("const MsgpackRpcRequestHandler method_handlers[] = {\n")
for _, name in ipairs(hashorder) do for n, name in ipairs(hashorder) do
local fn = remote_fns[name] local fn = remote_fns[name]
fn.handler_id = n-1
output:write(' { .name = "'..name..'", .fn = handle_'.. (fn.impl_name or fn.name).. output:write(' { .name = "'..name..'", .fn = handle_'.. (fn.impl_name or fn.name)..
', .fast = '..tostring(fn.fast)..'},\n') ', .fast = '..tostring(fn.fast)..', .arena_return = '..tostring(not not fn.arena_return)..'},\n')
end end
output:write("};\n\n") output:write("};\n\n")
output:write(hashfun) output:write(hashfun)
@@ -400,6 +411,10 @@ output:write([[
#include "nvim/api/private/helpers.h" #include "nvim/api/private/helpers.h"
#include "nvim/lua/converter.h" #include "nvim/lua/converter.h"
#include "nvim/lua/executor.h" #include "nvim/lua/executor.h"
#include "nvim/memory.h"
static ArenaMem lua_reuse_blk = { 0 };
]]) ]])
include_headers(output, headers) include_headers(output, headers)
output:write('\n') output:write('\n')
@@ -477,6 +492,14 @@ local function process_function(fn)
if fn.receives_channel_id then if fn.receives_channel_id then
cparams = 'LUA_INTERNAL_CALL, ' .. cparams cparams = 'LUA_INTERNAL_CALL, ' .. cparams
end end
if fn.arena_return then
cparams = cparams .. '&arena, '
write_shifted_output(output, [[
Arena arena = ARENA_EMPTY;
arena_start(&arena, &lua_reuse_blk);
]])
end
if fn.can_fail then if fn.can_fail then
cparams = cparams .. '&err' cparams = cparams .. '&err'
else else
@@ -511,15 +534,21 @@ local function process_function(fn)
else else
return_type = fn.return_type return_type = fn.return_type
end end
local free_retval
if fn.arena_return then
free_retval = "arena_mem_free(arena_finish(&arena), &lua_reuse_blk);"
else
free_retval = "api_free_"..return_type:lower().."(ret);"
end
write_shifted_output(output, string.format([[ write_shifted_output(output, string.format([[
const %s ret = %s(%s); const %s ret = %s(%s);
nlua_push_%s(lstate, ret, true); nlua_push_%s(lstate, ret, true);
api_free_%s(ret); %s
%s %s
%s %s
return 1; return 1;
]], fn.return_type, fn.name, cparams, return_type, return_type:lower(), ]], fn.return_type, fn.name, cparams, return_type,
free_at_exit_code, err_throw_code)) free_retval, free_at_exit_code, err_throw_code))
else else
write_shifted_output(output, string.format([[ write_shifted_output(output, string.format([[
%s(%s); %s(%s);

View File

@@ -28,13 +28,20 @@ local hashy = require'generators.hashy'
local hashpipe = io.open(funcsfname, 'wb') local hashpipe = io.open(funcsfname, 'wb')
local funcs = require('eval').funcs local funcs = require('eval').funcs
for _, func in pairs(funcs) do
if func.float_func then
func.func = "float_op_wrapper"
func.data = "{ .float_func = &"..func.float_func.." }"
end
end
local metadata = mpack.unpack(io.open(metadata_file, 'rb'):read("*all")) local metadata = mpack.unpack(io.open(metadata_file, 'rb'):read("*all"))
for _,fun in ipairs(metadata) do for _,fun in ipairs(metadata) do
if fun.eval then if fun.eval then
funcs[fun.name] = { funcs[fun.name] = {
args=#fun.parameters, args=#fun.parameters,
func='api_wrapper', func='api_wrapper',
data='&handle_'..fun.name, data='{ .api_handler = &method_handlers['..fun.handler_id..'] }'
} }
end end
end end
@@ -60,12 +67,12 @@ for _, name in ipairs(neworder) do
end end
local base = def.base or "BASE_NONE" local base = def.base or "BASE_NONE"
local func = def.func or ('f_' .. name) local func = def.func or ('f_' .. name)
local data = def.data or "NULL" local data = def.data or "{ .nullptr = NULL }"
local fast = def.fast and 'true' or 'false' local fast = def.fast and 'true' or 'false'
hashpipe:write((' { "%s", %s, %s, %s, %s, &%s, (FunPtr)%s },\n') hashpipe:write((' { "%s", %s, %s, %s, %s, &%s, %s },\n')
:format(name, args[1], args[2], base, fast, func, data)) :format(name, args[1], args[2], base, fast, func, data))
end end
hashpipe:write(' { NULL, 0, 0, BASE_NONE, false, NULL, NULL },\n') hashpipe:write(' { NULL, 0, 0, BASE_NONE, false, NULL, { .nullptr = NULL } },\n')
hashpipe:write("};\n\n") hashpipe:write("};\n\n")
hashpipe:write(hashfun) hashpipe:write(hashfun)
hashpipe:close() hashpipe:close()

View File

@@ -1810,13 +1810,13 @@ static void getchar_common(typval_T *argvars, typval_T *rettv)
} }
/// "getchar()" function /// "getchar()" function
void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_getchar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
getchar_common(argvars, rettv); getchar_common(argvars, rettv);
} }
/// "getcharstr()" function /// "getcharstr()" function
void f_getcharstr(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_getcharstr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
getchar_common(argvars, rettv); getchar_common(argvars, rettv);
@@ -1836,7 +1836,7 @@ void f_getcharstr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "getcharmod()" function /// "getcharmod()" function
void f_getcharmod(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_getcharmod(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
rettv->vval.v_number = mod_mask; rettv->vval.v_number = mod_mask;
} }

View File

@@ -2256,7 +2256,7 @@ static void set_completion(colnr_T startcol, list_T *list)
} }
/// "complete()" function /// "complete()" function
void f_complete(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_complete(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
if ((State & MODE_INSERT) == 0) { if ((State & MODE_INSERT) == 0) {
emsg(_("E785: complete() can only be used in Insert mode")); emsg(_("E785: complete() can only be used in Insert mode"));
@@ -2280,13 +2280,13 @@ void f_complete(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "complete_add()" function /// "complete_add()" function
void f_complete_add(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_complete_add(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0, false); rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0, false);
} }
/// "complete_check()" function /// "complete_check()" function
void f_complete_check(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_complete_check(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
int saved = RedrawingDisabled; int saved = RedrawingDisabled;
@@ -2441,7 +2441,7 @@ static void get_complete_info(list_T *what_list, dict_T *retdict)
} }
/// "complete_info()" function /// "complete_info()" function
void f_complete_info(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_complete_info(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
tv_dict_alloc_ret(rettv); tv_dict_alloc_ret(rettv);

View File

@@ -1967,7 +1967,7 @@ char_u *check_map(char_u *keys, int mode, int exact, int ign_mod, int abbr, mapb
} }
/// "hasmapto()" function /// "hasmapto()" function
void f_hasmapto(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_hasmapto(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
const char *mode; const char *mode;
const char *const name = tv_get_string(&argvars[0]); const char *const name = tv_get_string(&argvars[0]);
@@ -2127,7 +2127,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
} }
/// "mapset()" function /// "mapset()" function
void f_mapset(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_mapset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
char buf[NUMBUFLEN]; char buf[NUMBUFLEN];
const char *which = tv_get_string_buf_chk(&argvars[0], buf); const char *which = tv_get_string_buf_chk(&argvars[0], buf);
@@ -2195,13 +2195,13 @@ void f_mapset(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "maparg()" function /// "maparg()" function
void f_maparg(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_maparg(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
get_maparg(argvars, rettv, true); get_maparg(argvars, rettv, true);
} }
/// "mapcheck()" function /// "mapcheck()" function
void f_mapcheck(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_mapcheck(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
get_maparg(argvars, rettv, false); get_maparg(argvars, rettv, false);
} }

View File

@@ -859,7 +859,7 @@ static int matchadd_dict_arg(typval_T *tv, const char **conceal_char, win_T **wi
} }
/// "clearmatches()" function /// "clearmatches()" function
void f_clearmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_clearmatches(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
win_T *win = get_optional_window(argvars, 0); win_T *win = get_optional_window(argvars, 0);
@@ -869,7 +869,7 @@ void f_clearmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "getmatches()" function /// "getmatches()" function
void f_getmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_getmatches(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
matchitem_T *cur; matchitem_T *cur;
int i; int i;
@@ -924,7 +924,7 @@ void f_getmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "setmatches()" function /// "setmatches()" function
void f_setmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_setmatches(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
dict_T *d; dict_T *d;
list_T *s = NULL; list_T *s = NULL;
@@ -1027,7 +1027,7 @@ void f_setmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "matchadd()" function /// "matchadd()" function
void f_matchadd(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_matchadd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
char grpbuf[NUMBUFLEN]; char grpbuf[NUMBUFLEN];
char patbuf[NUMBUFLEN]; char patbuf[NUMBUFLEN];
@@ -1069,7 +1069,7 @@ void f_matchadd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "matchaddpo()" function /// "matchaddpo()" function
void f_matchaddpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_matchaddpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
rettv->vval.v_number = -1; rettv->vval.v_number = -1;
@@ -1120,7 +1120,7 @@ void f_matchaddpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "matcharg()" function /// "matcharg()" function
void f_matcharg(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_matcharg(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
const int id = (int)tv_get_number(&argvars[0]); const int id = (int)tv_get_number(&argvars[0]);
@@ -1143,7 +1143,7 @@ void f_matcharg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "matchdelete()" function /// "matchdelete()" function
void f_matchdelete(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_matchdelete(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
win_T *win = get_optional_window(argvars, 1); win_T *win = get_optional_window(argvars, 1);
if (win == NULL) { if (win == NULL) {

View File

@@ -2748,7 +2748,7 @@ static int tv_nr_compare(const void *a1, const void *a2)
} }
/// "setcellwidths()" function /// "setcellwidths()" function
void f_setcellwidths(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_setcellwidths(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL) { if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL) {
emsg(_(e_listreq)); emsg(_(e_listreq));
@@ -2860,7 +2860,7 @@ void f_setcellwidths(typval_T *argvars, typval_T *rettv, FunPtr fptr)
redraw_all_later(NOT_VALID); redraw_all_later(NOT_VALID);
} }
void f_charclass(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_charclass(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
if (tv_check_for_string(&argvars[0]) == FAIL if (tv_check_for_string(&argvars[0]) == FAIL
|| argvars[0].vval.v_string == NULL) { || argvars[0].vval.v_string == NULL) {

View File

@@ -534,15 +534,18 @@ void arena_start(Arena *arena, ArenaMem *reuse_blk)
if (reuse_blk && *reuse_blk) { if (reuse_blk && *reuse_blk) {
arena->cur_blk = (char *)(*reuse_blk); arena->cur_blk = (char *)(*reuse_blk);
*reuse_blk = NULL; *reuse_blk = NULL;
} else {
arena->cur_blk = xmalloc(ARENA_BLOCK_SIZE);
}
arena->pos = 0;
arena->size = ARENA_BLOCK_SIZE; arena->size = ARENA_BLOCK_SIZE;
arena->pos = 0;
// address is the same as as (struct consumed_blk *)arena->cur_blk // address is the same as as (struct consumed_blk *)arena->cur_blk
struct consumed_blk *blk = arena_alloc(arena, sizeof(struct consumed_blk), true); struct consumed_blk *blk = arena_alloc(arena, sizeof(struct consumed_blk), true);
assert((char *)blk == (char *)arena->cur_blk); assert((char *)blk == (char *)arena->cur_blk);
blk->prev = NULL; blk->prev = NULL;
} else {
arena->cur_blk = NULL;
arena->size = 0;
arena->pos = 0;
}
} }
/// Finnish the allocations in an arena. /// Finnish the allocations in an arena.
@@ -558,17 +561,35 @@ ArenaMem arena_finish(Arena *arena)
return res; return res;
} }
void alloc_block(Arena *arena)
{
struct consumed_blk *prev_blk = (struct consumed_blk *)arena->cur_blk;
arena->cur_blk = xmalloc(ARENA_BLOCK_SIZE);
arena->pos = 0;
arena->size = ARENA_BLOCK_SIZE;
struct consumed_blk *blk = arena_alloc(arena, sizeof(struct consumed_blk), true);
blk->prev = prev_blk;
arena_alloc_count++;
}
/// @param size if zero, will still return a non-null pointer, but not a unique one
void *arena_alloc(Arena *arena, size_t size, bool align) void *arena_alloc(Arena *arena, size_t size, bool align)
{ {
if (align) { if (align) {
arena->pos = (arena->pos + (ARENA_ALIGN - 1)) & ~(ARENA_ALIGN - 1); arena->pos = (arena->pos + (ARENA_ALIGN - 1)) & ~(ARENA_ALIGN - 1);
} }
if (arena->pos + size > arena->size) { if (arena->pos + size > arena->size || !arena->cur_blk) {
if (size > (arena->size - sizeof(struct consumed_blk)) >> 1) { if (size > (ARENA_BLOCK_SIZE - sizeof(struct consumed_blk)) >> 1) {
// if allocation is too big, allocate a large block with the requested // if allocation is too big, allocate a large block with the requested
// size, but still with block pointer head. We do this even for // size, but still with block pointer head. We do this even for
// arena->size / 2, as there likely is space left for the next // arena->size / 2, as there likely is space left for the next
// small allocation in the current block. // small allocation in the current block.
if (!arena->cur_blk) {
// to simplify free-list management, arena->cur_blk must
// always be a normal, ARENA_BLOCK_SIZE sized, block
alloc_block(arena);
}
arena_alloc_count++;
char *alloc = xmalloc(size + sizeof(struct consumed_blk)); char *alloc = xmalloc(size + sizeof(struct consumed_blk));
struct consumed_blk *cur_blk = (struct consumed_blk *)arena->cur_blk; struct consumed_blk *cur_blk = (struct consumed_blk *)arena->cur_blk;
struct consumed_blk *fix_blk = (struct consumed_blk *)alloc; struct consumed_blk *fix_blk = (struct consumed_blk *)alloc;
@@ -576,12 +597,7 @@ void *arena_alloc(Arena *arena, size_t size, bool align)
cur_blk->prev = fix_blk; cur_blk->prev = fix_blk;
return (alloc + sizeof(struct consumed_blk)); return (alloc + sizeof(struct consumed_blk));
} else { } else {
struct consumed_blk *prev_blk = (struct consumed_blk *)arena->cur_blk; alloc_block(arena);
arena->cur_blk = xmalloc(ARENA_BLOCK_SIZE);
arena->pos = 0;
arena->size = ARENA_BLOCK_SIZE;
struct consumed_blk *blk = arena_alloc(arena, sizeof(struct consumed_blk), true);
blk->prev = prev_blk;
} }
} }

View File

@@ -6,6 +6,8 @@
#include <stdint.h> // for uint8_t #include <stdint.h> // for uint8_t
#include <time.h> // for time_t #include <time.h> // for time_t
#include "nvim/macros.h"
/// `malloc()` function signature /// `malloc()` function signature
typedef void *(*MemMalloc)(size_t); typedef void *(*MemMalloc)(size_t);
@@ -37,6 +39,8 @@ extern MemRealloc mem_realloc;
extern bool entered_free_all_mem; extern bool entered_free_all_mem;
#endif #endif
EXTERN size_t arena_alloc_count INIT(=0);
typedef struct consumed_blk { typedef struct consumed_blk {
struct consumed_blk *prev; struct consumed_blk *prev;
} *ArenaMem; } *ArenaMem;

View File

@@ -1945,7 +1945,7 @@ static void menuitem_getinfo(const char *menu_name, const vimmenu_T *menu, int m
/// "menu_info()" function /// "menu_info()" function
/// Return information about a menu (including all the child menus) /// Return information about a menu (including all the child menus)
void f_menu_info(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_menu_info(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
tv_dict_alloc_ret(rettv); tv_dict_alloc_ret(rettv);
dict_T *const retdict = rettv->vval.v_dict; dict_T *const retdict = rettv->vval.v_dict;

View File

@@ -304,7 +304,8 @@ static void handle_request(Channel *channel, Unpacker *p, Array args)
evdata->channel = channel; evdata->channel = channel;
evdata->handler = p->handler; evdata->handler = p->handler;
evdata->args = args; evdata->args = args;
evdata->used_mem = arena_finish(&p->arena); evdata->used_mem = p->arena;
p->arena = (Arena)ARENA_EMPTY;
evdata->request_id = p->request_id; evdata->request_id = p->request_id;
channel_incref(channel); channel_incref(channel);
if (p->handler.fast) { if (p->handler.fast) {
@@ -344,7 +345,8 @@ static void request_event(void **argv)
// channel was closed, abort any pending requests // channel was closed, abort any pending requests
goto free_ret; goto free_ret;
} }
Object result = handler.fn(channel->id, e->args, &error);
Object result = handler.fn(channel->id, e->args, &e->used_mem, &error);
if (e->type == kMessageTypeRequest || ERROR_SET(&error)) { if (e->type == kMessageTypeRequest || ERROR_SET(&error)) {
// Send the response. // Send the response.
msgpack_packer response; msgpack_packer response;
@@ -355,13 +357,14 @@ static void request_event(void **argv)
&error, &error,
result, result,
&out_buffer)); &out_buffer));
} else { }
if (!handler.arena_return) {
api_free_object(result); api_free_object(result);
} }
free_ret: free_ret:
// e->args is allocated in an arena // e->args (and possibly result) are allocated in an arena
arena_mem_free(e->used_mem, &channel->rpc.unpacker->reuse_blk); arena_mem_free(arena_finish(&e->used_mem), &channel->rpc.unpacker->reuse_blk);
channel_decref(channel); channel_decref(channel);
xfree(e); xfree(e);
api_clear_error(&error); api_clear_error(&error);
@@ -624,7 +627,6 @@ static WBuffer *serialize_response(uint64_t channel_id, MessageType type, uint32
1, // responses only go though 1 channel 1, // responses only go though 1 channel
xfree); xfree);
msgpack_sbuffer_clear(sbuffer); msgpack_sbuffer_clear(sbuffer);
api_free_object(arg);
return rv; return rv;
} }

View File

@@ -27,7 +27,7 @@ typedef struct {
MsgpackRpcRequestHandler handler; MsgpackRpcRequestHandler handler;
Array args; Array args;
uint32_t request_id; uint32_t request_id;
ArenaMem used_mem; Arena used_mem;
} RequestEvent; } RequestEvent;
typedef struct { typedef struct {

View File

@@ -7169,14 +7169,14 @@ static void get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *
} }
/// "getloclist()" function /// "getloclist()" function
void f_getloclist(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_getloclist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
win_T *wp = find_win_by_nr_or_id(&argvars[0]); win_T *wp = find_win_by_nr_or_id(&argvars[0]);
get_qf_loc_list(false, wp, &argvars[1], rettv); get_qf_loc_list(false, wp, &argvars[1], rettv);
} }
/// "getqflist()" functions /// "getqflist()" functions
void f_getqflist(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_getqflist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
get_qf_loc_list(true, NULL, &argvars[0], rettv); get_qf_loc_list(true, NULL, &argvars[0], rettv);
} }
@@ -7263,7 +7263,7 @@ skip_args:
} }
/// "setloclist()" function /// "setloclist()" function
void f_setloclist(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_setloclist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
rettv->vval.v_number = -1; rettv->vval.v_number = -1;
@@ -7274,7 +7274,7 @@ void f_setloclist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "setqflist()" function /// "setqflist()" function
void f_setqflist(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_setqflist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
set_qf_ll_list(NULL, argvars, rettv); set_qf_ll_list(NULL, argvars, rettv);
} }

View File

@@ -4637,7 +4637,7 @@ static void update_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, searchst
} }
// "searchcount()" function // "searchcount()" function
void f_searchcount(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_searchcount(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
pos_T pos = curwin->w_cursor; pos_T pos = curwin->w_cursor;
char_u *pattern = NULL; char_u *pattern = NULL;
@@ -5287,13 +5287,13 @@ static void do_fuzzymatch(const typval_T *const argvars, typval_T *const rettv,
} }
/// "matchfuzzy()" function /// "matchfuzzy()" function
void f_matchfuzzy(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_matchfuzzy(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
do_fuzzymatch(argvars, rettv, false); do_fuzzymatch(argvars, rettv, false);
} }
/// "matchfuzzypos()" function /// "matchfuzzypos()" function
void f_matchfuzzypos(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_matchfuzzypos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
do_fuzzymatch(argvars, rettv, true); do_fuzzymatch(argvars, rettv, true);
} }

View File

@@ -1964,7 +1964,7 @@ static void sign_define_multiple(list_T *l, list_T *retlist)
} }
/// "sign_define()" function /// "sign_define()" function
void f_sign_define(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_sign_define(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
const char *name; const char *name;
@@ -1995,7 +1995,7 @@ void f_sign_define(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "sign_getdefined()" function /// "sign_getdefined()" function
void f_sign_getdefined(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_sign_getdefined(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
const char *name = NULL; const char *name = NULL;
@@ -2009,7 +2009,7 @@ void f_sign_getdefined(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "sign_getplaced()" function /// "sign_getplaced()" function
void f_sign_getplaced(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_sign_getplaced(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
buf_T *buf = NULL; buf_T *buf = NULL;
dict_T *dict; dict_T *dict;
@@ -2067,7 +2067,7 @@ void f_sign_getplaced(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "sign_jump()" function /// "sign_jump()" function
void f_sign_jump(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_sign_jump(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
int sign_id; int sign_id;
char *sign_group = NULL; char *sign_group = NULL;
@@ -2225,7 +2225,7 @@ cleanup:
} }
/// "sign_place()" function /// "sign_place()" function
void f_sign_place(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_sign_place(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
dict_T *dict = NULL; dict_T *dict = NULL;
@@ -2243,7 +2243,7 @@ void f_sign_place(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "sign_placelist()" function. Place multiple signs. /// "sign_placelist()" function. Place multiple signs.
void f_sign_placelist(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_sign_placelist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
int sign_id; int sign_id;
@@ -2283,7 +2283,7 @@ static void sign_undefine_multiple(list_T *l, list_T *retlist)
} }
/// "sign_undefine()" function /// "sign_undefine()" function
void f_sign_undefine(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_sign_undefine(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
const char *name; const char *name;
@@ -2373,7 +2373,7 @@ cleanup:
} }
/// "sign_unplace()" function /// "sign_unplace()" function
void f_sign_unplace(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_sign_unplace(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
dict_T *dict = NULL; dict_T *dict = NULL;
@@ -2396,7 +2396,7 @@ void f_sign_unplace(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "sign_unplacelist()" function /// "sign_unplacelist()" function
void f_sign_unplacelist(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_sign_unplacelist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
int retval; int retval;

View File

@@ -326,19 +326,19 @@ static int assert_beeps(typval_T *argvars, bool no_beep)
} }
/// "assert_beeps(cmd [, error])" function /// "assert_beeps(cmd [, error])" function
void f_assert_beeps(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_assert_beeps(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
rettv->vval.v_number = assert_beeps(argvars, false); rettv->vval.v_number = assert_beeps(argvars, false);
} }
/// "assert_nobeep(cmd [, error])" function /// "assert_nobeep(cmd [, error])" function
void f_assert_nobeep(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_assert_nobeep(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
rettv->vval.v_number = assert_beeps(argvars, true); rettv->vval.v_number = assert_beeps(argvars, true);
} }
/// "assert_equal(expected, actual[, msg])" function /// "assert_equal(expected, actual[, msg])" function
void f_assert_equal(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_assert_equal(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL); rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
} }
@@ -433,19 +433,19 @@ static int assert_equalfile(typval_T *argvars)
} }
/// "assert_equalfile(fname-one, fname-two[, msg])" function /// "assert_equalfile(fname-one, fname-two[, msg])" function
void f_assert_equalfile(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_assert_equalfile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
rettv->vval.v_number = assert_equalfile(argvars); rettv->vval.v_number = assert_equalfile(argvars);
} }
/// "assert_notequal(expected, actual[, msg])" function /// "assert_notequal(expected, actual[, msg])" function
void f_assert_notequal(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_assert_notequal(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL); rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
} }
/// "assert_exception(string[, msg])" function /// "assert_exception(string[, msg])" function
void f_assert_exception(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_assert_exception(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
garray_T ga; garray_T ga;
@@ -468,7 +468,7 @@ void f_assert_exception(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "assert_fails(cmd [, error [, msg]])" function /// "assert_fails(cmd [, error [, msg]])" function
void f_assert_fails(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_assert_fails(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
const char *const cmd = tv_get_string_chk(&argvars[0]); const char *const cmd = tv_get_string_chk(&argvars[0]);
garray_T ga; garray_T ga;
@@ -513,7 +513,7 @@ void f_assert_fails(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
// "assert_false(actual[, msg])" function // "assert_false(actual[, msg])" function
void f_assert_false(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_assert_false(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
rettv->vval.v_number = assert_bool(argvars, false); rettv->vval.v_number = assert_bool(argvars, false);
} }
@@ -574,25 +574,25 @@ static int assert_inrange(typval_T *argvars)
} }
/// "assert_inrange(lower, upper[, msg])" function /// "assert_inrange(lower, upper[, msg])" function
void f_assert_inrange(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_assert_inrange(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
rettv->vval.v_number = assert_inrange(argvars); rettv->vval.v_number = assert_inrange(argvars);
} }
/// "assert_match(pattern, actual[, msg])" function /// "assert_match(pattern, actual[, msg])" function
void f_assert_match(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_assert_match(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH); rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
} }
/// "assert_notmatch(pattern, actual[, msg])" function /// "assert_notmatch(pattern, actual[, msg])" function
void f_assert_notmatch(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_assert_notmatch(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH); rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
} }
/// "assert_report(msg)" function /// "assert_report(msg)" function
void f_assert_report(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_assert_report(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
garray_T ga; garray_T ga;
@@ -604,13 +604,13 @@ void f_assert_report(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "assert_true(actual[, msg])" function /// "assert_true(actual[, msg])" function
void f_assert_true(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_assert_true(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
rettv->vval.v_number = assert_bool(argvars, true); rettv->vval.v_number = assert_bool(argvars, true);
} }
/// "test_garbagecollect_now()" function /// "test_garbagecollect_now()" function
void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv, FunPtr fptr) void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
// This is dangerous, any Lists and Dicts used internally may be freed // This is dangerous, any Lists and Dicts used internally may be freed
// while still in use. // while still in use.
@@ -618,7 +618,7 @@ void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
/// "test_write_list_log()" function /// "test_write_list_log()" function
void f_test_write_list_log(typval_T *const argvars, typval_T *const rettv, FunPtr fptr) void f_test_write_list_log(typval_T *const argvars, typval_T *const rettv, EvalFuncData fptr)
{ {
const char *const fname = tv_get_string_chk(&argvars[0]); const char *const fname = tv_get_string_chk(&argvars[0]);
if (fname == NULL) { if (fname == NULL) {

View File

@@ -22,7 +22,17 @@ typedef int handle_T;
// absent callback etc. // absent callback etc.
typedef int LuaRef; typedef int LuaRef;
typedef void (*FunPtr)(void); /// Type used for VimL VAR_FLOAT values
typedef double float_T;
typedef struct MsgpackRpcRequestHandler MsgpackRpcRequestHandler;
typedef union {
float_T (*float_func)(float_T);
const MsgpackRpcRequestHandler *api_handler;
void *nullptr;
} EvalFuncData;
typedef handle_T NS; typedef handle_T NS;

View File

@@ -55,7 +55,7 @@ UIClientHandler ui_client_get_redraw_handler(const char *name, size_t name_len,
/// async 'redraw' events, which are expected when nvim acts as an ui client. /// async 'redraw' events, which are expected when nvim acts as an ui client.
/// get handled in msgpack_rpc/unpacker.c and directly dispatched to handlers /// get handled in msgpack_rpc/unpacker.c and directly dispatched to handlers
/// of specific ui events, like ui_client_event_grid_resize and so on. /// of specific ui events, like ui_client_event_grid_resize and so on.
Object handle_ui_client_redraw(uint64_t channel_id, Array args, Error *error) Object handle_ui_client_redraw(uint64_t channel_id, Array args, Arena *arena, Error *error)
{ {
api_set_error(error, kErrorTypeValidation, "'redraw' cannot be sent as a request"); api_set_error(error, kErrorTypeValidation, "'redraw' cannot be sent as a request");
return NIL; return NIL;