aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorStefan Monnier2012-11-08 14:12:23 -0500
committerStefan Monnier2012-11-08 14:12:23 -0500
commitb7432bb20f48902994bee522bea15acdb0c0e209 (patch)
tree940e242625e16ade096c4144d728c56107aa7005 /src
parent880027430c5580abf612a82273bd49b75b9fb73c (diff)
downloademacs-b7432bb20f48902994bee522bea15acdb0c0e209.tar.gz
emacs-b7432bb20f48902994bee522bea15acdb0c0e209.zip
Use ad-hoc comparison function for the profiler's hash-tables.
* src/profiler.c (Qprofiler_backtrace_equal, hashtest_profiler): New vars. (make_log): Use them. (handle_profiler_signal): Don't inhibit quit any longer since we don't call Fequal any more. (Ffunction_equal): New function. (cmpfn_profiler, hashfn_profiler): New functions. (syms_of_profiler): Initialize them. * src/lisp.h (struct hash_table_test): New struct. (struct Lisp_Hash_Table): Use it. * src/alloc.c (mark_object): Mark hash_table_test fields of hash tables. * src/fns.c (make_hash_table): Take a struct to describe the test. (cmpfn_eql, cmpfn_equal, cmpfn_user_defined, hashfn_eq, hashfn_eql) (hashfn_equal, hashfn_user_defined): Adjust to new calling convention. (hash_lookup, hash_remove_from_table): Move assertion checking of hashfn result here. Check hash-equality before calling cmpfn. (Fmake_hash_table): Adjust call to make_hash_table. (hashtest_eq, hashtest_eql, hashtest_equal): New structs. (syms_of_fns): Initialize them. * src/emacs.c (main): Move syms_of_fns earlier. * src/xterm.c (syms_of_xterm): * src/category.c (hash_get_category_set): Adjust call to make_hash_table. * src/print.c (print_object): Adjust to new hash-table struct. * src/composite.c (composition_gstring_put_cache): Adjust to new hashfn.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog27
-rw-r--r--src/alloc.c3
-rw-r--r--src/category.c4
-rw-r--r--src/composite.c4
-rw-r--r--src/emacs.c4
-rw-r--r--src/fns.c138
-rw-r--r--src/lisp.h44
-rw-r--r--src/print.c6
-rw-r--r--src/profiler.c91
-rw-r--r--src/regex.c2
-rw-r--r--src/xterm.c4
11 files changed, 204 insertions, 123 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 8f2aa41bef0..24f3305b870 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,30 @@
12012-11-08 Stefan Monnier <monnier@iro.umontreal.ca>
2
3 Use ad-hoc comparison function for the profiler's hash-tables.
4 * profiler.c (Qprofiler_backtrace_equal, hashtest_profiler): New vars.
5 (make_log): Use them.
6 (handle_profiler_signal): Don't inhibit quit any longer since we don't
7 call Fequal any more.
8 (Ffunction_equal): New function.
9 (cmpfn_profiler, hashfn_profiler): New functions.
10 (syms_of_profiler): Initialize them.
11 * lisp.h (struct hash_table_test): New struct.
12 (struct Lisp_Hash_Table): Use it.
13 * alloc.c (mark_object): Mark hash_table_test fields of hash tables.
14 * fns.c (make_hash_table): Take a struct to describe the test.
15 (cmpfn_eql, cmpfn_equal, cmpfn_user_defined, hashfn_eq, hashfn_eql)
16 (hashfn_equal, hashfn_user_defined): Adjust to new calling convention.
17 (hash_lookup, hash_remove_from_table): Move assertion checking of
18 hashfn result here. Check hash-equality before calling cmpfn.
19 (Fmake_hash_table): Adjust call to make_hash_table.
20 (hashtest_eq, hashtest_eql, hashtest_equal): New structs.
21 (syms_of_fns): Initialize them.
22 * emacs.c (main): Move syms_of_fns earlier.
23 * xterm.c (syms_of_xterm):
24 * category.c (hash_get_category_set): Adjust call to make_hash_table.
25 * print.c (print_object): Adjust to new hash-table struct.
26 * composite.c (composition_gstring_put_cache): Adjust to new hashfn.
27
12012-11-08 Eli Zaretskii <eliz@gnu.org> 282012-11-08 Eli Zaretskii <eliz@gnu.org>
2 29
3 * w32fns.c (modifier_set): Fix handling of Scroll Lock when the 30 * w32fns.c (modifier_set): Fix handling of Scroll Lock when the
diff --git a/src/alloc.c b/src/alloc.c
index 557c68ca5af..808557dd70f 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -5809,6 +5809,9 @@ mark_object (Lisp_Object arg)
5809 struct Lisp_Hash_Table *h = (struct Lisp_Hash_Table *) ptr; 5809 struct Lisp_Hash_Table *h = (struct Lisp_Hash_Table *) ptr;
5810 5810
5811 mark_vectorlike (ptr); 5811 mark_vectorlike (ptr);
5812 mark_object (h->test.name);
5813 mark_object (h->test.user_hash_function);
5814 mark_object (h->test.user_cmp_function);
5812 /* If hash table is not weak, mark all keys and values. 5815 /* If hash table is not weak, mark all keys and values.
5813 For weak tables, mark only the vector. */ 5816 For weak tables, mark only the vector. */
5814 if (NILP (h->weak)) 5817 if (NILP (h->weak))
diff --git a/src/category.c b/src/category.c
index fe02303f679..31cc90bca68 100644
--- a/src/category.c
+++ b/src/category.c
@@ -78,10 +78,10 @@ hash_get_category_set (Lisp_Object table, Lisp_Object category_set)
78 if (NILP (XCHAR_TABLE (table)->extras[1])) 78 if (NILP (XCHAR_TABLE (table)->extras[1]))
79 set_char_table_extras 79 set_char_table_extras
80 (table, 1, 80 (table, 1,
81 make_hash_table (Qequal, make_number (DEFAULT_HASH_SIZE), 81 make_hash_table (hashtest_equal, make_number (DEFAULT_HASH_SIZE),
82 make_float (DEFAULT_REHASH_SIZE), 82 make_float (DEFAULT_REHASH_SIZE),
83 make_float (DEFAULT_REHASH_THRESHOLD), 83 make_float (DEFAULT_REHASH_THRESHOLD),
84 Qnil, Qnil, Qnil)); 84 Qnil));
85 h = XHASH_TABLE (XCHAR_TABLE (table)->extras[1]); 85 h = XHASH_TABLE (XCHAR_TABLE (table)->extras[1]);
86 i = hash_lookup (h, category_set, &hash); 86 i = hash_lookup (h, category_set, &hash);
87 if (i >= 0) 87 if (i >= 0)
diff --git a/src/composite.c b/src/composite.c
index 6c603fab3fc..bcde0a4c9e6 100644
--- a/src/composite.c
+++ b/src/composite.c
@@ -676,7 +676,7 @@ composition_gstring_put_cache (Lisp_Object gstring, ptrdiff_t len)
676 ptrdiff_t i; 676 ptrdiff_t i;
677 677
678 header = LGSTRING_HEADER (gstring); 678 header = LGSTRING_HEADER (gstring);
679 hash = h->hashfn (h, header); 679 hash = h->test.hashfn (&h->test, header);
680 if (len < 0) 680 if (len < 0)
681 { 681 {
682 ptrdiff_t j, glyph_len = LGSTRING_GLYPH_LEN (gstring); 682 ptrdiff_t j, glyph_len = LGSTRING_GLYPH_LEN (gstring);
@@ -1382,7 +1382,7 @@ composition_update_it (struct composition_it *cmp_it, ptrdiff_t charpos, ptrdiff
1382 } 1382 }
1383 else 1383 else
1384 { 1384 {
1385 /* automatic composition */ 1385 /* Automatic composition. */
1386 Lisp_Object gstring = composition_gstring_from_id (cmp_it->id); 1386 Lisp_Object gstring = composition_gstring_from_id (cmp_it->id);
1387 Lisp_Object glyph; 1387 Lisp_Object glyph;
1388 ptrdiff_t from; 1388 ptrdiff_t from;
diff --git a/src/emacs.c b/src/emacs.c
index f12713b9628..fee9c332c55 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -1154,6 +1154,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1154 1154
1155 /* Called before syms_of_fileio, because it sets up Qerror_condition. */ 1155 /* Called before syms_of_fileio, because it sets up Qerror_condition. */
1156 syms_of_data (); 1156 syms_of_data ();
1157 syms_of_fns (); /* Before syms_of_charset which uses hashtables. */
1157 syms_of_fileio (); 1158 syms_of_fileio ();
1158 /* Before syms_of_coding to initialize Vgc_cons_threshold. */ 1159 /* Before syms_of_coding to initialize Vgc_cons_threshold. */
1159 syms_of_alloc (); 1160 syms_of_alloc ();
@@ -1165,7 +1166,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1165 1166
1166 init_window_once (); /* Init the window system. */ 1167 init_window_once (); /* Init the window system. */
1167#ifdef HAVE_WINDOW_SYSTEM 1168#ifdef HAVE_WINDOW_SYSTEM
1168 init_fringe_once (); /* Swap bitmaps if necessary. */ 1169 init_fringe_once (); /* Swap bitmaps if necessary. */
1169#endif /* HAVE_WINDOW_SYSTEM */ 1170#endif /* HAVE_WINDOW_SYSTEM */
1170 } 1171 }
1171 1172
@@ -1348,7 +1349,6 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1348 syms_of_lread (); 1349 syms_of_lread ();
1349 syms_of_print (); 1350 syms_of_print ();
1350 syms_of_eval (); 1351 syms_of_eval ();
1351 syms_of_fns ();
1352 syms_of_floatfns (); 1352 syms_of_floatfns ();
1353 1353
1354 syms_of_buffer (); 1354 syms_of_buffer ();
diff --git a/src/fns.c b/src/fns.c
index 1d2e510b7e5..6faaa67152e 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -2014,7 +2014,7 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props)
2014 d1 = extract_float (o1); 2014 d1 = extract_float (o1);
2015 d2 = extract_float (o2); 2015 d2 = extract_float (o2);
2016 /* If d is a NaN, then d != d. Two NaNs should be `equal' even 2016 /* If d is a NaN, then d != d. Two NaNs should be `equal' even
2017 though they are not =. */ 2017 though they are not =. */
2018 return d1 == d2 || (d1 != d1 && d2 != d2); 2018 return d1 == d2 || (d1 != d1 && d2 != d2);
2019 } 2019 }
2020 2020
@@ -3424,14 +3424,16 @@ larger_vector (Lisp_Object vec, ptrdiff_t incr_min, ptrdiff_t nitems_max)
3424 Low-level Functions 3424 Low-level Functions
3425 ***********************************************************************/ 3425 ***********************************************************************/
3426 3426
3427struct hash_table_test hashtest_eq, hashtest_eql, hashtest_equal;
3428
3427/* Compare KEY1 which has hash code HASH1 and KEY2 with hash code 3429/* Compare KEY1 which has hash code HASH1 and KEY2 with hash code
3428 HASH2 in hash table H using `eql'. Value is true if KEY1 and 3430 HASH2 in hash table H using `eql'. Value is true if KEY1 and
3429 KEY2 are the same. */ 3431 KEY2 are the same. */
3430 3432
3431static bool 3433static bool
3432cmpfn_eql (struct Lisp_Hash_Table *h, 3434cmpfn_eql (struct hash_table_test *ht,
3433 Lisp_Object key1, EMACS_UINT hash1, 3435 Lisp_Object key1,
3434 Lisp_Object key2, EMACS_UINT hash2) 3436 Lisp_Object key2)
3435{ 3437{
3436 return (FLOATP (key1) 3438 return (FLOATP (key1)
3437 && FLOATP (key2) 3439 && FLOATP (key2)
@@ -3444,11 +3446,11 @@ cmpfn_eql (struct Lisp_Hash_Table *h,
3444 KEY2 are the same. */ 3446 KEY2 are the same. */
3445 3447
3446static bool 3448static bool
3447cmpfn_equal (struct Lisp_Hash_Table *h, 3449cmpfn_equal (struct hash_table_test *ht,
3448 Lisp_Object key1, EMACS_UINT hash1, 3450 Lisp_Object key1,
3449 Lisp_Object key2, EMACS_UINT hash2) 3451 Lisp_Object key2)
3450{ 3452{
3451 return hash1 == hash2 && !NILP (Fequal (key1, key2)); 3453 return !NILP (Fequal (key1, key2));
3452} 3454}
3453 3455
3454 3456
@@ -3457,21 +3459,16 @@ cmpfn_equal (struct Lisp_Hash_Table *h,
3457 if KEY1 and KEY2 are the same. */ 3459 if KEY1 and KEY2 are the same. */
3458 3460
3459static bool 3461static bool
3460cmpfn_user_defined (struct Lisp_Hash_Table *h, 3462cmpfn_user_defined (struct hash_table_test *ht,
3461 Lisp_Object key1, EMACS_UINT hash1, 3463 Lisp_Object key1,
3462 Lisp_Object key2, EMACS_UINT hash2) 3464 Lisp_Object key2)
3463{ 3465{
3464 if (hash1 == hash2) 3466 Lisp_Object args[3];
3465 {
3466 Lisp_Object args[3];
3467 3467
3468 args[0] = h->user_cmp_function; 3468 args[0] = ht->user_cmp_function;
3469 args[1] = key1; 3469 args[1] = key1;
3470 args[2] = key2; 3470 args[2] = key2;
3471 return !NILP (Ffuncall (3, args)); 3471 return !NILP (Ffuncall (3, args));
3472 }
3473 else
3474 return 0;
3475} 3472}
3476 3473
3477 3474
@@ -3480,54 +3477,48 @@ cmpfn_user_defined (struct Lisp_Hash_Table *h,
3480 in a Lisp integer. */ 3477 in a Lisp integer. */
3481 3478
3482static EMACS_UINT 3479static EMACS_UINT
3483hashfn_eq (struct Lisp_Hash_Table *h, Lisp_Object key) 3480hashfn_eq (struct hash_table_test *ht, Lisp_Object key)
3484{ 3481{
3485 EMACS_UINT hash = XUINT (key) ^ XTYPE (key); 3482 EMACS_UINT hash = XUINT (key) ^ XTYPE (key);
3486 eassert ((hash & ~INTMASK) == 0);
3487 return hash; 3483 return hash;
3488} 3484}
3489 3485
3490
3491/* Value is a hash code for KEY for use in hash table H which uses 3486/* Value is a hash code for KEY for use in hash table H which uses
3492 `eql' to compare keys. The hash code returned is guaranteed to fit 3487 `eql' to compare keys. The hash code returned is guaranteed to fit
3493 in a Lisp integer. */ 3488 in a Lisp integer. */
3494 3489
3495static EMACS_UINT 3490static EMACS_UINT
3496hashfn_eql (struct Lisp_Hash_Table *h, Lisp_Object key) 3491hashfn_eql (struct hash_table_test *ht, Lisp_Object key)
3497{ 3492{
3498 EMACS_UINT hash; 3493 EMACS_UINT hash;
3499 if (FLOATP (key)) 3494 if (FLOATP (key))
3500 hash = sxhash (key, 0); 3495 hash = sxhash (key, 0);
3501 else 3496 else
3502 hash = XUINT (key) ^ XTYPE (key); 3497 hash = XUINT (key) ^ XTYPE (key);
3503 eassert ((hash & ~INTMASK) == 0);
3504 return hash; 3498 return hash;
3505} 3499}
3506 3500
3507
3508/* Value is a hash code for KEY for use in hash table H which uses 3501/* Value is a hash code for KEY for use in hash table H which uses
3509 `equal' to compare keys. The hash code returned is guaranteed to fit 3502 `equal' to compare keys. The hash code returned is guaranteed to fit
3510 in a Lisp integer. */ 3503 in a Lisp integer. */
3511 3504
3512static EMACS_UINT 3505static EMACS_UINT
3513hashfn_equal (struct Lisp_Hash_Table *h, Lisp_Object key) 3506hashfn_equal (struct hash_table_test *ht, Lisp_Object key)
3514{ 3507{
3515 EMACS_UINT hash = sxhash (key, 0); 3508 EMACS_UINT hash = sxhash (key, 0);
3516 eassert ((hash & ~INTMASK) == 0);
3517 return hash; 3509 return hash;
3518} 3510}
3519 3511
3520
3521/* Value is a hash code for KEY for use in hash table H which uses as 3512/* Value is a hash code for KEY for use in hash table H which uses as
3522 user-defined function to compare keys. The hash code returned is 3513 user-defined function to compare keys. The hash code returned is
3523 guaranteed to fit in a Lisp integer. */ 3514 guaranteed to fit in a Lisp integer. */
3524 3515
3525static EMACS_UINT 3516static EMACS_UINT
3526hashfn_user_defined (struct Lisp_Hash_Table *h, Lisp_Object key) 3517hashfn_user_defined (struct hash_table_test *ht, Lisp_Object key)
3527{ 3518{
3528 Lisp_Object args[2], hash; 3519 Lisp_Object args[2], hash;
3529 3520
3530 args[0] = h->user_hash_function; 3521 args[0] = ht->user_hash_function;
3531 args[1] = key; 3522 args[1] = key;
3532 hash = Ffuncall (2, args); 3523 hash = Ffuncall (2, args);
3533 if (!INTEGERP (hash)) 3524 if (!INTEGERP (hash))
@@ -3563,9 +3554,9 @@ hashfn_user_defined (struct Lisp_Hash_Table *h, Lisp_Object key)
3563 one of the symbols `key', `value', `key-or-value', or `key-and-value'. */ 3554 one of the symbols `key', `value', `key-or-value', or `key-and-value'. */
3564 3555
3565Lisp_Object 3556Lisp_Object
3566make_hash_table (Lisp_Object test, Lisp_Object size, Lisp_Object rehash_size, 3557make_hash_table (struct hash_table_test test,
3567 Lisp_Object rehash_threshold, Lisp_Object weak, 3558 Lisp_Object size, Lisp_Object rehash_size,
3568 Lisp_Object user_test, Lisp_Object user_hash) 3559 Lisp_Object rehash_threshold, Lisp_Object weak)
3569{ 3560{
3570 struct Lisp_Hash_Table *h; 3561 struct Lisp_Hash_Table *h;
3571 Lisp_Object table; 3562 Lisp_Object table;
@@ -3574,7 +3565,7 @@ make_hash_table (Lisp_Object test, Lisp_Object size, Lisp_Object rehash_size,
3574 double index_float; 3565 double index_float;
3575 3566
3576 /* Preconditions. */ 3567 /* Preconditions. */
3577 eassert (SYMBOLP (test)); 3568 eassert (SYMBOLP (test.name));
3578 eassert (INTEGERP (size) && XINT (size) >= 0); 3569 eassert (INTEGERP (size) && XINT (size) >= 0);
3579 eassert ((INTEGERP (rehash_size) && XINT (rehash_size) > 0) 3570 eassert ((INTEGERP (rehash_size) && XINT (rehash_size) > 0)
3580 || (FLOATP (rehash_size) && 1 < XFLOAT_DATA (rehash_size))); 3571 || (FLOATP (rehash_size) && 1 < XFLOAT_DATA (rehash_size)));
@@ -3598,29 +3589,6 @@ make_hash_table (Lisp_Object test, Lisp_Object size, Lisp_Object rehash_size,
3598 3589
3599 /* Initialize hash table slots. */ 3590 /* Initialize hash table slots. */
3600 h->test = test; 3591 h->test = test;
3601 if (EQ (test, Qeql))
3602 {
3603 h->cmpfn = cmpfn_eql;
3604 h->hashfn = hashfn_eql;
3605 }
3606 else if (EQ (test, Qeq))
3607 {
3608 h->cmpfn = NULL;
3609 h->hashfn = hashfn_eq;
3610 }
3611 else if (EQ (test, Qequal))
3612 {
3613 h->cmpfn = cmpfn_equal;
3614 h->hashfn = hashfn_equal;
3615 }
3616 else
3617 {
3618 h->user_cmp_function = user_test;
3619 h->user_hash_function = user_hash;
3620 h->cmpfn = cmpfn_user_defined;
3621 h->hashfn = hashfn_user_defined;
3622 }
3623
3624 h->weak = weak; 3592 h->weak = weak;
3625 h->rehash_threshold = rehash_threshold; 3593 h->rehash_threshold = rehash_threshold;
3626 h->rehash_size = rehash_size; 3594 h->rehash_size = rehash_size;
@@ -3776,7 +3744,8 @@ hash_lookup (struct Lisp_Hash_Table *h, Lisp_Object key, EMACS_UINT *hash)
3776 ptrdiff_t start_of_bucket; 3744 ptrdiff_t start_of_bucket;
3777 Lisp_Object idx; 3745 Lisp_Object idx;
3778 3746
3779 hash_code = h->hashfn (h, key); 3747 hash_code = h->test.hashfn (&h->test, key);
3748 eassert ((hash_code & ~INTMASK) == 0);
3780 if (hash) 3749 if (hash)
3781 *hash = hash_code; 3750 *hash = hash_code;
3782 3751
@@ -3788,9 +3757,9 @@ hash_lookup (struct Lisp_Hash_Table *h, Lisp_Object key, EMACS_UINT *hash)
3788 { 3757 {
3789 ptrdiff_t i = XFASTINT (idx); 3758 ptrdiff_t i = XFASTINT (idx);
3790 if (EQ (key, HASH_KEY (h, i)) 3759 if (EQ (key, HASH_KEY (h, i))
3791 || (h->cmpfn 3760 || (h->test.cmpfn
3792 && h->cmpfn (h, key, hash_code, 3761 && hash_code == XUINT (HASH_HASH (h, i))
3793 HASH_KEY (h, i), XUINT (HASH_HASH (h, i))))) 3762 && h->test.cmpfn (&h->test, key, HASH_KEY (h, i))))
3794 break; 3763 break;
3795 idx = HASH_NEXT (h, i); 3764 idx = HASH_NEXT (h, i);
3796 } 3765 }
@@ -3841,7 +3810,8 @@ hash_remove_from_table (struct Lisp_Hash_Table *h, Lisp_Object key)
3841 ptrdiff_t start_of_bucket; 3810 ptrdiff_t start_of_bucket;
3842 Lisp_Object idx, prev; 3811 Lisp_Object idx, prev;
3843 3812
3844 hash_code = h->hashfn (h, key); 3813 hash_code = h->test.hashfn (&h->test, key);
3814 eassert ((hash_code & ~INTMASK) == 0);
3845 start_of_bucket = hash_code % ASIZE (h->index); 3815 start_of_bucket = hash_code % ASIZE (h->index);
3846 idx = HASH_INDEX (h, start_of_bucket); 3816 idx = HASH_INDEX (h, start_of_bucket);
3847 prev = Qnil; 3817 prev = Qnil;
@@ -3852,9 +3822,9 @@ hash_remove_from_table (struct Lisp_Hash_Table *h, Lisp_Object key)
3852 ptrdiff_t i = XFASTINT (idx); 3822 ptrdiff_t i = XFASTINT (idx);
3853 3823
3854 if (EQ (key, HASH_KEY (h, i)) 3824 if (EQ (key, HASH_KEY (h, i))
3855 || (h->cmpfn 3825 || (h->test.cmpfn
3856 && h->cmpfn (h, key, hash_code, 3826 && hash_code == XUINT (HASH_HASH (h, i))
3857 HASH_KEY (h, i), XUINT (HASH_HASH (h, i))))) 3827 && h->test.cmpfn (&h->test, key, HASH_KEY (h, i))))
3858 { 3828 {
3859 /* Take entry out of collision chain. */ 3829 /* Take entry out of collision chain. */
3860 if (NILP (prev)) 3830 if (NILP (prev))
@@ -4303,7 +4273,7 @@ usage: (make-hash-table &rest KEYWORD-ARGS) */)
4303 (ptrdiff_t nargs, Lisp_Object *args) 4273 (ptrdiff_t nargs, Lisp_Object *args)
4304{ 4274{
4305 Lisp_Object test, size, rehash_size, rehash_threshold, weak; 4275 Lisp_Object test, size, rehash_size, rehash_threshold, weak;
4306 Lisp_Object user_test, user_hash; 4276 struct hash_table_test testdesc;
4307 char *used; 4277 char *used;
4308 ptrdiff_t i; 4278 ptrdiff_t i;
4309 4279
@@ -4315,7 +4285,13 @@ usage: (make-hash-table &rest KEYWORD-ARGS) */)
4315 /* See if there's a `:test TEST' among the arguments. */ 4285 /* See if there's a `:test TEST' among the arguments. */
4316 i = get_key_arg (QCtest, nargs, args, used); 4286 i = get_key_arg (QCtest, nargs, args, used);
4317 test = i ? args[i] : Qeql; 4287 test = i ? args[i] : Qeql;
4318 if (!EQ (test, Qeq) && !EQ (test, Qeql) && !EQ (test, Qequal)) 4288 if (EQ (test, Qeq))
4289 testdesc = hashtest_eq;
4290 else if (EQ (test, Qeql))
4291 testdesc = hashtest_eql;
4292 else if (EQ (test, Qequal))
4293 testdesc = hashtest_equal;
4294 else
4319 { 4295 {
4320 /* See if it is a user-defined test. */ 4296 /* See if it is a user-defined test. */
4321 Lisp_Object prop; 4297 Lisp_Object prop;
@@ -4323,11 +4299,12 @@ usage: (make-hash-table &rest KEYWORD-ARGS) */)
4323 prop = Fget (test, Qhash_table_test); 4299 prop = Fget (test, Qhash_table_test);
4324 if (!CONSP (prop) || !CONSP (XCDR (prop))) 4300 if (!CONSP (prop) || !CONSP (XCDR (prop)))
4325 signal_error ("Invalid hash table test", test); 4301 signal_error ("Invalid hash table test", test);
4326 user_test = XCAR (prop); 4302 testdesc.name = test;
4327 user_hash = XCAR (XCDR (prop)); 4303 testdesc.user_cmp_function = XCAR (prop);
4304 testdesc.user_hash_function = XCAR (XCDR (prop));
4305 testdesc.hashfn = hashfn_user_defined;
4306 testdesc.cmpfn = cmpfn_user_defined;
4328 } 4307 }
4329 else
4330 user_test = user_hash = Qnil;
4331 4308
4332 /* See if there's a `:size SIZE' argument. */ 4309 /* See if there's a `:size SIZE' argument. */
4333 i = get_key_arg (QCsize, nargs, args, used); 4310 i = get_key_arg (QCsize, nargs, args, used);
@@ -4369,8 +4346,7 @@ usage: (make-hash-table &rest KEYWORD-ARGS) */)
4369 if (!used[i]) 4346 if (!used[i])
4370 signal_error ("Invalid argument list", args[i]); 4347 signal_error ("Invalid argument list", args[i]);
4371 4348
4372 return make_hash_table (test, size, rehash_size, rehash_threshold, weak, 4349 return make_hash_table (testdesc, size, rehash_size, rehash_threshold, weak);
4373 user_test, user_hash);
4374} 4350}
4375 4351
4376 4352
@@ -4424,7 +4400,7 @@ DEFUN ("hash-table-test", Fhash_table_test, Shash_table_test, 1, 1, 0,
4424 doc: /* Return the test TABLE uses. */) 4400 doc: /* Return the test TABLE uses. */)
4425 (Lisp_Object table) 4401 (Lisp_Object table)
4426{ 4402{
4427 return check_hash_table (table)->test; 4403 return check_hash_table (table)->test.name;
4428} 4404}
4429 4405
4430 4406
@@ -4988,4 +4964,14 @@ this variable. */);
4988 defsubr (&Smd5); 4964 defsubr (&Smd5);
4989 defsubr (&Ssecure_hash); 4965 defsubr (&Ssecure_hash);
4990 defsubr (&Slocale_info); 4966 defsubr (&Slocale_info);
4967
4968 {
4969 struct hash_table_test
4970 eq = { Qeq, Qnil, Qnil, NULL, hashfn_eq },
4971 eql = { Qeql, Qnil, Qnil, cmpfn_eql, hashfn_eql },
4972 equal = { Qequal, Qnil, Qnil, cmpfn_equal, hashfn_equal };
4973 hashtest_eq = eq;
4974 hashtest_eql = eql;
4975 hashtest_equal = equal;
4976 }
4991} 4977}
diff --git a/src/lisp.h b/src/lisp.h
index 66612e2987e..cac7d4b7012 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -1159,14 +1159,29 @@ struct Lisp_Symbol
1159 1159
1160/* The structure of a Lisp hash table. */ 1160/* The structure of a Lisp hash table. */
1161 1161
1162struct hash_table_test
1163{
1164 /* Name of the function used to compare keys. */
1165 Lisp_Object name;
1166
1167 /* User-supplied hash function, or nil. */
1168 Lisp_Object user_hash_function;
1169
1170 /* User-supplied key comparison function, or nil. */
1171 Lisp_Object user_cmp_function;
1172
1173 /* C function to compare two keys. */
1174 bool (*cmpfn) (struct hash_table_test *t, Lisp_Object, Lisp_Object);
1175
1176 /* C function to compute hash code. */
1177 EMACS_UINT (*hashfn) (struct hash_table_test *t, Lisp_Object);
1178};
1179
1162struct Lisp_Hash_Table 1180struct Lisp_Hash_Table
1163{ 1181{
1164 /* This is for Lisp; the hash table code does not refer to it. */ 1182 /* This is for Lisp; the hash table code does not refer to it. */
1165 struct vectorlike_header header; 1183 struct vectorlike_header header;
1166 1184
1167 /* Function used to compare keys. */
1168 Lisp_Object test;
1169
1170 /* Nil if table is non-weak. Otherwise a symbol describing the 1185 /* Nil if table is non-weak. Otherwise a symbol describing the
1171 weakness of the table. */ 1186 weakness of the table. */
1172 Lisp_Object weak; 1187 Lisp_Object weak;
@@ -1197,12 +1212,6 @@ struct Lisp_Hash_Table
1197 hash table size to reduce collisions. */ 1212 hash table size to reduce collisions. */
1198 Lisp_Object index; 1213 Lisp_Object index;
1199 1214
1200 /* User-supplied hash function, or nil. */
1201 Lisp_Object user_hash_function;
1202
1203 /* User-supplied key comparison function, or nil. */
1204 Lisp_Object user_cmp_function;
1205
1206 /* Only the fields above are traced normally by the GC. The ones below 1215 /* Only the fields above are traced normally by the GC. The ones below
1207 `count' are special and are either ignored by the GC or traced in 1216 `count' are special and are either ignored by the GC or traced in
1208 a special way (e.g. because of weakness). */ 1217 a special way (e.g. because of weakness). */
@@ -1215,17 +1224,12 @@ struct Lisp_Hash_Table
1215 This is gc_marked specially if the table is weak. */ 1224 This is gc_marked specially if the table is weak. */
1216 Lisp_Object key_and_value; 1225 Lisp_Object key_and_value;
1217 1226
1227 /* The comparison and hash functions. */
1228 struct hash_table_test test;
1229
1218 /* Next weak hash table if this is a weak hash table. The head 1230 /* Next weak hash table if this is a weak hash table. The head
1219 of the list is in weak_hash_tables. */ 1231 of the list is in weak_hash_tables. */
1220 struct Lisp_Hash_Table *next_weak; 1232 struct Lisp_Hash_Table *next_weak;
1221
1222 /* C function to compare two keys. */
1223 bool (*cmpfn) (struct Lisp_Hash_Table *,
1224 Lisp_Object, EMACS_UINT,
1225 Lisp_Object, EMACS_UINT);
1226
1227 /* C function to compute hash code. */
1228 EMACS_UINT (*hashfn) (struct Lisp_Hash_Table *, Lisp_Object);
1229}; 1233};
1230 1234
1231 1235
@@ -2707,12 +2711,12 @@ extern Lisp_Object Qstring_lessp;
2707extern Lisp_Object QCsize, QCtest, QCweakness, Qequal, Qeq, Qeql; 2711extern Lisp_Object QCsize, QCtest, QCweakness, Qequal, Qeq, Qeql;
2708EMACS_UINT hash_string (char const *, ptrdiff_t); 2712EMACS_UINT hash_string (char const *, ptrdiff_t);
2709EMACS_UINT sxhash (Lisp_Object, int); 2713EMACS_UINT sxhash (Lisp_Object, int);
2710Lisp_Object make_hash_table (Lisp_Object, Lisp_Object, Lisp_Object, 2714Lisp_Object make_hash_table (struct hash_table_test, Lisp_Object, Lisp_Object,
2711 Lisp_Object, Lisp_Object, Lisp_Object, 2715 Lisp_Object, Lisp_Object);
2712 Lisp_Object);
2713ptrdiff_t hash_lookup (struct Lisp_Hash_Table *, Lisp_Object, EMACS_UINT *); 2716ptrdiff_t hash_lookup (struct Lisp_Hash_Table *, Lisp_Object, EMACS_UINT *);
2714ptrdiff_t hash_put (struct Lisp_Hash_Table *, Lisp_Object, Lisp_Object, 2717ptrdiff_t hash_put (struct Lisp_Hash_Table *, Lisp_Object, Lisp_Object,
2715 EMACS_UINT); 2718 EMACS_UINT);
2719extern struct hash_table_test hashtest_eq, hashtest_eql, hashtest_equal;
2716 2720
2717extern Lisp_Object substring_both (Lisp_Object, ptrdiff_t, ptrdiff_t, 2721extern Lisp_Object substring_both (Lisp_Object, ptrdiff_t, ptrdiff_t,
2718 ptrdiff_t, ptrdiff_t); 2722 ptrdiff_t, ptrdiff_t);
diff --git a/src/print.c b/src/print.c
index ccf0e8ed7cc..af6eda7298f 100644
--- a/src/print.c
+++ b/src/print.c
@@ -1815,14 +1815,14 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
1815#endif 1815#endif
1816 /* Implement a readable output, e.g.: 1816 /* Implement a readable output, e.g.:
1817 #s(hash-table size 2 test equal data (k1 v1 k2 v2)) */ 1817 #s(hash-table size 2 test equal data (k1 v1 k2 v2)) */
1818 /* Always print the size. */ 1818 /* Always print the size. */
1819 len = sprintf (buf, "#s(hash-table size %"pD"d", ASIZE (h->next)); 1819 len = sprintf (buf, "#s(hash-table size %"pD"d", ASIZE (h->next));
1820 strout (buf, len, len, printcharfun); 1820 strout (buf, len, len, printcharfun);
1821 1821
1822 if (!NILP (h->test)) 1822 if (!NILP (h->test.name))
1823 { 1823 {
1824 strout (" test ", -1, -1, printcharfun); 1824 strout (" test ", -1, -1, printcharfun);
1825 print_object (h->test, printcharfun, escapeflag); 1825 print_object (h->test.name, printcharfun, escapeflag);
1826 } 1826 }
1827 1827
1828 if (!NILP (h->weak)) 1828 if (!NILP (h->weak))
diff --git a/src/profiler.c b/src/profiler.c
index 51580710f28..6f112440902 100644
--- a/src/profiler.c
+++ b/src/profiler.c
@@ -35,6 +35,9 @@ saturated_add (EMACS_INT a, EMACS_INT b)
35 35
36typedef struct Lisp_Hash_Table log_t; 36typedef struct Lisp_Hash_Table log_t;
37 37
38static Lisp_Object Qprofiler_backtrace_equal;
39static struct hash_table_test hashtest_profiler;
40
38static Lisp_Object 41static Lisp_Object
39make_log (int heap_size, int max_stack_depth) 42make_log (int heap_size, int max_stack_depth)
40{ 43{
@@ -42,10 +45,11 @@ make_log (int heap_size, int max_stack_depth)
42 a special way. This is OK as long as the object is not exposed 45 a special way. This is OK as long as the object is not exposed
43 to Elisp, i.e. until it is returned by *-profiler-log, after which 46 to Elisp, i.e. until it is returned by *-profiler-log, after which
44 it can't be used any more. */ 47 it can't be used any more. */
45 Lisp_Object log = make_hash_table (Qequal, make_number (heap_size), 48 Lisp_Object log = make_hash_table (hashtest_profiler,
49 make_number (heap_size),
46 make_float (DEFAULT_REHASH_SIZE), 50 make_float (DEFAULT_REHASH_SIZE),
47 make_float (DEFAULT_REHASH_THRESHOLD), 51 make_float (DEFAULT_REHASH_THRESHOLD),
48 Qnil, Qnil, Qnil); 52 Qnil);
49 struct Lisp_Hash_Table *h = XHASH_TABLE (log); 53 struct Lisp_Hash_Table *h = XHASH_TABLE (log);
50 54
51 /* What is special about our hash-tables is that the keys are pre-filled 55 /* What is special about our hash-tables is that the keys are pre-filled
@@ -238,8 +242,6 @@ handle_profiler_signal (int signal)
238 cpu_gc_count = saturated_add (cpu_gc_count, 1); 242 cpu_gc_count = saturated_add (cpu_gc_count, 1);
239 else 243 else
240 { 244 {
241 Lisp_Object oquit;
242 bool saved_pending_signals;
243 EMACS_INT count = 1; 245 EMACS_INT count = 1;
244#ifdef HAVE_ITIMERSPEC 246#ifdef HAVE_ITIMERSPEC
245 if (profiler_timer_ok) 247 if (profiler_timer_ok)
@@ -249,19 +251,8 @@ handle_profiler_signal (int signal)
249 count += overruns; 251 count += overruns;
250 } 252 }
251#endif 253#endif
252 /* record_backtrace uses hash functions that call Fequal, which
253 uses QUIT, which can call malloc, which can cause disaster in
254 a signal handler. So inhibit QUIT. */
255 oquit = Vinhibit_quit;
256 saved_pending_signals = pending_signals;
257 Vinhibit_quit = Qt;
258 pending_signals = 0;
259
260 eassert (HASH_TABLE_P (cpu_log)); 254 eassert (HASH_TABLE_P (cpu_log));
261 record_backtrace (XHASH_TABLE (cpu_log), count); 255 record_backtrace (XHASH_TABLE (cpu_log), count);
262
263 Vinhibit_quit = oquit;
264 pending_signals = saved_pending_signals;
265 } 256 }
266} 257}
267 258
@@ -515,6 +506,66 @@ malloc_probe (size_t size)
515 record_backtrace (XHASH_TABLE (memory_log), min (size, MOST_POSITIVE_FIXNUM)); 506 record_backtrace (XHASH_TABLE (memory_log), min (size, MOST_POSITIVE_FIXNUM));
516} 507}
517 508
509DEFUN ("function-equal", Ffunction_equal, Sfunction_equal, 2, 2, 0,
510 doc: /* Return non-nil if F1 and F2 come from the same source.
511Used to determine if different closures are just different instances of
512the same lambda expression, or are really unrelated function. */)
513 (Lisp_Object f1, Lisp_Object f2)
514{
515 bool res;
516 if (EQ (f1, f2))
517 res = true;
518 else if (COMPILEDP (f1) && COMPILEDP (f2))
519 res = EQ (AREF (f1, COMPILED_BYTECODE), AREF (f2, COMPILED_BYTECODE));
520 else if (CONSP (f1) && CONSP (f2) && CONSP (XCDR (f1)) && CONSP (XCDR (f2))
521 && EQ (Qclosure, XCAR (f1))
522 && EQ (Qclosure, XCAR (f2)))
523 res = EQ (XCDR (XCDR (f1)), XCDR (XCDR (f2)));
524 else
525 res = false;
526 return res ? Qt : Qnil;
527}
528
529static bool
530cmpfn_profiler (struct hash_table_test *t,
531 Lisp_Object bt1, Lisp_Object bt2)
532{
533 if (VECTORP (bt1) && VECTORP (bt2))
534 {
535 ptrdiff_t i, l = ASIZE (bt1);
536 if (l != ASIZE (bt2))
537 return false;
538 for (i = 0; i < l; i++)
539 if (NILP (Ffunction_equal (AREF (bt1, i), AREF (bt2, i))))
540 return false;
541 return true;
542 }
543 else
544 return EQ (bt1, bt2);
545}
546
547static EMACS_UINT
548hashfn_profiler (struct hash_table_test *ht, Lisp_Object bt)
549{
550 if (VECTORP (bt))
551 {
552 EMACS_UINT hash = 0;
553 ptrdiff_t i, l = ASIZE (bt);
554 for (i = 0; i < l; i++)
555 {
556 Lisp_Object f = AREF (bt, i);
557 EMACS_UINT hash1
558 = (COMPILEDP (f) ? XUINT (AREF (f, COMPILED_BYTECODE))
559 : (CONSP (f) && CONSP (XCDR (f)) && EQ (Qclosure, XCAR (f)))
560 ? XUINT (XCDR (XCDR (f))) : XUINT (f));
561 hash = hash1 + (hash << 1) + (hash == (EMACS_INT) hash);
562 }
563 return (hash & INTMASK);
564 }
565 else
566 return XUINT (bt);
567}
568
518void 569void
519syms_of_profiler (void) 570syms_of_profiler (void)
520{ 571{
@@ -527,6 +578,16 @@ If the log gets full, some of the least-seen call-stacks will be evicted
527to make room for new entries. */); 578to make room for new entries. */);
528 profiler_log_size = 10000; 579 profiler_log_size = 10000;
529 580
581 DEFSYM (Qprofiler_backtrace_equal, "profiler-backtrace-equal");
582 {
583 struct hash_table_test test
584 = { Qprofiler_backtrace_equal, Qnil, Qnil,
585 cmpfn_profiler, hashfn_profiler };
586 hashtest_profiler = test;
587 }
588
589 defsubr (&Sfunction_equal);
590
530#ifdef PROFILER_CPU_SUPPORT 591#ifdef PROFILER_CPU_SUPPORT
531 profiler_cpu_running = NOT_RUNNING; 592 profiler_cpu_running = NOT_RUNNING;
532 cpu_log = Qnil; 593 cpu_log = Qnil;
diff --git a/src/regex.c b/src/regex.c
index 7443eff3977..1473551e6cc 100644
--- a/src/regex.c
+++ b/src/regex.c
@@ -28,7 +28,7 @@
28 rather than at run-time, so that re_match can be reentrant. 28 rather than at run-time, so that re_match can be reentrant.
29*/ 29*/
30 30
31/* AIX requires this to be the first thing in the file. */ 31/* AIX requires this to be the first thing in the file. */
32#if defined _AIX && !defined REGEX_MALLOC 32#if defined _AIX && !defined REGEX_MALLOC
33 #pragma alloca 33 #pragma alloca
34#endif 34#endif
diff --git a/src/xterm.c b/src/xterm.c
index 4dd1dee0f75..f89fbabaecc 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -10868,10 +10868,10 @@ default is nil, which is the same as `super'. */);
10868 10868
10869 DEFVAR_LISP ("x-keysym-table", Vx_keysym_table, 10869 DEFVAR_LISP ("x-keysym-table", Vx_keysym_table,
10870 doc: /* Hash table of character codes indexed by X keysym codes. */); 10870 doc: /* Hash table of character codes indexed by X keysym codes. */);
10871 Vx_keysym_table = make_hash_table (Qeql, make_number (900), 10871 Vx_keysym_table = make_hash_table (hashtest_eql, make_number (900),
10872 make_float (DEFAULT_REHASH_SIZE), 10872 make_float (DEFAULT_REHASH_SIZE),
10873 make_float (DEFAULT_REHASH_THRESHOLD), 10873 make_float (DEFAULT_REHASH_THRESHOLD),
10874 Qnil, Qnil, Qnil); 10874 Qnil);
10875} 10875}
10876 10876
10877#endif /* HAVE_X_WINDOWS */ 10877#endif /* HAVE_X_WINDOWS */