Mercurial > vim
comparison src/eval.c @ 1891:7a4ad3fb109d v7.2.188
updated for version 7.2-188
author | vimboss |
---|---|
date | Sun, 24 May 2009 11:40:58 +0000 |
parents | e5602d92da8c |
children | afb740b5dfab |
comparison
equal
deleted
inserted
replaced
1890:2928a6b338c3 | 1891:7a4ad3fb109d |
---|---|
127 static hashtab_T compat_hashtab; | 127 static hashtab_T compat_hashtab; |
128 | 128 |
129 /* | 129 /* |
130 * When recursively copying lists and dicts we need to remember which ones we | 130 * When recursively copying lists and dicts we need to remember which ones we |
131 * have done to avoid endless recursiveness. This unique ID is used for that. | 131 * have done to avoid endless recursiveness. This unique ID is used for that. |
132 * The last bit is used for previous_funccal, ignored when comparing. | |
132 */ | 133 */ |
133 static int current_copyID = 0; | 134 static int current_copyID = 0; |
135 #define COPYID_INC 2 | |
136 #define COPYID_MASK (~0x1) | |
134 | 137 |
135 /* | 138 /* |
136 * Array to hold the hashtab with variables local to each sourced script. | 139 * Array to hold the hashtab with variables local to each sourced script. |
137 * Each item holds a variable (nameless) that points to the dict_T. | 140 * Each item holds a variable (nameless) that points to the dict_T. |
138 */ | 141 */ |
437 static int list_concat __ARGS((list_T *l1, list_T *l2, typval_T *tv)); | 440 static int list_concat __ARGS((list_T *l1, list_T *l2, typval_T *tv)); |
438 static list_T *list_copy __ARGS((list_T *orig, int deep, int copyID)); | 441 static list_T *list_copy __ARGS((list_T *orig, int deep, int copyID)); |
439 static void list_remove __ARGS((list_T *l, listitem_T *item, listitem_T *item2)); | 442 static void list_remove __ARGS((list_T *l, listitem_T *item, listitem_T *item2)); |
440 static char_u *list2string __ARGS((typval_T *tv, int copyID)); | 443 static char_u *list2string __ARGS((typval_T *tv, int copyID)); |
441 static int list_join __ARGS((garray_T *gap, list_T *l, char_u *sep, int echo, int copyID)); | 444 static int list_join __ARGS((garray_T *gap, list_T *l, char_u *sep, int echo, int copyID)); |
445 static int free_unref_items __ARGS((int copyID)); | |
442 static void set_ref_in_ht __ARGS((hashtab_T *ht, int copyID)); | 446 static void set_ref_in_ht __ARGS((hashtab_T *ht, int copyID)); |
443 static void set_ref_in_list __ARGS((list_T *l, int copyID)); | 447 static void set_ref_in_list __ARGS((list_T *l, int copyID)); |
444 static void set_ref_in_item __ARGS((typval_T *tv, int copyID)); | 448 static void set_ref_in_item __ARGS((typval_T *tv, int copyID)); |
445 static void dict_unref __ARGS((dict_T *d)); | 449 static void dict_unref __ARGS((dict_T *d)); |
446 static void dict_free __ARGS((dict_T *d, int recurse)); | 450 static void dict_free __ARGS((dict_T *d, int recurse)); |
6492 * Return TRUE if some memory was freed. | 6496 * Return TRUE if some memory was freed. |
6493 */ | 6497 */ |
6494 int | 6498 int |
6495 garbage_collect() | 6499 garbage_collect() |
6496 { | 6500 { |
6497 dict_T *dd; | 6501 int copyID; |
6498 list_T *ll; | |
6499 int copyID = ++current_copyID; | |
6500 buf_T *buf; | 6502 buf_T *buf; |
6501 win_T *wp; | 6503 win_T *wp; |
6502 int i; | 6504 int i; |
6503 funccall_T *fc, **pfc; | 6505 funccall_T *fc, **pfc; |
6504 int did_free = FALSE; | 6506 int did_free; |
6507 int did_free_funccal = FALSE; | |
6505 #ifdef FEAT_WINDOWS | 6508 #ifdef FEAT_WINDOWS |
6506 tabpage_T *tp; | 6509 tabpage_T *tp; |
6507 #endif | 6510 #endif |
6508 | 6511 |
6509 /* Only do this once. */ | 6512 /* Only do this once. */ |
6510 want_garbage_collect = FALSE; | 6513 want_garbage_collect = FALSE; |
6511 may_garbage_collect = FALSE; | 6514 may_garbage_collect = FALSE; |
6512 garbage_collect_at_exit = FALSE; | 6515 garbage_collect_at_exit = FALSE; |
6513 | 6516 |
6517 /* We advance by two because we add one for items referenced through | |
6518 * previous_funccal. */ | |
6519 current_copyID += COPYID_INC; | |
6520 copyID = current_copyID; | |
6521 | |
6514 /* | 6522 /* |
6515 * 1. Go through all accessible variables and mark all lists and dicts | 6523 * 1. Go through all accessible variables and mark all lists and dicts |
6516 * with copyID. | 6524 * with copyID. |
6517 */ | 6525 */ |
6526 | |
6527 /* Don't free variables in the previous_funccal list unless they are only | |
6528 * referenced through previous_funccal. This must be first, because if | |
6529 * the item is referenced elsewhere it must not be freed. */ | |
6530 for (fc = previous_funccal; fc != NULL; fc = fc->caller) | |
6531 { | |
6532 set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1); | |
6533 set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1); | |
6534 } | |
6535 | |
6518 /* script-local variables */ | 6536 /* script-local variables */ |
6519 for (i = 1; i <= ga_scripts.ga_len; ++i) | 6537 for (i = 1; i <= ga_scripts.ga_len; ++i) |
6520 set_ref_in_ht(&SCRIPT_VARS(i), copyID); | 6538 set_ref_in_ht(&SCRIPT_VARS(i), copyID); |
6521 | 6539 |
6522 /* buffer-local variables */ | 6540 /* buffer-local variables */ |
6544 } | 6562 } |
6545 | 6563 |
6546 /* v: vars */ | 6564 /* v: vars */ |
6547 set_ref_in_ht(&vimvarht, copyID); | 6565 set_ref_in_ht(&vimvarht, copyID); |
6548 | 6566 |
6567 /* Free lists and dictionaries that are not referenced. */ | |
6568 did_free = free_unref_items(copyID); | |
6569 | |
6570 /* check if any funccal can be freed now */ | |
6571 for (pfc = &previous_funccal; *pfc != NULL; ) | |
6572 { | |
6573 if (can_free_funccal(*pfc, copyID)) | |
6574 { | |
6575 fc = *pfc; | |
6576 *pfc = fc->caller; | |
6577 free_funccal(fc, TRUE); | |
6578 did_free = TRUE; | |
6579 did_free_funccal = TRUE; | |
6580 } | |
6581 else | |
6582 pfc = &(*pfc)->caller; | |
6583 } | |
6584 if (did_free_funccal) | |
6585 /* When a funccal was freed some more items might be garbage | |
6586 * collected, so run again. */ | |
6587 (void)garbage_collect(); | |
6588 | |
6589 return did_free; | |
6590 } | |
6591 | |
6592 /* | |
6593 * Free lists and dictionaries that are no longer referenced. | |
6594 */ | |
6595 static int | |
6596 free_unref_items(copyID) | |
6597 int copyID; | |
6598 { | |
6599 dict_T *dd; | |
6600 list_T *ll; | |
6601 int did_free = FALSE; | |
6602 | |
6549 /* | 6603 /* |
6550 * 2. Go through the list of dicts and free items without the copyID. | 6604 * Go through the list of dicts and free items without the copyID. |
6551 */ | 6605 */ |
6552 for (dd = first_dict; dd != NULL; ) | 6606 for (dd = first_dict; dd != NULL; ) |
6553 if (dd->dv_copyID != copyID) | 6607 if ((dd->dv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)) |
6554 { | 6608 { |
6555 /* Free the Dictionary and ordinary items it contains, but don't | 6609 /* Free the Dictionary and ordinary items it contains, but don't |
6556 * recurse into Lists and Dictionaries, they will be in the list | 6610 * recurse into Lists and Dictionaries, they will be in the list |
6557 * of dicts or list of lists. */ | 6611 * of dicts or list of lists. */ |
6558 dict_free(dd, FALSE); | 6612 dict_free(dd, FALSE); |
6563 } | 6617 } |
6564 else | 6618 else |
6565 dd = dd->dv_used_next; | 6619 dd = dd->dv_used_next; |
6566 | 6620 |
6567 /* | 6621 /* |
6568 * 3. Go through the list of lists and free items without the copyID. | 6622 * Go through the list of lists and free items without the copyID. |
6569 * But don't free a list that has a watcher (used in a for loop), these | 6623 * But don't free a list that has a watcher (used in a for loop), these |
6570 * are not referenced anywhere. | 6624 * are not referenced anywhere. |
6571 */ | 6625 */ |
6572 for (ll = first_list; ll != NULL; ) | 6626 for (ll = first_list; ll != NULL; ) |
6573 if (ll->lv_copyID != copyID && ll->lv_watch == NULL) | 6627 if ((ll->lv_copyID & COPYID_MASK) != (copyID & COPYID_MASK) |
6628 && ll->lv_watch == NULL) | |
6574 { | 6629 { |
6575 /* Free the List and ordinary items it contains, but don't recurse | 6630 /* Free the List and ordinary items it contains, but don't recurse |
6576 * into Lists and Dictionaries, they will be in the list of dicts | 6631 * into Lists and Dictionaries, they will be in the list of dicts |
6577 * or list of lists. */ | 6632 * or list of lists. */ |
6578 list_free(ll, FALSE); | 6633 list_free(ll, FALSE); |
6581 /* restart, next list may also have been freed */ | 6636 /* restart, next list may also have been freed */ |
6582 ll = first_list; | 6637 ll = first_list; |
6583 } | 6638 } |
6584 else | 6639 else |
6585 ll = ll->lv_used_next; | 6640 ll = ll->lv_used_next; |
6586 | |
6587 /* check if any funccal can be freed now */ | |
6588 for (pfc = &previous_funccal; *pfc != NULL; ) | |
6589 { | |
6590 if (can_free_funccal(*pfc, copyID)) | |
6591 { | |
6592 fc = *pfc; | |
6593 *pfc = fc->caller; | |
6594 free_funccal(fc, TRUE); | |
6595 did_free = TRUE; | |
6596 } | |
6597 else | |
6598 pfc = &(*pfc)->caller; | |
6599 } | |
6600 | 6641 |
6601 return did_free; | 6642 return did_free; |
6602 } | 6643 } |
6603 | 6644 |
6604 /* | 6645 /* |
18840 dict_T *dict; | 18881 dict_T *dict; |
18841 dictitem_T *dict_var; | 18882 dictitem_T *dict_var; |
18842 { | 18883 { |
18843 hash_init(&dict->dv_hashtab); | 18884 hash_init(&dict->dv_hashtab); |
18844 dict->dv_refcount = DO_NOT_FREE_CNT; | 18885 dict->dv_refcount = DO_NOT_FREE_CNT; |
18886 dict->dv_copyID = 0; | |
18845 dict_var->di_tv.vval.v_dict = dict; | 18887 dict_var->di_tv.vval.v_dict = dict; |
18846 dict_var->di_tv.v_type = VAR_DICT; | 18888 dict_var->di_tv.v_type = VAR_DICT; |
18847 dict_var->di_tv.v_lock = VAR_FIXED; | 18889 dict_var->di_tv.v_lock = VAR_FIXED; |
18848 dict_var->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; | 18890 dict_var->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; |
18849 dict_var->di_key[0] = NUL; | 18891 dict_var->di_key[0] = NUL; |
21292 | 21334 |
21293 did_emsg |= save_did_emsg; | 21335 did_emsg |= save_did_emsg; |
21294 current_funccal = fc->caller; | 21336 current_funccal = fc->caller; |
21295 --depth; | 21337 --depth; |
21296 | 21338 |
21297 /* if the a:000 list and the a: dict are not referenced we can free the | 21339 /* If the a:000 list and the l: and a: dicts are not referenced we can |
21298 * funccall_T and what's in it. */ | 21340 * free the funccall_T and what's in it. */ |
21299 if (fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT | 21341 if (fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT |
21300 && fc->l_vars.dv_refcount == DO_NOT_FREE_CNT | 21342 && fc->l_vars.dv_refcount == DO_NOT_FREE_CNT |
21301 && fc->l_avars.dv_refcount == DO_NOT_FREE_CNT) | 21343 && fc->l_avars.dv_refcount == DO_NOT_FREE_CNT) |
21302 { | 21344 { |
21303 free_funccal(fc, FALSE); | 21345 free_funccal(fc, FALSE); |
21332 } | 21374 } |
21333 } | 21375 } |
21334 | 21376 |
21335 /* | 21377 /* |
21336 * Return TRUE if items in "fc" do not have "copyID". That means they are not | 21378 * Return TRUE if items in "fc" do not have "copyID". That means they are not |
21337 * referenced from anywhere. | 21379 * referenced from anywhere that is in use. |
21338 */ | 21380 */ |
21339 static int | 21381 static int |
21340 can_free_funccal(fc, copyID) | 21382 can_free_funccal(fc, copyID) |
21341 funccall_T *fc; | 21383 funccall_T *fc; |
21342 int copyID; | 21384 int copyID; |