• R/O
  • SSH

vim: Commit

Mirror of the Vim source from https://github.com/vim/vim


Commit MetaInfo

Revision15003353a4647e60022bd065b2c10710d33a2808 (tree)
Time2020-09-24 05:00:06
AuthorBram Moolenaar <Bram@vim....>
CommiterBram Moolenaar

Log Message

patch 8.2.1734: Vim9: cannot use a funcref for a closure twice

Commit: https://github.com/vim/vim/commit/148ce7ae62e92ecf6487a4ba5902ddb7e699074b
Author: Bram Moolenaar <Bram@vim.org>
Date: Wed Sep 23 21:57:23 2020 +0200

patch 8.2.1734: Vim9: cannot use a funcref for a closure twice
Problem: Vim9: cannot use a funcref for a closure twice.
Solution: Instead of putting the funcref on the stack use a growarray on the
execution context.

Change Summary

Incremental Difference

diff -r 9a06648f05d3 -r 15003353a464 src/testdir/test_vim9_disassemble.vim
--- a/src/testdir/test_vim9_disassemble.vim Wed Sep 23 19:00:04 2020 +0200
+++ b/src/testdir/test_vim9_disassemble.vim Wed Sep 23 22:00:06 2020 +0200
@@ -708,7 +708,7 @@
708708 let instr = execute('disassemble WithLambda')
709709 assert_match('WithLambda\_s*' ..
710710 'let F = {a -> "X" .. a .. "X"}\_s*' ..
711- '\d FUNCREF <lambda>\d\+ $1\_s*' ..
711+ '\d FUNCREF <lambda>\d\+\_s*' ..
712712 '\d STORE $0\_s*' ..
713713 'return F("x")\_s*' ..
714714 '\d PUSHS "x"\_s*' ..
diff -r 9a06648f05d3 -r 15003353a464 src/testdir/test_vim9_func.vim
--- a/src/testdir/test_vim9_func.vim Wed Sep 23 19:00:04 2020 +0200
+++ b/src/testdir/test_vim9_func.vim Wed Sep 23 22:00:06 2020 +0200
@@ -1367,7 +1367,7 @@
13671367 enddef
13681368 Func()
13691369 END
1370- CheckScriptFailure(lines, 'Multiple closures not supported yet')
1370+ CheckScriptSuccess(lines)
13711371 enddef
13721372
13731373 def Test_sort_return_type()
diff -r 9a06648f05d3 -r 15003353a464 src/version.c
--- a/src/version.c Wed Sep 23 19:00:04 2020 +0200
+++ b/src/version.c Wed Sep 23 22:00:06 2020 +0200
@@ -751,6 +751,8 @@
751751 static int included_patches[] =
752752 { /* Add new patch number below this line */
753753 /**/
754+ 1734,
755+/**/
754756 1733,
755757 /**/
756758 1732,
diff -r 9a06648f05d3 -r 15003353a464 src/vim9.h
--- a/src/vim9.h Wed Sep 23 19:00:04 2020 +0200
+++ b/src/vim9.h Wed Sep 23 22:00:06 2020 +0200
@@ -244,7 +244,6 @@
244244 // arguments to ISN_FUNCREF
245245 typedef struct {
246246 int fr_func; // function index
247- int fr_var_idx; // variable to store partial
248247 } funcref_T;
249248
250249 // arguments to ISN_NEWFUNC
@@ -323,7 +322,7 @@
323322 int df_instr_count;
324323
325324 int df_varcount; // number of local variables
326- int df_closure_count; // number of closures created
325+ int df_has_closure; // one if a closure was created
327326 };
328327
329328 // Number of entries used by stack frame for a function call.
diff -r 9a06648f05d3 -r 15003353a464 src/vim9compile.c
--- a/src/vim9compile.c Wed Sep 23 19:00:04 2020 +0200
+++ b/src/vim9compile.c Wed Sep 23 22:00:06 2020 +0200
@@ -126,8 +126,8 @@
126126 garray_T ctx_locals; // currently visible local variables
127127 int ctx_locals_count; // total number of local variables
128128
129- int ctx_closure_count; // number of closures created in the
130- // function
129+ int ctx_has_closure; // set to one if a closures was created in
130+ // the function
131131
132132 garray_T ctx_imports; // imported items
133133
@@ -1273,7 +1273,7 @@
12731273 if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL)
12741274 return FAIL;
12751275 isn->isn_arg.funcref.fr_func = ufunc->uf_dfunc_idx;
1276- isn->isn_arg.funcref.fr_var_idx = cctx->ctx_closure_count++;
1276+ cctx->ctx_has_closure = 1;
12771277
12781278 if (ga_grow(stack, 1) == FAIL)
12791279 return FAIL;
@@ -7138,7 +7138,7 @@
71387138 dfunc->df_instr = instr->ga_data;
71397139 dfunc->df_instr_count = instr->ga_len;
71407140 dfunc->df_varcount = cctx.ctx_locals_count;
7141- dfunc->df_closure_count = cctx.ctx_closure_count;
7141+ dfunc->df_has_closure = cctx.ctx_has_closure;
71427142 if (cctx.ctx_outer_used)
71437143 ufunc->uf_flags |= FC_CLOSURE;
71447144 ufunc->uf_def_status = UF_COMPILED;
@@ -7312,7 +7312,8 @@
73127312 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
73137313 + isn->isn_arg.dfunc.cdf_idx;
73147314
7315- if (func_name_refcount(dfunc->df_ufunc->uf_name))
7315+ if (dfunc->df_ufunc != NULL
7316+ && func_name_refcount(dfunc->df_ufunc->uf_name))
73167317 func_ptr_unref(dfunc->df_ufunc);
73177318 }
73187319 break;
diff -r 9a06648f05d3 -r 15003353a464 src/vim9execute.c
--- a/src/vim9execute.c Wed Sep 23 19:00:04 2020 +0200
+++ b/src/vim9execute.c Wed Sep 23 22:00:06 2020 +0200
@@ -67,6 +67,8 @@
6767 int ec_dfunc_idx; // current function index
6868 isn_T *ec_instr; // array with instructions
6969 int ec_iidx; // index in ec_instr: instruction to execute
70+
71+ garray_T ec_funcrefs; // partials that might be a closure
7072 } ectx_T;
7173
7274 // Get pointer to item relative to the bottom of the stack, -1 is the last one.
@@ -165,6 +167,7 @@
165167 ufunc_T *ufunc = dfunc->df_ufunc;
166168 int arg_to_add;
167169 int vararg_count = 0;
170+ int varcount;
168171 int idx;
169172 estack_T *entry;
170173
@@ -212,8 +215,16 @@
212215 semsg(_(e_nr_arguments_too_many), -arg_to_add);
213216 return FAIL;
214217 }
215- if (ga_grow(&ectx->ec_stack, arg_to_add + 3
216- + dfunc->df_varcount + dfunc->df_closure_count) == FAIL)
218+
219+ // Reserve space for:
220+ // - missing arguments
221+ // - stack frame
222+ // - local variables
223+ // - if needed: a counter for number of closures created in
224+ // ectx->ec_funcrefs.
225+ varcount = dfunc->df_varcount + dfunc->df_has_closure;
226+ if (ga_grow(&ectx->ec_stack, arg_to_add + STACK_FRAME_SIZE + varcount)
227+ == FAIL)
217228 return FAIL;
218229
219230 // Move the vararg-list to below the missing optional arguments.
@@ -232,10 +243,16 @@
232243 ectx->ec_frame_idx = ectx->ec_stack.ga_len;
233244
234245 // Initialize local variables
235- for (idx = 0; idx < dfunc->df_varcount + dfunc->df_closure_count; ++idx)
246+ for (idx = 0; idx < dfunc->df_varcount; ++idx)
236247 STACK_TV_BOT(STACK_FRAME_SIZE + idx)->v_type = VAR_UNKNOWN;
237- ectx->ec_stack.ga_len += STACK_FRAME_SIZE
238- + dfunc->df_varcount + dfunc->df_closure_count;
248+ if (dfunc->df_has_closure)
249+ {
250+ typval_T *tv = STACK_TV_BOT(STACK_FRAME_SIZE + dfunc->df_varcount);
251+
252+ tv->v_type = VAR_NUMBER;
253+ tv->vval.v_number = 0;
254+ }
255+ ectx->ec_stack.ga_len += STACK_FRAME_SIZE + varcount;
239256
240257 // Set execution state to the start of the called function.
241258 ectx->ec_dfunc_idx = cdf_idx;
@@ -275,22 +292,30 @@
275292 int idx;
276293 typval_T *tv;
277294 int closure_in_use = FALSE;
295+ garray_T *gap = &ectx->ec_funcrefs;
296+ varnumber_T closure_count;
278297
279298 if (dfunc->df_ufunc == NULL)
280- // function was freed
281- return OK;
299+ return OK; // function was freed
300+ if (dfunc->df_has_closure == 0)
301+ return OK; // no closures
302+ tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE + dfunc->df_varcount);
303+ closure_count = tv->vval.v_number;
304+ if (closure_count == 0)
305+ return OK; // no funcrefs created
306+
282307 argcount = ufunc_argcount(dfunc->df_ufunc);
283308 top = ectx->ec_frame_idx - argcount;
284309
285310 // Check if any created closure is still in use.
286- for (idx = 0; idx < dfunc->df_closure_count; ++idx)
311+ for (idx = 0; idx < closure_count; ++idx)
287312 {
288- tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE
289- + dfunc->df_varcount + idx);
290- if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL
291- && tv->vval.v_partial->pt_refcount > 1)
313+ partial_T *pt = ((partial_T **)gap->ga_data)[gap->ga_len
314+ - closure_count + idx];
315+
316+ if (pt->pt_refcount > 1)
292317 {
293- int refcount = tv->vval.v_partial->pt_refcount;
318+ int refcount = pt->pt_refcount;
294319 int i;
295320
296321 // A Reference in a local variables doesn't count, it gets
@@ -299,8 +324,7 @@
299324 {
300325 typval_T *stv = STACK_TV(ectx->ec_frame_idx
301326 + STACK_FRAME_SIZE + i);
302- if (stv->v_type == VAR_PARTIAL
303- && tv->vval.v_partial == stv->vval.v_partial)
327+ if (stv->v_type == VAR_PARTIAL && pt == stv->vval.v_partial)
304328 --refcount;
305329 }
306330 if (refcount > 1)
@@ -355,46 +379,43 @@
355379 if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL)
356380 {
357381 int i;
358- typval_T *ctv;
359-
360- for (i = 0; i < dfunc->df_closure_count; ++i)
382+
383+ for (i = 0; i < closure_count; ++i)
361384 {
362- ctv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE
363- + dfunc->df_varcount + i);
364- if (tv->vval.v_partial == ctv->vval.v_partial)
385+ partial_T *pt = ((partial_T **)gap->ga_data)[gap->ga_len
386+ - closure_count + i];
387+ if (tv->vval.v_partial == pt)
365388 break;
366389 }
367- if (i < dfunc->df_closure_count)
368- {
369- (stack + argcount + STACK_FRAME_SIZE + idx)->v_type =
370- VAR_UNKNOWN;
390+ if (i < closure_count)
371391 continue;
372- }
373392 }
374393
375394 *(stack + argcount + STACK_FRAME_SIZE + idx) = *tv;
376395 tv->v_type = VAR_UNKNOWN;
377396 }
378397
379- for (idx = 0; idx < dfunc->df_closure_count; ++idx)
398+ for (idx = 0; idx < closure_count; ++idx)
380399 {
381- tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE
382- + dfunc->df_varcount + idx);
383- if (tv->v_type == VAR_PARTIAL)
400+ partial_T *pt = ((partial_T **)gap->ga_data)[gap->ga_len
401+ - closure_count + idx];
402+ if (pt->pt_refcount > 1)
384403 {
385- partial_T *partial = tv->vval.v_partial;
386-
387- if (partial->pt_refcount > 1)
388- {
389- ++funcstack->fs_refcount;
390- partial->pt_funcstack = funcstack;
391- partial->pt_ectx_stack = &funcstack->fs_ga;
392- partial->pt_ectx_frame = ectx->ec_frame_idx - top;
393- }
404+ ++funcstack->fs_refcount;
405+ pt->pt_funcstack = funcstack;
406+ pt->pt_ectx_stack = &funcstack->fs_ga;
407+ pt->pt_ectx_frame = ectx->ec_frame_idx - top;
394408 }
395409 }
396410 }
397411
412+ for (idx = 0; idx < closure_count; ++idx)
413+ partial_unref(((partial_T **)gap->ga_data)[gap->ga_len
414+ - closure_count + idx]);
415+ gap->ga_len -= closure_count;
416+ if (gap->ga_len == 0)
417+ ga_clear(gap);
418+
398419 return OK;
399420 }
400421
@@ -809,6 +830,7 @@
809830 if (ga_grow(&ectx.ec_stack, 20) == FAIL)
810831 return FAIL;
811832 ga_init2(&ectx.ec_trystack, sizeof(trycmd_T), 10);
833+ ga_init2(&ectx.ec_funcrefs, sizeof(partial_T *), 10);
812834
813835 // Put arguments on the stack.
814836 for (idx = 0; idx < argc; ++idx)
@@ -896,14 +918,19 @@
896918 }
897919
898920 {
899- // Reserve space for local variables and closure references.
921+ // Reserve space for local variables and any closure reference count.
900922 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
901923 + ufunc->uf_dfunc_idx;
902- int count = dfunc->df_varcount + dfunc->df_closure_count;
903-
904- for (idx = 0; idx < count; ++idx)
924+
925+ for (idx = 0; idx < dfunc->df_varcount; ++idx)
905926 STACK_TV_VAR(idx)->v_type = VAR_UNKNOWN;
906- ectx.ec_stack.ga_len += count;
927+ ectx.ec_stack.ga_len += dfunc->df_varcount;
928+ if (dfunc->df_has_closure)
929+ {
930+ STACK_TV_VAR(idx)->v_type = VAR_NUMBER;
931+ STACK_TV_VAR(idx)->vval.v_number = 0;
932+ ++ectx.ec_stack.ga_len;
933+ }
907934
908935 ectx.ec_instr = dfunc->df_instr;
909936 }
@@ -1812,7 +1839,6 @@
18121839 + iptr->isn_arg.funcref.fr_func;
18131840 pt->pt_func = pt_dfunc->df_ufunc;
18141841 pt->pt_refcount = 1;
1815- ++pt_dfunc->df_ufunc->uf_refcount;
18161842
18171843 if (pt_dfunc->df_ufunc->uf_flags & FC_CLOSURE)
18181844 {
@@ -1825,23 +1851,25 @@
18251851 pt->pt_ectx_frame = ectx.ec_frame_idx;
18261852
18271853 // If this function returns and the closure is still
1828- // used, we need to make a copy of the context
1854+ // being used, we need to make a copy of the context
18291855 // (arguments and local variables). Store a reference
18301856 // to the partial so we can handle that.
1831- ++pt->pt_refcount;
1832- tv = STACK_TV_VAR(dfunc->df_varcount
1833- + iptr->isn_arg.funcref.fr_var_idx);
1834- if (tv->v_type == VAR_PARTIAL)
1857+ if (ga_grow(&ectx.ec_funcrefs, 1) == FAIL)
18351858 {
1836- // TODO: use a garray_T on ectx.
1837- SOURCING_LNUM = iptr->isn_lnum;
1838- emsg("Multiple closures not supported yet");
18391859 vim_free(pt);
18401860 goto failed;
18411861 }
1842- tv->v_type = VAR_PARTIAL;
1843- tv->vval.v_partial = pt;
1862+ // Extra variable keeps the count of closures created
1863+ // in the current function call.
1864+ tv = STACK_TV_VAR(dfunc->df_varcount);
1865+ ++tv->vval.v_number;
1866+
1867+ ((partial_T **)ectx.ec_funcrefs.ga_data)
1868+ [ectx.ec_funcrefs.ga_len] = pt;
1869+ ++pt->pt_refcount;
1870+ ++ectx.ec_funcrefs.ga_len;
18441871 }
1872+ ++pt_dfunc->df_ufunc->uf_refcount;
18451873
18461874 tv = STACK_TV_BOT(0);
18471875 ++ectx.ec_stack.ga_len;
@@ -3124,8 +3152,7 @@
31243152 dfunc_T *df = ((dfunc_T *)def_functions.ga_data)
31253153 + funcref->fr_func;
31263154
3127- smsg("%4d FUNCREF %s $%d", current, df->df_ufunc->uf_name,
3128- funcref->fr_var_idx + dfunc->df_varcount);
3155+ smsg("%4d FUNCREF %s", current, df->df_ufunc->uf_name);
31293156 }
31303157 break;
31313158
Show on old repository browser