mirror of
https://gitlab.com/embeddable-common-lisp/ecl.git
synced 2026-04-27 11:40:45 -07:00
Use thread-local hashes instead of per-function hashes to cache the results of invoking generic functions
This commit is contained in:
parent
26d819ad80
commit
4356e84222
12 changed files with 274 additions and 206 deletions
|
|
@ -12,6 +12,11 @@ ECL 0.9k:
|
|||
|
||||
- Improved hashing on 64-bit machines.
|
||||
|
||||
* CLOS:
|
||||
|
||||
- When caching generic function calls, ECL now uses a thread-local hash table
|
||||
instead of one hash table per generic function.
|
||||
|
||||
;;; Local Variables: ***
|
||||
;;; mode:text ***
|
||||
;;; fill-column:79 ***
|
||||
|
|
|
|||
103
src/c/gfun.d
103
src/c/gfun.d
|
|
@ -15,6 +15,54 @@
|
|||
#include <string.h>
|
||||
#include <ecl/ecl.h>
|
||||
#include <ecl/internal.h>
|
||||
#include "newhash.h"
|
||||
|
||||
static cl_object
|
||||
do_clear_gfun_hash(cl_object target)
|
||||
{
|
||||
cl_object table = cl_env.gfun_hash;
|
||||
if (target == Ct) {
|
||||
cl_clrhash(table);
|
||||
} else {
|
||||
cl_index hsize = table->hash.size;
|
||||
struct ecl_hashtable_entry *htable = table->hash.data;
|
||||
for (; hsize; htable++, hsize--) {
|
||||
if (htable->key != OBJNULL) {
|
||||
cl_object gfun = CAR(htable->key);
|
||||
if (gfun == target) {
|
||||
htable->key = OBJNULL;
|
||||
htable->value = OBJNULL;
|
||||
table->hash.entries--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cl_object
|
||||
si_clear_gfun_hash(cl_object what)
|
||||
{
|
||||
/*
|
||||
* This function clears the generic function call hashes selectively.
|
||||
* what = Ct means clear the hash completely
|
||||
* what = generic function, means cleans only these entries
|
||||
* If we work on a multithreaded environment, we simply enqueue these
|
||||
* operations and wait for the destination thread to update its own hash.
|
||||
*/
|
||||
#ifdef ECL_THREADS
|
||||
cl_object list;
|
||||
THREAD_OP_LOCK();
|
||||
list = cl_core.processes;
|
||||
for (; list != Cnil; list = CDR(list)) {
|
||||
cl_object process = CAR(list);
|
||||
struct cl_env_struct *env = process->process.env;
|
||||
env->gfun_hash_clear_list = CONS(what, env->gfun_hash_clear_list);
|
||||
}
|
||||
THREAD_OP_UNLOCK();
|
||||
#else
|
||||
do_clear_gfun_hash(what);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
reshape_instance(cl_object x, int delta)
|
||||
|
|
@ -98,20 +146,22 @@ si_generic_function_p(cl_object x)
|
|||
static struct ecl_hashtable_entry *
|
||||
get_meth_hash(cl_object *keys, int argno, cl_object hashtable)
|
||||
{
|
||||
int hsize;
|
||||
cl_index hsize;
|
||||
struct ecl_hashtable_entry *e, *htable;
|
||||
cl_object hkey, tlist;
|
||||
register cl_index i = 0;
|
||||
int k, n; /* k added by chou */
|
||||
register cl_index i;
|
||||
int k, n;
|
||||
|
||||
for (i = 0, n = 0; n < argno; n++) {
|
||||
register cl_index a = (cl_index)keys[n];
|
||||
register cl_index b = GOLDEN_RATIO;
|
||||
mix(a, b, i);
|
||||
}
|
||||
|
||||
hsize = hashtable->hash.size;
|
||||
htable = hashtable->hash.data;
|
||||
for (n = 0; n < argno; n++)
|
||||
i += (cl_index)keys[n] / 4; /* instead of:
|
||||
i += hash_eql(keys[n]);
|
||||
i += hash_eql(Cnil);
|
||||
*/
|
||||
for (i %= hsize, k = 0; k < hsize; i = (i + 1) % hsize, k++) {
|
||||
i = i % hsize;
|
||||
for (k = 0; k < hsize; k++) {
|
||||
bool b = 1;
|
||||
e = &htable[i];
|
||||
hkey = e->key;
|
||||
|
|
@ -122,6 +172,7 @@ get_meth_hash(cl_object *keys, int argno, cl_object hashtable)
|
|||
b &= (keys[n] == CAR(tlist));
|
||||
if (b)
|
||||
return(&htable[i]);
|
||||
if (++i >= hsize) i = 0;
|
||||
}
|
||||
ecl_internal_error("get_meth_hash");
|
||||
}
|
||||
|
|
@ -134,12 +185,14 @@ set_meth_hash(cl_object *keys, int argno, cl_object hashtable, cl_object value)
|
|||
cl_index i;
|
||||
|
||||
i = hashtable->hash.entries + 1;
|
||||
if (i > 512) {
|
||||
/* It does not make sense to let these hashes grow large */
|
||||
cl_clrhash(hashtable);
|
||||
} else if (i >= hashtable->hash.size ||
|
||||
i >= (hashtable->hash.size * hashtable->hash.factor)) {
|
||||
ecl_extend_hashtable(hashtable);
|
||||
if (i >= hashtable->hash.size ||
|
||||
i >= (hashtable->hash.size * hashtable->hash.factor)) {
|
||||
if (hashtable->hash.size > 4092) {
|
||||
/* It does not make sense to let these hashes grow large */
|
||||
cl_clrhash(hashtable);
|
||||
} else {
|
||||
ecl_extend_hashtable(hashtable);
|
||||
}
|
||||
}
|
||||
keylist = Cnil;
|
||||
for (p = keys + argno; p > keys; p--) keylist = CONS(p[-1], keylist);
|
||||
|
|
@ -157,10 +210,24 @@ standard_dispatch(cl_narg narg, cl_object gf, cl_object *args)
|
|||
int i, spec_no;
|
||||
struct ecl_hashtable_entry *e;
|
||||
cl_object spec_how_list = GFUN_SPEC(gf);
|
||||
cl_object table = GFUN_HASH(gf);
|
||||
cl_object argtype[LAMBDA_PARAMETERS_LIMIT];
|
||||
cl_object table = cl_env.gfun_hash;
|
||||
cl_object argtype[1+LAMBDA_PARAMETERS_LIMIT];
|
||||
|
||||
for (spec_no = 0; spec_how_list != Cnil;) {
|
||||
#ifdef ECL_THREADS
|
||||
/* See whether we have to clear the hash from some generic functions right now. */
|
||||
if (cl_env.gfun_hash_clear_list != Cnil) {
|
||||
cl_object clear_list;
|
||||
THREAD_OP_LOCK();
|
||||
clear_list = cl_env.gfun_hash_clear_list;
|
||||
for ( ; clear_list != Cnil ; clear_list = CDR(clear_list)) {
|
||||
do_clear_gfun_hash(CAR(clear_list));
|
||||
}
|
||||
cl_env.gfun_hash_clear_list = Cnil;
|
||||
THREAD_OP_UNLOCK();
|
||||
}
|
||||
#endif
|
||||
argtype[0] = gf;
|
||||
for (spec_no = 1; spec_how_list != Cnil;) {
|
||||
cl_object spec_how = CAR(spec_how_list);
|
||||
cl_object spec_type = CAR(spec_how);
|
||||
int spec_position = fix(CDR(spec_how));
|
||||
|
|
|
|||
167
src/c/hash.d
167
src/c/hash.d
|
|
@ -19,172 +19,7 @@
|
|||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <ecl/internal.h>
|
||||
|
||||
/********************
|
||||
* HASHING ROUTINES *
|
||||
********************/
|
||||
|
||||
/*
|
||||
* SBCL'S old mashing function. Leads to many collisions.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
|
||||
#define mash(h,n) ((((h) << 5) | ((h) >> (FIXNUM_BITS - 5))) ^ (n))
|
||||
#define hash_word(h,x) mash(h,(cl_index)x)
|
||||
|
||||
static cl_hashkey
|
||||
hash_string(cl_hashkey h, const unsigned char *buf, cl_index len)
|
||||
{
|
||||
for (; len; len--) {
|
||||
h = mash(h, (*buf++));
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* SBCL's newest algorithm. Leads to few collisions, and it is faster.
|
||||
*/
|
||||
|
||||
#if FIXNUM_BITS > 32
|
||||
/*
|
||||
* 64 bit version
|
||||
*/
|
||||
#define GOLDEN_RATIO 0x9e3779b97f4a7c13L
|
||||
#define mix(a,b,c) \
|
||||
{ \
|
||||
a=a-b; a=a-c; a=a^(c>>43); \
|
||||
b=b-c; b=b-a; b=b^(a<<9); \
|
||||
c=c-a; c=c-b; c=c^(b>>8); \
|
||||
a=a-b; a=a-c; a=a^(c>>38); \
|
||||
b=b-c; b=b-a; b=b^(a<<23); \
|
||||
c=c-a; c=c-b; c=c^(b>>5); \
|
||||
a=a-b; a=a-c; a=a^(c>>35); \
|
||||
b=b-c; b=b-a; b=b^(a<<49); \
|
||||
c=c-a; c=c-b; c=c^(b>>11); \
|
||||
a=a-b; a=a-c; a=a^(c>>12); \
|
||||
b=b-c; b=b-a; b=b^(a<<18); \
|
||||
c=c-a; c=c-b; c=c^(b>>22); \
|
||||
}
|
||||
|
||||
#define extract_word(k) \
|
||||
(k[0]+((cl_index)k[1]<<8)+((cl_index)k[2]<<16)+((cl_index)k[3]<<24)+ \
|
||||
((cl_index)k[4]<<32)+((cl_index)k[5]<<40)+((cl_index)k[6]<<48)+ \
|
||||
((cl_index)k[7]<<52))
|
||||
|
||||
static cl_index
|
||||
hash_string(cl_index initval, const unsigned char *k, cl_index len)
|
||||
{
|
||||
register cl_index a = GOLDEN_RATIO, b = GOLDEN_RATIO, c = initval;
|
||||
for (; len > 24; ) {
|
||||
a += extract_word(k); k+=8;
|
||||
b += extract_word(k); k+=8;
|
||||
c += extract_word(k); k+=8;
|
||||
mix(a,b,c);
|
||||
len -= 24;
|
||||
}
|
||||
|
||||
/*------------------------------------- handle the last 11 bytes */
|
||||
c += len;
|
||||
switch(len) {
|
||||
/* all the case statements fall through */
|
||||
case 23: c+=((cl_index)k[22]<<52);
|
||||
case 22: c+=((cl_index)k[21]<<48);
|
||||
case 21: c+=((cl_index)k[20]<<40);
|
||||
case 20: c+=((cl_index)k[19]<<32);
|
||||
case 19: c+=((cl_index)k[18]<<24);
|
||||
case 18: c+=((cl_index)k[17]<<16);
|
||||
case 17: c+=((cl_index)k[16]<<8);
|
||||
/* the first byte of c is reserved for the length */
|
||||
case 16: b+=((cl_index)k[15]<<52);
|
||||
case 15: b+=((cl_index)k[14]<<48);
|
||||
case 14: b+=((cl_index)k[13]<<40);
|
||||
case 13: b+=((cl_index)k[12]<<32);
|
||||
case 12: b+=((cl_index)k[11]<<24);
|
||||
case 11: b+=((cl_index)k[10]<<16);
|
||||
case 10: b+=((cl_index)k[9]<<8);
|
||||
case 9 : b+=k[8];
|
||||
case 8 : a+=((cl_index)k[7]<<52);
|
||||
case 7 : a+=((cl_index)k[6]<<48);
|
||||
case 6 : a+=((cl_index)k[5]<<40);
|
||||
case 5 : a+=((cl_index)k[4]<<32);
|
||||
case 4 : a+=((cl_index)k[3]<<24);
|
||||
case 3 : a+=((cl_index)k[2]<<16);
|
||||
case 2 : a+=((cl_index)k[1]<<8);
|
||||
case 1 : a+=k[0];
|
||||
/* case 0: nothing left to add */
|
||||
}
|
||||
mix(a,b,c);
|
||||
/*-------------------------------------------- report the result */
|
||||
return c;
|
||||
}
|
||||
|
||||
#else
|
||||
/*
|
||||
* 32 bit version
|
||||
*/
|
||||
|
||||
#define GOLDEN_RATIO 0x9e3779b9L
|
||||
#define mix(a,b,c) \
|
||||
{ \
|
||||
a -= b; a -= c; a ^= (c>>13); \
|
||||
b -= c; b -= a; b ^= (a<<8); \
|
||||
c -= a; c -= b; c ^= (b>>13); \
|
||||
a -= b; a -= c; a ^= (c>>12); \
|
||||
b -= c; b -= a; b ^= (a<<16); \
|
||||
c -= a; c -= b; c ^= (b>>5); \
|
||||
a -= b; a -= c; a ^= (c>>3); \
|
||||
b -= c; b -= a; b ^= (a<<10); \
|
||||
c -= a; c -= b; c ^= (b>>15); \
|
||||
}
|
||||
#define extract_word(k) \
|
||||
(k[0]+((cl_index)k[1]<<8)+((cl_index)k[2]<<16)+((cl_index)k[3]<<24))
|
||||
|
||||
|
||||
static cl_index
|
||||
hash_string(cl_index initval, const unsigned char *k, cl_index len)
|
||||
{
|
||||
register cl_index a = GOLDEN_RATIO, b = GOLDEN_RATIO, c = initval;
|
||||
for (; len > 12; ) {
|
||||
a += extract_word(k); k += 4;
|
||||
b += extract_word(k); k += 4;
|
||||
c += extract_word(k); k += 4;
|
||||
mix(a,b,c);
|
||||
len -= 12;
|
||||
}
|
||||
|
||||
/*------------------------------------- handle the last 11 bytes */
|
||||
c += len;
|
||||
switch(len) {
|
||||
/* all the case statements fall through */
|
||||
case 11: c+=((cl_index)k[10]<<24);
|
||||
case 10: c+=((cl_index)k[9]<<16);
|
||||
case 9 : c+=((cl_index)k[8]<<8);
|
||||
/* the first byte of c is reserved for the length */
|
||||
case 8 : b+=((cl_index)k[7]<<24);
|
||||
case 7 : b+=((cl_index)k[6]<<16);
|
||||
case 6 : b+=((cl_index)k[5]<<8);
|
||||
case 5 : b+=k[4];
|
||||
case 4 : a+=((cl_index)k[3]<<24);
|
||||
case 3 : a+=((cl_index)k[2]<<16);
|
||||
case 2 : a+=((cl_index)k[1]<<8);
|
||||
case 1 : a+=k[0];
|
||||
/* case 0: nothing left to add */
|
||||
}
|
||||
mix(a,b,c);
|
||||
/*-------------------------------------------- report the result */
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
||||
static cl_index hash_word(cl_index c, cl_index a)
|
||||
{
|
||||
cl_index b = GOLDEN_RATIO;
|
||||
mix(a, b, c);
|
||||
return c;
|
||||
}
|
||||
#include "newhash.h"
|
||||
|
||||
static void corrupted_hash(cl_object hashtable) /*__attribute__((noreturn))*/;
|
||||
|
||||
|
|
|
|||
11
src/c/main.d
11
src/c/main.d
|
|
@ -93,6 +93,17 @@ ecl_init_env(struct cl_env_struct *env)
|
|||
((struct ecl_fficall*)env->fficall)->registers = 0;
|
||||
#endif
|
||||
|
||||
#ifdef CLOS
|
||||
#ifdef ECL_THREADS
|
||||
env->gfun_hash_clear_list = Cnil;
|
||||
#endif
|
||||
env->gfun_hash =
|
||||
cl__make_hash_table(@'equalp', MAKE_FIXNUM(1024), /* size */
|
||||
ecl_make_singlefloat(1.5f), /* rehash-size */
|
||||
ecl_make_singlefloat(0.5f), /* rehash-threshold */
|
||||
Cnil); /* thread-safe */
|
||||
#endif
|
||||
|
||||
init_stacks(&i);
|
||||
}
|
||||
|
||||
|
|
|
|||
146
src/c/newhash.h
Normal file
146
src/c/newhash.h
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
/********************
|
||||
* HASHING ROUTINES *
|
||||
********************/
|
||||
|
||||
/*
|
||||
* SBCL's newest algorithm. Leads to few collisions, and it is faster.
|
||||
*/
|
||||
|
||||
#if FIXNUM_BITS > 32
|
||||
/*
|
||||
* 64 bit version
|
||||
*/
|
||||
#define GOLDEN_RATIO 0x9e3779b97f4a7c13L
|
||||
#define mix(a,b,c) \
|
||||
{ \
|
||||
a=a-b; a=a-c; a=a^(c>>43); \
|
||||
b=b-c; b=b-a; b=b^(a<<9); \
|
||||
c=c-a; c=c-b; c=c^(b>>8); \
|
||||
a=a-b; a=a-c; a=a^(c>>38); \
|
||||
b=b-c; b=b-a; b=b^(a<<23); \
|
||||
c=c-a; c=c-b; c=c^(b>>5); \
|
||||
a=a-b; a=a-c; a=a^(c>>35); \
|
||||
b=b-c; b=b-a; b=b^(a<<49); \
|
||||
c=c-a; c=c-b; c=c^(b>>11); \
|
||||
a=a-b; a=a-c; a=a^(c>>12); \
|
||||
b=b-c; b=b-a; b=b^(a<<18); \
|
||||
c=c-a; c=c-b; c=c^(b>>22); \
|
||||
}
|
||||
|
||||
#define extract_word(k) \
|
||||
(k[0]+((cl_index)k[1]<<8)+((cl_index)k[2]<<16)+((cl_index)k[3]<<24)+ \
|
||||
((cl_index)k[4]<<32)+((cl_index)k[5]<<40)+((cl_index)k[6]<<48)+ \
|
||||
((cl_index)k[7]<<52))
|
||||
|
||||
static cl_index
|
||||
hash_string(cl_index initval, const unsigned char *k, cl_index len)
|
||||
{
|
||||
register cl_index a = GOLDEN_RATIO, b = GOLDEN_RATIO, c = initval;
|
||||
for (; len > 24; ) {
|
||||
a += extract_word(k); k+=8;
|
||||
b += extract_word(k); k+=8;
|
||||
c += extract_word(k); k+=8;
|
||||
mix(a,b,c);
|
||||
len -= 24;
|
||||
}
|
||||
|
||||
/*------------------------------------- handle the last 11 bytes */
|
||||
c += len;
|
||||
switch(len) {
|
||||
/* all the case statements fall through */
|
||||
case 23: c+=((cl_index)k[22]<<52);
|
||||
case 22: c+=((cl_index)k[21]<<48);
|
||||
case 21: c+=((cl_index)k[20]<<40);
|
||||
case 20: c+=((cl_index)k[19]<<32);
|
||||
case 19: c+=((cl_index)k[18]<<24);
|
||||
case 18: c+=((cl_index)k[17]<<16);
|
||||
case 17: c+=((cl_index)k[16]<<8);
|
||||
/* the first byte of c is reserved for the length */
|
||||
case 16: b+=((cl_index)k[15]<<52);
|
||||
case 15: b+=((cl_index)k[14]<<48);
|
||||
case 14: b+=((cl_index)k[13]<<40);
|
||||
case 13: b+=((cl_index)k[12]<<32);
|
||||
case 12: b+=((cl_index)k[11]<<24);
|
||||
case 11: b+=((cl_index)k[10]<<16);
|
||||
case 10: b+=((cl_index)k[9]<<8);
|
||||
case 9 : b+=k[8];
|
||||
case 8 : a+=((cl_index)k[7]<<52);
|
||||
case 7 : a+=((cl_index)k[6]<<48);
|
||||
case 6 : a+=((cl_index)k[5]<<40);
|
||||
case 5 : a+=((cl_index)k[4]<<32);
|
||||
case 4 : a+=((cl_index)k[3]<<24);
|
||||
case 3 : a+=((cl_index)k[2]<<16);
|
||||
case 2 : a+=((cl_index)k[1]<<8);
|
||||
case 1 : a+=k[0];
|
||||
/* case 0: nothing left to add */
|
||||
}
|
||||
mix(a,b,c);
|
||||
/*-------------------------------------------- report the result */
|
||||
return c;
|
||||
}
|
||||
|
||||
#else
|
||||
/*
|
||||
* 32 bit version
|
||||
*/
|
||||
|
||||
#define GOLDEN_RATIO 0x9e3779b9L
|
||||
#define mix(a,b,c) \
|
||||
{ \
|
||||
a -= b; a -= c; a ^= (c>>13); \
|
||||
b -= c; b -= a; b ^= (a<<8); \
|
||||
c -= a; c -= b; c ^= (b>>13); \
|
||||
a -= b; a -= c; a ^= (c>>12); \
|
||||
b -= c; b -= a; b ^= (a<<16); \
|
||||
c -= a; c -= b; c ^= (b>>5); \
|
||||
a -= b; a -= c; a ^= (c>>3); \
|
||||
b -= c; b -= a; b ^= (a<<10); \
|
||||
c -= a; c -= b; c ^= (b>>15); \
|
||||
}
|
||||
#define extract_word(k) \
|
||||
(k[0]+((cl_index)k[1]<<8)+((cl_index)k[2]<<16)+((cl_index)k[3]<<24))
|
||||
|
||||
|
||||
static cl_index
|
||||
hash_string(cl_index initval, const unsigned char *k, cl_index len)
|
||||
{
|
||||
register cl_index a = GOLDEN_RATIO, b = GOLDEN_RATIO, c = initval;
|
||||
for (; len > 12; ) {
|
||||
a += extract_word(k); k += 4;
|
||||
b += extract_word(k); k += 4;
|
||||
c += extract_word(k); k += 4;
|
||||
mix(a,b,c);
|
||||
len -= 12;
|
||||
}
|
||||
|
||||
/*------------------------------------- handle the last 11 bytes */
|
||||
c += len;
|
||||
switch(len) {
|
||||
/* all the case statements fall through */
|
||||
case 11: c+=((cl_index)k[10]<<24);
|
||||
case 10: c+=((cl_index)k[9]<<16);
|
||||
case 9 : c+=((cl_index)k[8]<<8);
|
||||
/* the first byte of c is reserved for the length */
|
||||
case 8 : b+=((cl_index)k[7]<<24);
|
||||
case 7 : b+=((cl_index)k[6]<<16);
|
||||
case 6 : b+=((cl_index)k[5]<<8);
|
||||
case 5 : b+=k[4];
|
||||
case 4 : a+=((cl_index)k[3]<<24);
|
||||
case 3 : a+=((cl_index)k[2]<<16);
|
||||
case 2 : a+=((cl_index)k[1]<<8);
|
||||
case 1 : a+=k[0];
|
||||
/* case 0: nothing left to add */
|
||||
}
|
||||
mix(a,b,c);
|
||||
/*-------------------------------------------- report the result */
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
||||
static cl_index hash_word(cl_index c, cl_index a)
|
||||
{
|
||||
cl_index b = GOLDEN_RATIO;
|
||||
mix(a, b, c);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
|
@ -1673,6 +1673,10 @@ cl_symbols[] = {
|
|||
|
||||
{SYS_ "CODE-BLOCK", SI_ORDINARY, NULL, -1, OBJNULL},
|
||||
|
||||
#ifdef CLOS
|
||||
{SYS_ "CLEAR-GFUN-HASH", SI_ORDINARY, si_clear_gfun_hash, 1, OBJNULL},
|
||||
#endif
|
||||
|
||||
/* Tag for end of list */
|
||||
{NULL, CL_ORDINARY, NULL, -1, OBJNULL}};
|
||||
|
||||
|
|
|
|||
|
|
@ -1673,6 +1673,10 @@ cl_symbols[] = {
|
|||
|
||||
{SYS_ "CODE-BLOCK",NULL},
|
||||
|
||||
#ifdef CLOS
|
||||
{SYS_ "CLEAR-GFUN-HASH","si_clear_gfun_hash"},
|
||||
#endif
|
||||
|
||||
/* Tag for end of list */
|
||||
{NULL,NULL}};
|
||||
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ their lambda lists ~A and ~A are not congruent."
|
|||
(setf (generic-function-methods gf)
|
||||
(delete method (generic-function-methods gf))
|
||||
(method-generic-function method) nil)
|
||||
(clrhash (generic-function-method-hash gf))
|
||||
(si:clear-gfun-hash gf)
|
||||
gf)
|
||||
|
||||
;;; ----------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -86,13 +86,6 @@
|
|||
(defparameter +standard-generic-function-slots+
|
||||
'((name :initarg :name :initform nil
|
||||
:accessor generic-function-name)
|
||||
(method-hash :accessor generic-function-method-hash
|
||||
:initform (make-hash-table
|
||||
:test #'eql
|
||||
;; use fixnums as limits for efficiency:
|
||||
:size *default-method-cache-size*
|
||||
:rehash-size #.(/ *default-method-cache-size* 2)
|
||||
:rehash-threshold 0.5f0))
|
||||
(spec-list :initform nil :accessor generic-function-spec-list)
|
||||
(method-combination
|
||||
:initarg :method-combination :initform '(standard)
|
||||
|
|
@ -202,13 +195,7 @@
|
|||
(fdefinition name)
|
||||
;; create a fake standard-generic-function object:
|
||||
(let ((gfun (si:allocate-raw-instance nil (find-class 't)
|
||||
#.(length +standard-generic-function-slots+)))
|
||||
(hash (make-hash-table
|
||||
:test #'eql
|
||||
;; use fixnums as limits for efficiency:
|
||||
:size *default-method-cache-size*
|
||||
:rehash-size #.(/ *default-method-cache-size* 2)
|
||||
:rehash-threshold 0.5f0)))
|
||||
#.(length +standard-generic-function-slots+))))
|
||||
(declare (type standard-object gfun))
|
||||
;; create a new gfun
|
||||
(si::instance-sig-set gfun)
|
||||
|
|
@ -216,8 +203,7 @@
|
|||
(generic-function-lambda-list gfun) lambda-list
|
||||
(generic-function-method-combination gfun) '(standard)
|
||||
(generic-function-methods gfun) nil
|
||||
(generic-function-spec-list gfun) nil
|
||||
(generic-function-method-hash gfun) hash)
|
||||
(generic-function-spec-list gfun) nil)
|
||||
(when l-l-p
|
||||
(setf (generic-function-argument-precedence-order gfun)
|
||||
(rest (si::process-lambda-list lambda-list t))))
|
||||
|
|
@ -367,7 +353,7 @@
|
|||
(list ,@a-p-o)))
|
||||
'function))))))
|
||||
(setf (generic-function-a-p-o-function gf) function)
|
||||
(clrhash (generic-function-method-hash gf)))))
|
||||
(si:clear-gfun-hash gf))))
|
||||
|
||||
(defun print-object (object stream)
|
||||
(print-unreadable-object (object stream)))
|
||||
|
|
|
|||
|
|
@ -97,6 +97,16 @@ struct cl_env_struct {
|
|||
#endif
|
||||
int interrupt_pending;
|
||||
|
||||
/* The following is a hash table for caching invocations of
|
||||
generic functions. In a multithreaded environment we must
|
||||
queue operations in which the hash is cleared from updated
|
||||
generic functions. */
|
||||
#ifdef CLOS
|
||||
cl_object gfun_hash;
|
||||
#ifdef ECL_THREADS
|
||||
cl_object gfun_hash_clear_list;
|
||||
#endif
|
||||
#endif
|
||||
/* foreign function interface */
|
||||
void *fficall;
|
||||
};
|
||||
|
|
@ -630,6 +640,7 @@ extern void ecl_register_root(cl_object *p);
|
|||
/* gfun.c */
|
||||
|
||||
#ifdef CLOS
|
||||
extern cl_object si_clear_gfun_hash(cl_object what);
|
||||
extern cl_object clos_set_funcallable_instance_function(cl_object x, cl_object function_or_t);
|
||||
extern cl_object si_generic_function_p(cl_object instance);
|
||||
|
||||
|
|
|
|||
|
|
@ -165,9 +165,8 @@ extern void ecl_extend_hashtable(cl_object hashtable);
|
|||
/* gfun.d, kernel.lsp */
|
||||
|
||||
#define GFUN_NAME(x) ((x)->instance.slots[0])
|
||||
#define GFUN_HASH(x) ((x)->instance.slots[1])
|
||||
#define GFUN_SPEC(x) ((x)->instance.slots[2])
|
||||
#define GFUN_COMB(x) ((x)->instance.slots[3])
|
||||
#define GFUN_SPEC(x) ((x)->instance.slots[1])
|
||||
#define GFUN_COMB(x) ((x)->instance.slots[2])
|
||||
|
||||
/* package.d */
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ Returns, as a string, the location of the machine on which ECL runs."
|
|||
(defun lisp-implementation-version ()
|
||||
"Args:()
|
||||
Returns the version of your ECL as a string."
|
||||
"@PACKAGE_VERSION@ (CVS 2008-01-05 22:02)")
|
||||
"@PACKAGE_VERSION@ (CVS 2008-01-06 16:18)")
|
||||
|
||||
(defun machine-type ()
|
||||
"Args: ()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue