Mercurial > vim
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 { |