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