comparison src/vim9execute.c @ 22371:15003353a464 v8.2.1734

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.
author Bram Moolenaar <Bram@vim.org>
date Wed, 23 Sep 2020 22:00:06 +0200
parents a4ed0de125d9
children a9fb7efa31d6
comparison
equal deleted inserted replaced
22370:9a06648f05d3 22371:15003353a464
65 int ec_in_catch; // when TRUE in catch or finally block 65 int ec_in_catch; // when TRUE in catch or finally block
66 66
67 int ec_dfunc_idx; // current function index 67 int ec_dfunc_idx; // current function index
68 isn_T *ec_instr; // array with instructions 68 isn_T *ec_instr; // array with instructions
69 int ec_iidx; // index in ec_instr: instruction to execute 69 int ec_iidx; // index in ec_instr: instruction to execute
70
71 garray_T ec_funcrefs; // partials that might be a closure
70 } ectx_T; 72 } ectx_T;
71 73
72 // Get pointer to item relative to the bottom of the stack, -1 is the last one. 74 // Get pointer to item relative to the bottom of the stack, -1 is the last one.
73 #define STACK_TV_BOT(idx) (((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_stack.ga_len + (idx)) 75 #define STACK_TV_BOT(idx) (((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_stack.ga_len + (idx))
74 76
163 int argcount = argcount_arg; 165 int argcount = argcount_arg;
164 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + cdf_idx; 166 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + cdf_idx;
165 ufunc_T *ufunc = dfunc->df_ufunc; 167 ufunc_T *ufunc = dfunc->df_ufunc;
166 int arg_to_add; 168 int arg_to_add;
167 int vararg_count = 0; 169 int vararg_count = 0;
170 int varcount;
168 int idx; 171 int idx;
169 estack_T *entry; 172 estack_T *entry;
170 173
171 if (dfunc->df_deleted) 174 if (dfunc->df_deleted)
172 { 175 {
210 emsg(_(e_one_argument_too_many)); 213 emsg(_(e_one_argument_too_many));
211 else 214 else
212 semsg(_(e_nr_arguments_too_many), -arg_to_add); 215 semsg(_(e_nr_arguments_too_many), -arg_to_add);
213 return FAIL; 216 return FAIL;
214 } 217 }
215 if (ga_grow(&ectx->ec_stack, arg_to_add + 3 218
216 + dfunc->df_varcount + dfunc->df_closure_count) == FAIL) 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)
217 return FAIL; 228 return FAIL;
218 229
219 // Move the vararg-list to below the missing optional arguments. 230 // Move the vararg-list to below the missing optional arguments.
220 if (vararg_count > 0 && arg_to_add > 0) 231 if (vararg_count > 0 && arg_to_add > 0)
221 *STACK_TV_BOT(arg_to_add - 1) = *STACK_TV_BOT(-1); 232 *STACK_TV_BOT(arg_to_add - 1) = *STACK_TV_BOT(-1);
230 STACK_TV_BOT(1)->vval.v_number = ectx->ec_iidx; 241 STACK_TV_BOT(1)->vval.v_number = ectx->ec_iidx;
231 STACK_TV_BOT(2)->vval.v_number = ectx->ec_frame_idx; 242 STACK_TV_BOT(2)->vval.v_number = ectx->ec_frame_idx;
232 ectx->ec_frame_idx = ectx->ec_stack.ga_len; 243 ectx->ec_frame_idx = ectx->ec_stack.ga_len;
233 244
234 // Initialize local variables 245 // 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)
236 STACK_TV_BOT(STACK_FRAME_SIZE + idx)->v_type = VAR_UNKNOWN; 247 STACK_TV_BOT(STACK_FRAME_SIZE + idx)->v_type = VAR_UNKNOWN;
237 ectx->ec_stack.ga_len += STACK_FRAME_SIZE 248 if (dfunc->df_has_closure)
238 + dfunc->df_varcount + dfunc->df_closure_count; 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;
239 256
240 // Set execution state to the start of the called function. 257 // Set execution state to the start of the called function.
241 ectx->ec_dfunc_idx = cdf_idx; 258 ectx->ec_dfunc_idx = cdf_idx;
242 ectx->ec_instr = dfunc->df_instr; 259 ectx->ec_instr = dfunc->df_instr;
243 entry = estack_push_ufunc(dfunc->df_ufunc, 1); 260 entry = estack_push_ufunc(dfunc->df_ufunc, 1);
273 int argcount; 290 int argcount;
274 int top; 291 int top;
275 int idx; 292 int idx;
276 typval_T *tv; 293 typval_T *tv;
277 int closure_in_use = FALSE; 294 int closure_in_use = FALSE;
295 garray_T *gap = &ectx->ec_funcrefs;
296 varnumber_T closure_count;
278 297
279 if (dfunc->df_ufunc == NULL) 298 if (dfunc->df_ufunc == NULL)
280 // function was freed 299 return OK; // function was freed
281 return OK; 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
282 argcount = ufunc_argcount(dfunc->df_ufunc); 307 argcount = ufunc_argcount(dfunc->df_ufunc);
283 top = ectx->ec_frame_idx - argcount; 308 top = ectx->ec_frame_idx - argcount;
284 309
285 // Check if any created closure is still in use. 310 // 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)
287 { 312 {
288 tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE 313 partial_T *pt = ((partial_T **)gap->ga_data)[gap->ga_len
289 + dfunc->df_varcount + idx); 314 - closure_count + idx];
290 if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL 315
291 && tv->vval.v_partial->pt_refcount > 1) 316 if (pt->pt_refcount > 1)
292 { 317 {
293 int refcount = tv->vval.v_partial->pt_refcount; 318 int refcount = pt->pt_refcount;
294 int i; 319 int i;
295 320
296 // A Reference in a local variables doesn't count, it gets 321 // A Reference in a local variables doesn't count, it gets
297 // unreferenced on return. 322 // unreferenced on return.
298 for (i = 0; i < dfunc->df_varcount; ++i) 323 for (i = 0; i < dfunc->df_varcount; ++i)
299 { 324 {
300 typval_T *stv = STACK_TV(ectx->ec_frame_idx 325 typval_T *stv = STACK_TV(ectx->ec_frame_idx
301 + STACK_FRAME_SIZE + i); 326 + STACK_FRAME_SIZE + i);
302 if (stv->v_type == VAR_PARTIAL 327 if (stv->v_type == VAR_PARTIAL && pt == stv->vval.v_partial)
303 && tv->vval.v_partial == stv->vval.v_partial)
304 --refcount; 328 --refcount;
305 } 329 }
306 if (refcount > 1) 330 if (refcount > 1)
307 { 331 {
308 closure_in_use = TRUE; 332 closure_in_use = TRUE;
353 // inside the partial, thus needs special handling for garbage 377 // inside the partial, thus needs special handling for garbage
354 // collection. 378 // collection.
355 if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL) 379 if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL)
356 { 380 {
357 int i; 381 int i;
358 typval_T *ctv; 382
359 383 for (i = 0; i < closure_count; ++i)
360 for (i = 0; i < dfunc->df_closure_count; ++i) 384 {
361 { 385 partial_T *pt = ((partial_T **)gap->ga_data)[gap->ga_len
362 ctv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE 386 - closure_count + i];
363 + dfunc->df_varcount + i); 387 if (tv->vval.v_partial == pt)
364 if (tv->vval.v_partial == ctv->vval.v_partial)
365 break; 388 break;
366 } 389 }
367 if (i < dfunc->df_closure_count) 390 if (i < closure_count)
368 {
369 (stack + argcount + STACK_FRAME_SIZE + idx)->v_type =
370 VAR_UNKNOWN;
371 continue; 391 continue;
372 }
373 } 392 }
374 393
375 *(stack + argcount + STACK_FRAME_SIZE + idx) = *tv; 394 *(stack + argcount + STACK_FRAME_SIZE + idx) = *tv;
376 tv->v_type = VAR_UNKNOWN; 395 tv->v_type = VAR_UNKNOWN;
377 } 396 }
378 397
379 for (idx = 0; idx < dfunc->df_closure_count; ++idx) 398 for (idx = 0; idx < closure_count; ++idx)
380 { 399 {
381 tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE 400 partial_T *pt = ((partial_T **)gap->ga_data)[gap->ga_len
382 + dfunc->df_varcount + idx); 401 - closure_count + idx];
383 if (tv->v_type == VAR_PARTIAL) 402 if (pt->pt_refcount > 1)
384 { 403 {
385 partial_T *partial = tv->vval.v_partial; 404 ++funcstack->fs_refcount;
386 405 pt->pt_funcstack = funcstack;
387 if (partial->pt_refcount > 1) 406 pt->pt_ectx_stack = &funcstack->fs_ga;
388 { 407 pt->pt_ectx_frame = ectx->ec_frame_idx - top;
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 }
394 } 408 }
395 } 409 }
396 } 410 }
411
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);
397 418
398 return OK; 419 return OK;
399 } 420 }
400 421
401 /* 422 /*
807 ectx.ec_dfunc_idx = ufunc->uf_dfunc_idx; 828 ectx.ec_dfunc_idx = ufunc->uf_dfunc_idx;
808 ga_init2(&ectx.ec_stack, sizeof(typval_T), 500); 829 ga_init2(&ectx.ec_stack, sizeof(typval_T), 500);
809 if (ga_grow(&ectx.ec_stack, 20) == FAIL) 830 if (ga_grow(&ectx.ec_stack, 20) == FAIL)
810 return FAIL; 831 return FAIL;
811 ga_init2(&ectx.ec_trystack, sizeof(trycmd_T), 10); 832 ga_init2(&ectx.ec_trystack, sizeof(trycmd_T), 10);
833 ga_init2(&ectx.ec_funcrefs, sizeof(partial_T *), 10);
812 834
813 // Put arguments on the stack. 835 // Put arguments on the stack.
814 for (idx = 0; idx < argc; ++idx) 836 for (idx = 0; idx < argc; ++idx)
815 { 837 {
816 if (ufunc->uf_arg_types != NULL && idx < ufunc->uf_args.ga_len 838 if (ufunc->uf_arg_types != NULL && idx < ufunc->uf_args.ga_len
894 STACK_TV(ectx.ec_stack.ga_len)->v_type = VAR_UNKNOWN; 916 STACK_TV(ectx.ec_stack.ga_len)->v_type = VAR_UNKNOWN;
895 ++ectx.ec_stack.ga_len; 917 ++ectx.ec_stack.ga_len;
896 } 918 }
897 919
898 { 920 {
899 // Reserve space for local variables and closure references. 921 // Reserve space for local variables and any closure reference count.
900 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) 922 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
901 + ufunc->uf_dfunc_idx; 923 + ufunc->uf_dfunc_idx;
902 int count = dfunc->df_varcount + dfunc->df_closure_count; 924
903 925 for (idx = 0; idx < dfunc->df_varcount; ++idx)
904 for (idx = 0; idx < count; ++idx)
905 STACK_TV_VAR(idx)->v_type = VAR_UNKNOWN; 926 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 }
907 934
908 ectx.ec_instr = dfunc->df_instr; 935 ectx.ec_instr = dfunc->df_instr;
909 } 936 }
910 937
911 // Following errors are in the function, not the caller. 938 // Following errors are in the function, not the caller.
1810 } 1837 }
1811 pt_dfunc = ((dfunc_T *)def_functions.ga_data) 1838 pt_dfunc = ((dfunc_T *)def_functions.ga_data)
1812 + iptr->isn_arg.funcref.fr_func; 1839 + iptr->isn_arg.funcref.fr_func;
1813 pt->pt_func = pt_dfunc->df_ufunc; 1840 pt->pt_func = pt_dfunc->df_ufunc;
1814 pt->pt_refcount = 1; 1841 pt->pt_refcount = 1;
1815 ++pt_dfunc->df_ufunc->uf_refcount;
1816 1842
1817 if (pt_dfunc->df_ufunc->uf_flags & FC_CLOSURE) 1843 if (pt_dfunc->df_ufunc->uf_flags & FC_CLOSURE)
1818 { 1844 {
1819 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) 1845 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
1820 + ectx.ec_dfunc_idx; 1846 + ectx.ec_dfunc_idx;
1823 // variables in the current stack. 1849 // variables in the current stack.
1824 pt->pt_ectx_stack = &ectx.ec_stack; 1850 pt->pt_ectx_stack = &ectx.ec_stack;
1825 pt->pt_ectx_frame = ectx.ec_frame_idx; 1851 pt->pt_ectx_frame = ectx.ec_frame_idx;
1826 1852
1827 // If this function returns and the closure is still 1853 // 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
1829 // (arguments and local variables). Store a reference 1855 // (arguments and local variables). Store a reference
1830 // to the partial so we can handle that. 1856 // to the partial so we can handle that.
1831 ++pt->pt_refcount; 1857 if (ga_grow(&ectx.ec_funcrefs, 1) == FAIL)
1832 tv = STACK_TV_VAR(dfunc->df_varcount
1833 + iptr->isn_arg.funcref.fr_var_idx);
1834 if (tv->v_type == VAR_PARTIAL)
1835 { 1858 {
1836 // TODO: use a garray_T on ectx.
1837 SOURCING_LNUM = iptr->isn_lnum;
1838 emsg("Multiple closures not supported yet");
1839 vim_free(pt); 1859 vim_free(pt);
1840 goto failed; 1860 goto failed;
1841 } 1861 }
1842 tv->v_type = VAR_PARTIAL; 1862 // Extra variable keeps the count of closures created
1843 tv->vval.v_partial = pt; 1863 // in the current function call.
1844 } 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;
1871 }
1872 ++pt_dfunc->df_ufunc->uf_refcount;
1845 1873
1846 tv = STACK_TV_BOT(0); 1874 tv = STACK_TV_BOT(0);
1847 ++ectx.ec_stack.ga_len; 1875 ++ectx.ec_stack.ga_len;
1848 tv->vval.v_partial = pt; 1876 tv->vval.v_partial = pt;
1849 tv->v_type = VAR_PARTIAL; 1877 tv->v_type = VAR_PARTIAL;
3122 { 3150 {
3123 funcref_T *funcref = &iptr->isn_arg.funcref; 3151 funcref_T *funcref = &iptr->isn_arg.funcref;
3124 dfunc_T *df = ((dfunc_T *)def_functions.ga_data) 3152 dfunc_T *df = ((dfunc_T *)def_functions.ga_data)
3125 + funcref->fr_func; 3153 + funcref->fr_func;
3126 3154
3127 smsg("%4d FUNCREF %s $%d", current, df->df_ufunc->uf_name, 3155 smsg("%4d FUNCREF %s", current, df->df_ufunc->uf_name);
3128 funcref->fr_var_idx + dfunc->df_varcount);
3129 } 3156 }
3130 break; 3157 break;
3131 3158
3132 case ISN_NEWFUNC: 3159 case ISN_NEWFUNC:
3133 { 3160 {