comparison src/vim9execute.c @ 20257:683c2da4982b v8.2.0684

patch 8.2.0684: Vim9: memory leak when using lambda Commit: https://github.com/vim/vim/commit/f7779c63d4fe531e2483502d4441f24802342768 Author: Bram Moolenaar <Bram@vim.org> Date: Sun May 3 15:38:16 2020 +0200 patch 8.2.0684: Vim9: memory leak when using lambda Problem: Vim9: memory leak when using lambda. Solution: Move the funccal context to the partial. Free the function when exiting.
author Bram Moolenaar <Bram@vim.org>
date Sun, 03 May 2020 15:45:05 +0200
parents aac52c32a91f
children 49b50843e725
comparison
equal deleted inserted replaced
20256:e08857045ec1 20257:683c2da4982b
230 // Set execution state to the start of the called function. 230 // Set execution state to the start of the called function.
231 ectx->ec_dfunc_idx = cdf_idx; 231 ectx->ec_dfunc_idx = cdf_idx;
232 ectx->ec_instr = dfunc->df_instr; 232 ectx->ec_instr = dfunc->df_instr;
233 estack_push_ufunc(ETYPE_UFUNC, dfunc->df_ufunc, 1); 233 estack_push_ufunc(ETYPE_UFUNC, dfunc->df_ufunc, 1);
234 234
235 // used for closures
236 ectx->ec_outer_stack = dfunc->df_ectx_stack;
237 ectx->ec_outer_frame = dfunc->df_ectx_frame;
238
239 // Decide where to start execution, handles optional arguments. 235 // Decide where to start execution, handles optional arguments.
240 init_instr_idx(ufunc, argcount, ectx); 236 init_instr_idx(ufunc, argcount, ectx);
241 237
242 return OK; 238 return OK;
243 } 239 }
267 for (idx = 0; idx < dfunc->df_closure_count; ++idx) 263 for (idx = 0; idx < dfunc->df_closure_count; ++idx)
268 { 264 {
269 tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE 265 tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE
270 + dfunc->df_varcount + idx); 266 + dfunc->df_varcount + idx);
271 if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial->pt_refcount > 1) 267 if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial->pt_refcount > 1)
268 {
272 closure_in_use = TRUE; 269 closure_in_use = TRUE;
270 break;
271 }
273 } 272 }
274 273
275 if (closure_in_use) 274 if (closure_in_use)
276 { 275 {
277 funcstack_T *funcstack = ALLOC_CLEAR_ONE(funcstack_T); 276 funcstack_T *funcstack = ALLOC_CLEAR_ONE(funcstack_T);
313 312
314 for (idx = 0; idx < dfunc->df_closure_count; ++idx) 313 for (idx = 0; idx < dfunc->df_closure_count; ++idx)
315 { 314 {
316 tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE 315 tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE
317 + dfunc->df_varcount + idx); 316 + dfunc->df_varcount + idx);
318 if (tv->v_type == VAR_PARTIAL 317 if (tv->v_type == VAR_PARTIAL)
319 && tv->vval.v_partial->pt_refcount > 1)
320 { 318 {
321 dfunc_T *pt_dfunc = ((dfunc_T *)def_functions.ga_data) 319 partial_T *partial = tv->vval.v_partial;
322 + tv->vval.v_partial->pt_func->uf_dfunc_idx; 320
323 ++funcstack->fs_refcount; 321 if (partial->pt_refcount > 1)
324 pt_dfunc->df_funcstack = funcstack; 322 {
325 pt_dfunc->df_ectx_stack = &funcstack->fs_ga; 323 ++funcstack->fs_refcount;
326 pt_dfunc->df_ectx_frame = ectx->ec_frame_idx - top; 324 partial->pt_funcstack = funcstack;
325 partial->pt_ectx_stack = &funcstack->fs_ga;
326 partial->pt_ectx_frame = ectx->ec_frame_idx - top;
327 }
327 } 328 }
328 } 329 }
329 } 330 }
330 331
331 return OK; 332 return OK;
513 if (tv->v_type == VAR_PARTIAL) 514 if (tv->v_type == VAR_PARTIAL)
514 { 515 {
515 partial_T *pt = tv->vval.v_partial; 516 partial_T *pt = tv->vval.v_partial;
516 517
517 if (pt->pt_func != NULL) 518 if (pt->pt_func != NULL)
518 return call_ufunc(pt->pt_func, argcount, ectx, NULL); 519 {
520 int ret = call_ufunc(pt->pt_func, argcount, ectx, NULL);
521
522 // closure may need the function context where it was defined
523 ectx->ec_outer_stack = pt->pt_ectx_stack;
524 ectx->ec_outer_frame = pt->pt_ectx_frame;
525
526 return ret;
527 }
519 name = pt->pt_name; 528 name = pt->pt_name;
520 } 529 }
521 else if (tv->v_type == VAR_FUNC) 530 else if (tv->v_type == VAR_FUNC)
522 name = tv->vval.v_string; 531 name = tv->vval.v_string;
523 if (name == NULL || call_by_name(name, argcount, ectx, NULL) == FAIL) 532 if (name == NULL || call_by_name(name, argcount, ectx, NULL) == FAIL)
1432 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) 1441 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
1433 + ectx.ec_dfunc_idx; 1442 + ectx.ec_dfunc_idx;
1434 1443
1435 // The closure needs to find arguments and local 1444 // The closure needs to find arguments and local
1436 // variables in the current stack. 1445 // variables in the current stack.
1437 pt_dfunc->df_ectx_stack = &ectx.ec_stack; 1446 pt->pt_ectx_stack = &ectx.ec_stack;
1438 pt_dfunc->df_ectx_frame = ectx.ec_frame_idx; 1447 pt->pt_ectx_frame = ectx.ec_frame_idx;
1439 1448
1440 // If this function returns and the closure is still 1449 // If this function returns and the closure is still
1441 // used, we need to make a copy of the context 1450 // used, we need to make a copy of the context
1442 // (arguments and local variables). Store a reference 1451 // (arguments and local variables). Store a reference
1443 // to the partial so we can handle that. 1452 // to the partial so we can handle that.
2674 return FAIL; 2683 return FAIL;
2675 } 2684 }
2676 return OK; 2685 return OK;
2677 } 2686 }
2678 2687
2679 /*
2680 * Mark items in a def function as used.
2681 */
2682 int
2683 set_ref_in_dfunc(ufunc_T *ufunc, int copyID)
2684 {
2685 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx;
2686 int abort = FALSE;
2687
2688 if (dfunc->df_funcstack != NULL)
2689 {
2690 typval_T *stack = dfunc->df_funcstack->fs_ga.ga_data;
2691 int idx;
2692
2693 for (idx = 0; idx < dfunc->df_funcstack->fs_ga.ga_len; ++idx)
2694 abort = abort || set_ref_in_item(stack + idx, copyID, NULL, NULL);
2695 }
2696 return abort;
2697 }
2698
2699 2688
2700 #endif // FEAT_EVAL 2689 #endif // FEAT_EVAL