Mercurial > hg > xemacs-beta
comparison src/alloc.c @ 442:abe6d1db359e r21-2-36
Import from CVS: tag r21-2-36
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:35:02 +0200 |
parents | 8de8e3f6228a |
children | 576fb035e263 |
comparison
equal
deleted
inserted
replaced
441:72a7cfa4a488 | 442:abe6d1db359e |
---|---|
34 and various changes for Mule, for 19.12. | 34 and various changes for Mule, for 19.12. |
35 Added bit vectors for 19.13. | 35 Added bit vectors for 19.13. |
36 Added lcrecord lists for 19.14. | 36 Added lcrecord lists for 19.14. |
37 slb: Lots of work on the purification and dump time code. | 37 slb: Lots of work on the purification and dump time code. |
38 Synched Doug Lea malloc support from Emacs 20.2. | 38 Synched Doug Lea malloc support from Emacs 20.2. |
39 og: Killed the purespace. Portable dumper. | 39 og: Killed the purespace. Portable dumper (moved to dumper.c) |
40 */ | 40 */ |
41 | 41 |
42 #include <config.h> | 42 #include <config.h> |
43 #include "lisp.h" | 43 #include "lisp.h" |
44 | 44 |
45 #include "alloc.h" | |
45 #include "backtrace.h" | 46 #include "backtrace.h" |
46 #include "buffer.h" | 47 #include "buffer.h" |
47 #include "bytecode.h" | 48 #include "bytecode.h" |
48 #include "chartab.h" | 49 #include "chartab.h" |
49 #include "device.h" | 50 #include "device.h" |
54 #include "glyphs.h" | 55 #include "glyphs.h" |
55 #include "opaque.h" | 56 #include "opaque.h" |
56 #include "redisplay.h" | 57 #include "redisplay.h" |
57 #include "specifier.h" | 58 #include "specifier.h" |
58 #include "sysfile.h" | 59 #include "sysfile.h" |
60 #include "sysdep.h" | |
59 #include "window.h" | 61 #include "window.h" |
60 #include "console-stream.h" | 62 #include "console-stream.h" |
61 | 63 |
62 #ifdef DOUG_LEA_MALLOC | 64 #ifdef DOUG_LEA_MALLOC |
63 #include <malloc.h> | 65 #include <malloc.h> |
64 #endif | 66 #endif |
65 | 67 |
66 #ifdef HAVE_MMAP | 68 #ifdef PDUMP |
67 #include <unistd.h> | 69 #include "dumper.h" |
68 #include <sys/mman.h> | |
69 #endif | 70 #endif |
70 | 71 |
71 #ifdef PDUMP | |
72 typedef struct | |
73 { | |
74 const struct lrecord_description *desc; | |
75 int count; | |
76 } pdump_reloc_table; | |
77 | |
78 static char *pdump_rt_list = 0; | |
79 #endif | |
80 | |
81 EXFUN (Fgarbage_collect, 0); | 72 EXFUN (Fgarbage_collect, 0); |
82 | |
83 /* Return the true size of a struct with a variable-length array field. */ | |
84 #define STRETCHY_STRUCT_SIZEOF(stretchy_struct_type, \ | |
85 stretchy_array_field, \ | |
86 stretchy_array_length) \ | |
87 (offsetof (stretchy_struct_type, stretchy_array_field) + \ | |
88 (offsetof (stretchy_struct_type, stretchy_array_field[1]) - \ | |
89 offsetof (stretchy_struct_type, stretchy_array_field[0])) * \ | |
90 (stretchy_array_length)) | |
91 | 73 |
92 #if 0 /* this is _way_ too slow to be part of the standard debug options */ | 74 #if 0 /* this is _way_ too slow to be part of the standard debug options */ |
93 #if defined(DEBUG_XEMACS) && defined(MULE) | 75 #if defined(DEBUG_XEMACS) && defined(MULE) |
94 #define VERIFY_STRING_CHARS_INTEGRITY | 76 #define VERIFY_STRING_CHARS_INTEGRITY |
95 #endif | 77 #endif |
172 Lisp_Object Vpost_gc_hook, Qpost_gc_hook; | 154 Lisp_Object Vpost_gc_hook, Qpost_gc_hook; |
173 | 155 |
174 /* "Garbage collecting" */ | 156 /* "Garbage collecting" */ |
175 Lisp_Object Vgc_message; | 157 Lisp_Object Vgc_message; |
176 Lisp_Object Vgc_pointer_glyph; | 158 Lisp_Object Vgc_pointer_glyph; |
177 static CONST char gc_default_message[] = "Garbage collecting"; | 159 static const char gc_default_message[] = "Garbage collecting"; |
178 Lisp_Object Qgarbage_collecting; | 160 Lisp_Object Qgarbage_collecting; |
179 | |
180 #ifndef VIRT_ADDR_VARIES | |
181 extern | |
182 #endif /* VIRT_ADDR_VARIES */ | |
183 EMACS_INT malloc_sbrk_used; | |
184 | |
185 #ifndef VIRT_ADDR_VARIES | |
186 extern | |
187 #endif /* VIRT_ADDR_VARIES */ | |
188 EMACS_INT malloc_sbrk_unused; | |
189 | 161 |
190 /* Non-zero means we're in the process of doing the dump */ | 162 /* Non-zero means we're in the process of doing the dump */ |
191 int purify_flag; | 163 int purify_flag; |
192 | 164 |
193 #ifdef ERROR_CHECK_TYPECHECK | 165 #ifdef ERROR_CHECK_TYPECHECK |
232 } | 204 } |
233 } | 205 } |
234 | 206 |
235 /* malloc calls this if it finds we are near exhausting storage */ | 207 /* malloc calls this if it finds we are near exhausting storage */ |
236 void | 208 void |
237 malloc_warning (CONST char *str) | 209 malloc_warning (const char *str) |
238 { | 210 { |
239 if (ignore_malloc_warnings) | 211 if (ignore_malloc_warnings) |
240 return; | 212 return; |
241 | 213 |
242 warn_when_safe | 214 warn_when_safe |
355 | 327 |
356 #endif /* !ERROR_CHECK_GC */ | 328 #endif /* !ERROR_CHECK_GC */ |
357 | 329 |
358 #undef xstrdup | 330 #undef xstrdup |
359 char * | 331 char * |
360 xstrdup (CONST char *str) | 332 xstrdup (const char *str) |
361 { | 333 { |
362 int len = strlen (str) + 1; /* for stupid terminating 0 */ | 334 int len = strlen (str) + 1; /* for stupid terminating 0 */ |
363 | 335 |
364 void *val = xmalloc (len); | 336 void *val = xmalloc (len); |
365 if (val == 0) return 0; | 337 if (val == 0) return 0; |
366 return (char *) memcpy (val, str, len); | 338 return (char *) memcpy (val, str, len); |
367 } | 339 } |
368 | 340 |
369 #ifdef NEED_STRDUP | 341 #ifdef NEED_STRDUP |
370 char * | 342 char * |
371 strdup (CONST char *s) | 343 strdup (const char *s) |
372 { | 344 { |
373 return xstrdup (s); | 345 return xstrdup (s); |
374 } | 346 } |
375 #endif /* NEED_STRDUP */ | 347 #endif /* NEED_STRDUP */ |
376 | 348 |
380 { | 352 { |
381 return xmalloc (size); | 353 return xmalloc (size); |
382 } | 354 } |
383 | 355 |
384 | 356 |
385 /* lrecords are chained together through their "next.v" field. | 357 /* lcrecords are chained together through their "next" field. |
386 * After doing the mark phase, the GC will walk this linked | 358 After doing the mark phase, GC will walk this linked list |
387 * list and free any record which hasn't been marked. | 359 and free any lcrecord which hasn't been marked. */ |
388 */ | |
389 static struct lcrecord_header *all_lcrecords; | 360 static struct lcrecord_header *all_lcrecords; |
390 | 361 |
391 void * | 362 void * |
392 alloc_lcrecord (size_t size, CONST struct lrecord_implementation *implementation) | 363 alloc_lcrecord (size_t size, const struct lrecord_implementation *implementation) |
393 { | 364 { |
394 struct lcrecord_header *lcheader; | 365 struct lcrecord_header *lcheader; |
395 | 366 |
396 #ifdef ERROR_CHECK_GC | 367 type_checking_assert |
397 if (implementation->static_size == 0) | 368 ((implementation->static_size == 0 ? |
398 assert (implementation->size_in_bytes_method); | 369 implementation->size_in_bytes_method != NULL : |
399 else | 370 implementation->static_size == size) |
400 assert (implementation->static_size == size); | 371 && |
401 #endif | 372 (! implementation->basic_p) |
373 && | |
374 (! (implementation->hash == NULL && implementation->equal != NULL))); | |
402 | 375 |
403 lcheader = (struct lcrecord_header *) allocate_lisp_storage (size); | 376 lcheader = (struct lcrecord_header *) allocate_lisp_storage (size); |
404 set_lheader_implementation (&(lcheader->lheader), implementation); | 377 set_lheader_implementation (&lcheader->lheader, implementation); |
405 lcheader->next = all_lcrecords; | 378 lcheader->next = all_lcrecords; |
406 #if 1 /* mly prefers to see small ID numbers */ | 379 #if 1 /* mly prefers to see small ID numbers */ |
407 lcheader->uid = lrecord_uid_counter++; | 380 lcheader->uid = lrecord_uid_counter++; |
408 #else /* jwz prefers to see real addrs */ | 381 #else /* jwz prefers to see real addrs */ |
409 lcheader->uid = (int) &lcheader; | 382 lcheader->uid = (int) &lcheader; |
458 { | 431 { |
459 struct lcrecord_header *header; | 432 struct lcrecord_header *header; |
460 | 433 |
461 for (header = all_lcrecords; header; header = header->next) | 434 for (header = all_lcrecords; header; header = header->next) |
462 { | 435 { |
463 if (LHEADER_IMPLEMENTATION(&header->lheader)->finalizer && | 436 if (LHEADER_IMPLEMENTATION (&header->lheader)->finalizer && |
464 !header->free) | 437 !header->free) |
465 ((LHEADER_IMPLEMENTATION(&header->lheader)->finalizer) | 438 LHEADER_IMPLEMENTATION (&header->lheader)->finalizer (header, 1); |
466 (header, 1)); | 439 } |
467 } | |
468 } | |
469 | |
470 /* Semi-kludge -- lrecord_symbol_value_forward objects get stuck | |
471 in CONST space and you get SEGV's if you attempt to mark them. | |
472 This sits in lheader->implementation->marker. */ | |
473 | |
474 Lisp_Object | |
475 this_one_is_unmarkable (Lisp_Object obj) | |
476 { | |
477 abort (); | |
478 return Qnil; | |
479 } | 440 } |
480 | 441 |
481 | 442 |
482 /************************************************************************/ | 443 /************************************************************************/ |
483 /* Debugger support */ | 444 /* Debugger support */ |
492 | 453 |
493 #ifdef USE_UNION_TYPE | 454 #ifdef USE_UNION_TYPE |
494 unsigned char dbg_USE_UNION_TYPE = 1; | 455 unsigned char dbg_USE_UNION_TYPE = 1; |
495 #else | 456 #else |
496 unsigned char dbg_USE_UNION_TYPE = 0; | 457 unsigned char dbg_USE_UNION_TYPE = 0; |
497 #endif | |
498 | |
499 unsigned char Lisp_Type_Int = 100; | |
500 unsigned char Lisp_Type_Cons = 101; | |
501 unsigned char Lisp_Type_String = 102; | |
502 unsigned char Lisp_Type_Vector = 103; | |
503 unsigned char Lisp_Type_Symbol = 104; | |
504 | |
505 #ifndef MULE | |
506 unsigned char lrecord_char_table_entry; | |
507 unsigned char lrecord_charset; | |
508 #ifndef FILE_CODING | |
509 unsigned char lrecord_coding_system; | |
510 #endif | |
511 #endif | |
512 | |
513 #if !((defined HAVE_X_WINDOWS) && \ | |
514 (defined (HAVE_MENUBARS) || \ | |
515 defined (HAVE_SCROLLBARS) || \ | |
516 defined (HAVE_DIALOGS) || \ | |
517 defined (HAVE_TOOLBARS) || \ | |
518 defined (HAVE_WIDGETS))) | |
519 unsigned char lrecord_popup_data; | |
520 #endif | |
521 | |
522 #ifndef HAVE_TOOLBARS | |
523 unsigned char lrecord_toolbar_button; | |
524 #endif | |
525 | |
526 #ifndef TOOLTALK | |
527 unsigned char lrecord_tooltalk_message; | |
528 unsigned char lrecord_tooltalk_pattern; | |
529 #endif | |
530 | |
531 #ifndef HAVE_DATABASE | |
532 unsigned char lrecord_database; | |
533 #endif | 458 #endif |
534 | 459 |
535 unsigned char dbg_valbits = VALBITS; | 460 unsigned char dbg_valbits = VALBITS; |
536 unsigned char dbg_gctypebits = GCTYPEBITS; | 461 unsigned char dbg_gctypebits = GCTYPEBITS; |
537 | 462 |
711 try to set aside another reserve in case we run out once more. | 636 try to set aside another reserve in case we run out once more. |
712 | 637 |
713 This is called when a relocatable block is freed in ralloc.c. */ | 638 This is called when a relocatable block is freed in ralloc.c. */ |
714 void refill_memory_reserve (void); | 639 void refill_memory_reserve (void); |
715 void | 640 void |
716 refill_memory_reserve () | 641 refill_memory_reserve (void) |
717 { | 642 { |
718 if (breathing_space == 0) | 643 if (breathing_space == 0) |
719 breathing_space = (char *) malloc (4096 - MALLOC_OVERHEAD); | 644 breathing_space = (char *) malloc (4096 - MALLOC_OVERHEAD); |
720 } | 645 } |
721 #endif | 646 #endif |
850 # define INVALID_POINTER_VALUE 0xFFFFFFFFFFFFFFFF | 775 # define INVALID_POINTER_VALUE 0xFFFFFFFFFFFFFFFF |
851 #else | 776 #else |
852 You have some weird system and need to supply a reasonable value here. | 777 You have some weird system and need to supply a reasonable value here. |
853 #endif | 778 #endif |
854 | 779 |
780 /* The construct (* (void **) (ptr)) would cause aliasing problems | |
781 with modern optimizing compilers like `gcc -O3 -fstrict-aliasing'. | |
782 But `char *' can legally alias any pointer. Hence this union trick. */ | |
783 typedef union { char c; void *p; } *aliasing_voidpp; | |
784 #define ALIASING_VOIDPP_DEREFERENCE(ptr) \ | |
785 (((aliasing_voidpp) (ptr))->p) | |
855 #define FREE_STRUCT_P(ptr) \ | 786 #define FREE_STRUCT_P(ptr) \ |
856 (* (void **) ptr == (void *) INVALID_POINTER_VALUE) | 787 (ALIASING_VOIDPP_DEREFERENCE (ptr) == (void *) INVALID_POINTER_VALUE) |
857 #define MARK_STRUCT_AS_FREE(ptr) \ | 788 #define MARK_STRUCT_AS_FREE(ptr) \ |
858 (* (void **) ptr = (void *) INVALID_POINTER_VALUE) | 789 (ALIASING_VOIDPP_DEREFERENCE (ptr) = (void *) INVALID_POINTER_VALUE) |
859 #define MARK_STRUCT_AS_NOT_FREE(ptr) \ | 790 #define MARK_STRUCT_AS_NOT_FREE(ptr) \ |
860 (* (void **) ptr = 0) | 791 (ALIASING_VOIDPP_DEREFERENCE (ptr) = 0) |
861 | 792 |
862 #ifdef ERROR_CHECK_GC | 793 #ifdef ERROR_CHECK_GC |
863 | 794 |
864 #define PUT_FIXED_TYPE_ON_FREE_LIST(type, structtype, ptr) \ | 795 #define PUT_FIXED_TYPE_ON_FREE_LIST(type, structtype, ptr) \ |
865 do { if (type##_free_list_tail) \ | 796 do { if (type##_free_list_tail) \ |
938 } | 869 } |
939 | 870 |
940 static int | 871 static int |
941 cons_equal (Lisp_Object ob1, Lisp_Object ob2, int depth) | 872 cons_equal (Lisp_Object ob1, Lisp_Object ob2, int depth) |
942 { | 873 { |
943 while (internal_equal (XCAR (ob1), XCAR (ob2), depth + 1)) | 874 depth++; |
875 while (internal_equal (XCAR (ob1), XCAR (ob2), depth)) | |
944 { | 876 { |
945 ob1 = XCDR (ob1); | 877 ob1 = XCDR (ob1); |
946 ob2 = XCDR (ob2); | 878 ob2 = XCDR (ob2); |
947 if (! CONSP (ob1) || ! CONSP (ob2)) | 879 if (! CONSP (ob1) || ! CONSP (ob2)) |
948 return internal_equal (ob1, ob2, depth + 1); | 880 return internal_equal (ob1, ob2, depth); |
949 } | 881 } |
950 return 0; | 882 return 0; |
951 } | 883 } |
952 | 884 |
953 static const struct lrecord_description cons_description[] = { | 885 static const struct lrecord_description cons_description[] = { |
976 /* This cannot GC. */ | 908 /* This cannot GC. */ |
977 Lisp_Object val; | 909 Lisp_Object val; |
978 Lisp_Cons *c; | 910 Lisp_Cons *c; |
979 | 911 |
980 ALLOCATE_FIXED_TYPE (cons, Lisp_Cons, c); | 912 ALLOCATE_FIXED_TYPE (cons, Lisp_Cons, c); |
981 set_lheader_implementation (&(c->lheader), &lrecord_cons); | 913 set_lheader_implementation (&c->lheader, &lrecord_cons); |
982 XSETCONS (val, c); | 914 XSETCONS (val, c); |
983 c->car = car; | 915 c->car = car; |
984 c->cdr = cdr; | 916 c->cdr = cdr; |
985 return val; | 917 return val; |
986 } | 918 } |
993 { | 925 { |
994 Lisp_Object val; | 926 Lisp_Object val; |
995 Lisp_Cons *c; | 927 Lisp_Cons *c; |
996 | 928 |
997 NOSEEUM_ALLOCATE_FIXED_TYPE (cons, Lisp_Cons, c); | 929 NOSEEUM_ALLOCATE_FIXED_TYPE (cons, Lisp_Cons, c); |
998 set_lheader_implementation (&(c->lheader), &lrecord_cons); | 930 set_lheader_implementation (&c->lheader, &lrecord_cons); |
999 XSETCONS (val, c); | 931 XSETCONS (val, c); |
1000 XCAR (val) = car; | 932 XCAR (val) = car; |
1001 XCDR (val) = cdr; | 933 XCDR (val) = cdr; |
1002 return val; | 934 return val; |
1003 } | 935 } |
1110 | 1042 |
1111 /* Avoid dump-time `uninitialized memory read' purify warnings. */ | 1043 /* Avoid dump-time `uninitialized memory read' purify warnings. */ |
1112 if (sizeof (struct lrecord_header) + sizeof (double) != sizeof (*f)) | 1044 if (sizeof (struct lrecord_header) + sizeof (double) != sizeof (*f)) |
1113 xzero (*f); | 1045 xzero (*f); |
1114 | 1046 |
1115 set_lheader_implementation (&(f->lheader), &lrecord_float); | 1047 set_lheader_implementation (&f->lheader, &lrecord_float); |
1116 float_data (f) = float_value; | 1048 float_data (f) = float_value; |
1117 XSETFLOAT (val, f); | 1049 XSETFLOAT (val, f); |
1118 return val; | 1050 return val; |
1119 } | 1051 } |
1120 | 1052 |
1136 mark_object (ptr->contents[i]); | 1068 mark_object (ptr->contents[i]); |
1137 return (len > 0) ? ptr->contents[len - 1] : Qnil; | 1069 return (len > 0) ? ptr->contents[len - 1] : Qnil; |
1138 } | 1070 } |
1139 | 1071 |
1140 static size_t | 1072 static size_t |
1141 size_vector (CONST void *lheader) | 1073 size_vector (const void *lheader) |
1142 { | 1074 { |
1143 return STRETCHY_STRUCT_SIZEOF (Lisp_Vector, contents, | 1075 return FLEXIBLE_ARRAY_STRUCT_SIZEOF (Lisp_Vector, contents, |
1144 ((Lisp_Vector *) lheader)->size); | 1076 ((Lisp_Vector *) lheader)->size); |
1145 } | 1077 } |
1146 | 1078 |
1147 static int | 1079 static int |
1148 vector_equal (Lisp_Object obj1, Lisp_Object obj2, int depth) | 1080 vector_equal (Lisp_Object obj1, Lisp_Object obj2, int depth) |
1149 { | 1081 { |
1159 return 0; | 1091 return 0; |
1160 } | 1092 } |
1161 return 1; | 1093 return 1; |
1162 } | 1094 } |
1163 | 1095 |
1096 static hashcode_t | |
1097 vector_hash (Lisp_Object obj, int depth) | |
1098 { | |
1099 return HASH2 (XVECTOR_LENGTH (obj), | |
1100 internal_array_hash (XVECTOR_DATA (obj), | |
1101 XVECTOR_LENGTH (obj), | |
1102 depth + 1)); | |
1103 } | |
1104 | |
1164 static const struct lrecord_description vector_description[] = { | 1105 static const struct lrecord_description vector_description[] = { |
1165 { XD_LONG, offsetof (Lisp_Vector, size) }, | 1106 { XD_LONG, offsetof (Lisp_Vector, size) }, |
1166 { XD_LISP_OBJECT_ARRAY, offsetof (Lisp_Vector, contents), XD_INDIRECT(0, 0) }, | 1107 { XD_LISP_OBJECT_ARRAY, offsetof (Lisp_Vector, contents), XD_INDIRECT(0, 0) }, |
1167 { XD_END } | 1108 { XD_END } |
1168 }; | 1109 }; |
1169 | 1110 |
1170 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION("vector", vector, | 1111 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION("vector", vector, |
1171 mark_vector, print_vector, 0, | 1112 mark_vector, print_vector, 0, |
1172 vector_equal, | 1113 vector_equal, |
1173 /* | 1114 vector_hash, |
1174 * No `hash' method needed for | |
1175 * vectors. internal_hash | |
1176 * knows how to handle vectors. | |
1177 */ | |
1178 0, | |
1179 vector_description, | 1115 vector_description, |
1180 size_vector, Lisp_Vector); | 1116 size_vector, Lisp_Vector); |
1181 | 1117 |
1182 /* #### should allocate `small' vectors from a frob-block */ | 1118 /* #### should allocate `small' vectors from a frob-block */ |
1183 static Lisp_Vector * | 1119 static Lisp_Vector * |
1184 make_vector_internal (size_t sizei) | 1120 make_vector_internal (size_t sizei) |
1185 { | 1121 { |
1186 /* no vector_next */ | 1122 /* no vector_next */ |
1187 size_t sizem = STRETCHY_STRUCT_SIZEOF (Lisp_Vector, contents, sizei); | 1123 size_t sizem = FLEXIBLE_ARRAY_STRUCT_SIZEOF (Lisp_Vector, contents, sizei); |
1188 Lisp_Vector *p = (Lisp_Vector *) alloc_lcrecord (sizem, &lrecord_vector); | 1124 Lisp_Vector *p = (Lisp_Vector *) alloc_lcrecord (sizem, &lrecord_vector); |
1189 | 1125 |
1190 p->size = sizei; | 1126 p->size = sizei; |
1191 return p; | 1127 return p; |
1192 } | 1128 } |
1345 /* #### should allocate `small' bit vectors from a frob-block */ | 1281 /* #### should allocate `small' bit vectors from a frob-block */ |
1346 static Lisp_Bit_Vector * | 1282 static Lisp_Bit_Vector * |
1347 make_bit_vector_internal (size_t sizei) | 1283 make_bit_vector_internal (size_t sizei) |
1348 { | 1284 { |
1349 size_t num_longs = BIT_VECTOR_LONG_STORAGE (sizei); | 1285 size_t num_longs = BIT_VECTOR_LONG_STORAGE (sizei); |
1350 size_t sizem = STRETCHY_STRUCT_SIZEOF (Lisp_Bit_Vector, bits, num_longs); | 1286 size_t sizem = FLEXIBLE_ARRAY_STRUCT_SIZEOF (Lisp_Bit_Vector, bits, num_longs); |
1351 Lisp_Bit_Vector *p = (Lisp_Bit_Vector *) allocate_lisp_storage (sizem); | 1287 Lisp_Bit_Vector *p = (Lisp_Bit_Vector *) allocate_lisp_storage (sizem); |
1352 set_lheader_implementation (&(p->lheader), &lrecord_bit_vector); | 1288 set_lheader_implementation (&p->lheader, &lrecord_bit_vector); |
1353 | 1289 |
1354 INCREMENT_CONS_COUNTER (sizem, "bit-vector"); | 1290 INCREMENT_CONS_COUNTER (sizem, "bit-vector"); |
1355 | 1291 |
1356 bit_vector_length (p) = sizei; | 1292 bit_vector_length (p) = sizei; |
1357 bit_vector_next (p) = all_bit_vectors; | 1293 bit_vector_next (p) = all_bit_vectors; |
1451 { | 1387 { |
1452 Lisp_Compiled_Function *f; | 1388 Lisp_Compiled_Function *f; |
1453 Lisp_Object fun; | 1389 Lisp_Object fun; |
1454 | 1390 |
1455 ALLOCATE_FIXED_TYPE (compiled_function, Lisp_Compiled_Function, f); | 1391 ALLOCATE_FIXED_TYPE (compiled_function, Lisp_Compiled_Function, f); |
1456 set_lheader_implementation (&(f->lheader), &lrecord_compiled_function); | 1392 set_lheader_implementation (&f->lheader, &lrecord_compiled_function); |
1457 | 1393 |
1458 f->stack_depth = 0; | 1394 f->stack_depth = 0; |
1459 f->specpdl_depth = 0; | 1395 f->specpdl_depth = 0; |
1460 f->flags.documentationp = 0; | 1396 f->flags.documentationp = 0; |
1461 f->flags.interactivep = 0; | 1397 f->flags.interactivep = 0; |
1503 list2 (intern ("make-byte-code"), make_int (nargs))); | 1439 list2 (intern ("make-byte-code"), make_int (nargs))); |
1504 | 1440 |
1505 /* Check for valid formal parameter list now, to allow us to use | 1441 /* Check for valid formal parameter list now, to allow us to use |
1506 SPECBIND_FAST_UNSAFE() later in funcall_compiled_function(). */ | 1442 SPECBIND_FAST_UNSAFE() later in funcall_compiled_function(). */ |
1507 { | 1443 { |
1508 Lisp_Object symbol, tail; | |
1509 EXTERNAL_LIST_LOOP_3 (symbol, arglist, tail) | 1444 EXTERNAL_LIST_LOOP_3 (symbol, arglist, tail) |
1510 { | 1445 { |
1511 CHECK_SYMBOL (symbol); | 1446 CHECK_SYMBOL (symbol); |
1512 if (EQ (symbol, Qt) || | 1447 if (EQ (symbol, Qt) || |
1513 EQ (symbol, Qnil) || | 1448 EQ (symbol, Qnil) || |
1535 if (!NILP (constants)) | 1470 if (!NILP (constants)) |
1536 CHECK_VECTOR (constants); | 1471 CHECK_VECTOR (constants); |
1537 f->constants = constants; | 1472 f->constants = constants; |
1538 | 1473 |
1539 CHECK_NATNUM (stack_depth); | 1474 CHECK_NATNUM (stack_depth); |
1540 f->stack_depth = XINT (stack_depth); | 1475 f->stack_depth = (unsigned short) XINT (stack_depth); |
1541 | 1476 |
1542 #ifdef COMPILED_FUNCTION_ANNOTATION_HACK | 1477 #ifdef COMPILED_FUNCTION_ANNOTATION_HACK |
1543 if (!NILP (Vcurrent_compiled_function_annotation)) | 1478 if (!NILP (Vcurrent_compiled_function_annotation)) |
1544 f->annotated = Fcopy (Vcurrent_compiled_function_annotation); | 1479 f->annotated = Fcopy (Vcurrent_compiled_function_annotation); |
1545 else if (!NILP (Vload_file_name_internal_the_purecopy)) | 1480 else if (!NILP (Vload_file_name_internal_the_purecopy)) |
1598 Lisp_Symbol *p; | 1533 Lisp_Symbol *p; |
1599 | 1534 |
1600 CHECK_STRING (name); | 1535 CHECK_STRING (name); |
1601 | 1536 |
1602 ALLOCATE_FIXED_TYPE (symbol, Lisp_Symbol, p); | 1537 ALLOCATE_FIXED_TYPE (symbol, Lisp_Symbol, p); |
1603 set_lheader_implementation (&(p->lheader), &lrecord_symbol); | 1538 set_lheader_implementation (&p->lheader, &lrecord_symbol); |
1604 p->name = XSTRING (name); | 1539 p->name = XSTRING (name); |
1605 p->plist = Qnil; | 1540 p->plist = Qnil; |
1606 p->value = Qunbound; | 1541 p->value = Qunbound; |
1607 p->function = Qunbound; | 1542 p->function = Qunbound; |
1608 symbol_next (p) = 0; | 1543 symbol_next (p) = 0; |
1622 allocate_extent (void) | 1557 allocate_extent (void) |
1623 { | 1558 { |
1624 struct extent *e; | 1559 struct extent *e; |
1625 | 1560 |
1626 ALLOCATE_FIXED_TYPE (extent, struct extent, e); | 1561 ALLOCATE_FIXED_TYPE (extent, struct extent, e); |
1627 set_lheader_implementation (&(e->lheader), &lrecord_extent); | 1562 set_lheader_implementation (&e->lheader, &lrecord_extent); |
1628 extent_object (e) = Qnil; | 1563 extent_object (e) = Qnil; |
1629 set_extent_start (e, -1); | 1564 set_extent_start (e, -1); |
1630 set_extent_end (e, -1); | 1565 set_extent_end (e, -1); |
1631 e->plist = Qnil; | 1566 e->plist = Qnil; |
1632 | 1567 |
1652 { | 1587 { |
1653 Lisp_Object val; | 1588 Lisp_Object val; |
1654 Lisp_Event *e; | 1589 Lisp_Event *e; |
1655 | 1590 |
1656 ALLOCATE_FIXED_TYPE (event, Lisp_Event, e); | 1591 ALLOCATE_FIXED_TYPE (event, Lisp_Event, e); |
1657 set_lheader_implementation (&(e->lheader), &lrecord_event); | 1592 set_lheader_implementation (&e->lheader, &lrecord_event); |
1658 | 1593 |
1659 XSETEVENT (val, e); | 1594 XSETEVENT (val, e); |
1660 return val; | 1595 return val; |
1661 } | 1596 } |
1662 | 1597 |
1675 { | 1610 { |
1676 Lisp_Object val; | 1611 Lisp_Object val; |
1677 Lisp_Marker *p; | 1612 Lisp_Marker *p; |
1678 | 1613 |
1679 ALLOCATE_FIXED_TYPE (marker, Lisp_Marker, p); | 1614 ALLOCATE_FIXED_TYPE (marker, Lisp_Marker, p); |
1680 set_lheader_implementation (&(p->lheader), &lrecord_marker); | 1615 set_lheader_implementation (&p->lheader, &lrecord_marker); |
1681 p->buffer = 0; | 1616 p->buffer = 0; |
1682 p->memind = 0; | 1617 p->memind = 0; |
1683 marker_next (p) = 0; | 1618 marker_next (p) = 0; |
1684 marker_prev (p) = 0; | 1619 marker_prev (p) = 0; |
1685 p->insertion_type = 0; | 1620 p->insertion_type = 0; |
1692 { | 1627 { |
1693 Lisp_Object val; | 1628 Lisp_Object val; |
1694 Lisp_Marker *p; | 1629 Lisp_Marker *p; |
1695 | 1630 |
1696 NOSEEUM_ALLOCATE_FIXED_TYPE (marker, Lisp_Marker, p); | 1631 NOSEEUM_ALLOCATE_FIXED_TYPE (marker, Lisp_Marker, p); |
1697 set_lheader_implementation (&(p->lheader), &lrecord_marker); | 1632 set_lheader_implementation (&p->lheader, &lrecord_marker); |
1698 p->buffer = 0; | 1633 p->buffer = 0; |
1699 p->memind = 0; | 1634 p->memind = 0; |
1700 marker_next (p) = 0; | 1635 marker_next (p) = 0; |
1701 marker_prev (p) = 0; | 1636 marker_prev (p) = 0; |
1702 p->insertion_type = 0; | 1637 p->insertion_type = 0; |
1750 { XD_OPAQUE_DATA_PTR, offsetof (Lisp_String, data), XD_INDIRECT(0, 1) }, | 1685 { XD_OPAQUE_DATA_PTR, offsetof (Lisp_String, data), XD_INDIRECT(0, 1) }, |
1751 { XD_LISP_OBJECT, offsetof (Lisp_String, plist) }, | 1686 { XD_LISP_OBJECT, offsetof (Lisp_String, plist) }, |
1752 { XD_END } | 1687 { XD_END } |
1753 }; | 1688 }; |
1754 | 1689 |
1755 DEFINE_BASIC_LRECORD_IMPLEMENTATION ("string", string, | 1690 /* We store the string's extent info as the first element of the string's |
1756 mark_string, print_string, | 1691 property list; and the string's MODIFF as the first or second element |
1757 /* | 1692 of the string's property list (depending on whether the extent info |
1758 * No `finalize', or `hash' methods. | 1693 is present), but only if the string has been modified. This is ugly |
1759 * internal_hash already knows how | 1694 but it reduces the memory allocated for the string in the vast |
1760 * to hash strings and finalization | 1695 majority of cases, where the string is never modified and has no |
1761 * is done with the | 1696 extent info. |
1762 * ADDITIONAL_FREE_string macro, | 1697 |
1763 * which is the standard way to do | 1698 #### This means you can't use an int as a key in a string's plist. */ |
1764 * finalization when using | 1699 |
1765 * SWEEP_FIXED_TYPE_BLOCK(). | 1700 static Lisp_Object * |
1766 */ | 1701 string_plist_ptr (Lisp_Object string) |
1767 0, string_equal, 0, | 1702 { |
1768 string_description, | 1703 Lisp_Object *ptr = &XSTRING (string)->plist; |
1769 Lisp_String); | 1704 |
1705 if (CONSP (*ptr) && EXTENT_INFOP (XCAR (*ptr))) | |
1706 ptr = &XCDR (*ptr); | |
1707 if (CONSP (*ptr) && INTP (XCAR (*ptr))) | |
1708 ptr = &XCDR (*ptr); | |
1709 return ptr; | |
1710 } | |
1711 | |
1712 static Lisp_Object | |
1713 string_getprop (Lisp_Object string, Lisp_Object property) | |
1714 { | |
1715 return external_plist_get (string_plist_ptr (string), property, 0, ERROR_ME); | |
1716 } | |
1717 | |
1718 static int | |
1719 string_putprop (Lisp_Object string, Lisp_Object property, Lisp_Object value) | |
1720 { | |
1721 external_plist_put (string_plist_ptr (string), property, value, 0, ERROR_ME); | |
1722 return 1; | |
1723 } | |
1724 | |
1725 static int | |
1726 string_remprop (Lisp_Object string, Lisp_Object property) | |
1727 { | |
1728 return external_remprop (string_plist_ptr (string), property, 0, ERROR_ME); | |
1729 } | |
1730 | |
1731 static Lisp_Object | |
1732 string_plist (Lisp_Object string) | |
1733 { | |
1734 return *string_plist_ptr (string); | |
1735 } | |
1736 | |
1737 /* No `finalize', or `hash' methods. | |
1738 internal_hash() already knows how to hash strings and finalization | |
1739 is done with the ADDITIONAL_FREE_string macro, which is the | |
1740 standard way to do finalization when using | |
1741 SWEEP_FIXED_TYPE_BLOCK(). */ | |
1742 DEFINE_BASIC_LRECORD_IMPLEMENTATION_WITH_PROPS ("string", string, | |
1743 mark_string, print_string, | |
1744 0, string_equal, 0, | |
1745 string_description, | |
1746 string_getprop, | |
1747 string_putprop, | |
1748 string_remprop, | |
1749 string_plist, | |
1750 Lisp_String); | |
1770 | 1751 |
1771 /* String blocks contain this many useful bytes. */ | 1752 /* String blocks contain this many useful bytes. */ |
1772 #define STRING_CHARS_BLOCK_SIZE \ | 1753 #define STRING_CHARS_BLOCK_SIZE \ |
1773 ((Bytecount) (8192 - MALLOC_OVERHEAD - \ | 1754 ((Bytecount) (8192 - MALLOC_OVERHEAD - \ |
1774 ((2 * sizeof (struct string_chars_block *)) \ | 1755 ((2 * sizeof (struct string_chars_block *)) \ |
1866 | 1847 |
1867 assert (length >= 0 && fullsize > 0); | 1848 assert (length >= 0 && fullsize > 0); |
1868 | 1849 |
1869 /* Allocate the string header */ | 1850 /* Allocate the string header */ |
1870 ALLOCATE_FIXED_TYPE (string, Lisp_String, s); | 1851 ALLOCATE_FIXED_TYPE (string, Lisp_String, s); |
1871 set_lheader_implementation (&(s->lheader), &lrecord_string); | 1852 set_lheader_implementation (&s->lheader, &lrecord_string); |
1872 | 1853 |
1873 set_string_data (s, BIG_STRING_FULLSIZE_P (fullsize) | 1854 set_string_data (s, BIG_STRING_FULLSIZE_P (fullsize) |
1874 ? xnew_array (Bufbyte, length + 1) | 1855 ? xnew_array (Bufbyte, length + 1) |
1875 : allocate_string_chars_struct (s, fullsize)->chars); | 1856 : allocate_string_chars_struct (s, fullsize)->chars); |
1876 | 1857 |
2109 | 2090 |
2110 | 2091 |
2111 /* Take some raw memory, which MUST already be in internal format, | 2092 /* Take some raw memory, which MUST already be in internal format, |
2112 and package it up into a Lisp string. */ | 2093 and package it up into a Lisp string. */ |
2113 Lisp_Object | 2094 Lisp_Object |
2114 make_string (CONST Bufbyte *contents, Bytecount length) | 2095 make_string (const Bufbyte *contents, Bytecount length) |
2115 { | 2096 { |
2116 Lisp_Object val; | 2097 Lisp_Object val; |
2117 | 2098 |
2118 /* Make sure we find out about bad make_string's when they happen */ | 2099 /* Make sure we find out about bad make_string's when they happen */ |
2119 #if defined (ERROR_CHECK_BUFPOS) && defined (MULE) | 2100 #if defined (ERROR_CHECK_BUFPOS) && defined (MULE) |
2126 } | 2107 } |
2127 | 2108 |
2128 /* Take some raw memory, encoded in some external data format, | 2109 /* Take some raw memory, encoded in some external data format, |
2129 and convert it into a Lisp string. */ | 2110 and convert it into a Lisp string. */ |
2130 Lisp_Object | 2111 Lisp_Object |
2131 make_ext_string (CONST Extbyte *contents, EMACS_INT length, | 2112 make_ext_string (const Extbyte *contents, EMACS_INT length, |
2132 Lisp_Object coding_system) | 2113 Lisp_Object coding_system) |
2133 { | 2114 { |
2134 Lisp_Object string; | 2115 Lisp_Object string; |
2135 TO_INTERNAL_FORMAT (DATA, (contents, length), | 2116 TO_INTERNAL_FORMAT (DATA, (contents, length), |
2136 LISP_STRING, string, | 2117 LISP_STRING, string, |
2137 coding_system); | 2118 coding_system); |
2138 return string; | 2119 return string; |
2139 } | 2120 } |
2140 | 2121 |
2141 Lisp_Object | 2122 Lisp_Object |
2142 build_string (CONST char *str) | 2123 build_string (const char *str) |
2143 { | 2124 { |
2144 /* Some strlen's crash and burn if passed null. */ | 2125 /* Some strlen's crash and burn if passed null. */ |
2145 return make_string ((CONST Bufbyte *) str, (str ? strlen(str) : 0)); | 2126 return make_string ((const Bufbyte *) str, (str ? strlen(str) : 0)); |
2146 } | 2127 } |
2147 | 2128 |
2148 Lisp_Object | 2129 Lisp_Object |
2149 build_ext_string (CONST char *str, Lisp_Object coding_system) | 2130 build_ext_string (const char *str, Lisp_Object coding_system) |
2150 { | 2131 { |
2151 /* Some strlen's crash and burn if passed null. */ | 2132 /* Some strlen's crash and burn if passed null. */ |
2152 return make_ext_string ((CONST Extbyte *) str, (str ? strlen(str) : 0), | 2133 return make_ext_string ((const Extbyte *) str, (str ? strlen(str) : 0), |
2153 coding_system); | 2134 coding_system); |
2154 } | 2135 } |
2155 | 2136 |
2156 Lisp_Object | 2137 Lisp_Object |
2157 build_translated_string (CONST char *str) | 2138 build_translated_string (const char *str) |
2158 { | 2139 { |
2159 return build_string (GETTEXT (str)); | 2140 return build_string (GETTEXT (str)); |
2160 } | 2141 } |
2161 | 2142 |
2162 Lisp_Object | 2143 Lisp_Object |
2163 make_string_nocopy (CONST Bufbyte *contents, Bytecount length) | 2144 make_string_nocopy (const Bufbyte *contents, Bytecount length) |
2164 { | 2145 { |
2165 Lisp_String *s; | 2146 Lisp_String *s; |
2166 Lisp_Object val; | 2147 Lisp_Object val; |
2167 | 2148 |
2168 /* Make sure we find out about bad make_string_nocopy's when they happen */ | 2149 /* Make sure we find out about bad make_string_nocopy's when they happen */ |
2170 bytecount_to_charcount (contents, length); /* Just for the assertions */ | 2151 bytecount_to_charcount (contents, length); /* Just for the assertions */ |
2171 #endif | 2152 #endif |
2172 | 2153 |
2173 /* Allocate the string header */ | 2154 /* Allocate the string header */ |
2174 ALLOCATE_FIXED_TYPE (string, Lisp_String, s); | 2155 ALLOCATE_FIXED_TYPE (string, Lisp_String, s); |
2175 set_lheader_implementation (&(s->lheader), &lrecord_string); | 2156 set_lheader_implementation (&s->lheader, &lrecord_string); |
2176 SET_C_READONLY_RECORD_HEADER (&s->lheader); | 2157 SET_C_READONLY_RECORD_HEADER (&s->lheader); |
2177 s->plist = Qnil; | 2158 s->plist = Qnil; |
2178 set_string_data (s, (Bufbyte *)contents); | 2159 set_string_data (s, (Bufbyte *)contents); |
2179 set_string_length (s, length); | 2160 set_string_length (s, length); |
2180 | 2161 |
2225 { | 2206 { |
2226 struct lrecord_header *lheader = XRECORD_LHEADER (chain); | 2207 struct lrecord_header *lheader = XRECORD_LHEADER (chain); |
2227 struct free_lcrecord_header *free_header = | 2208 struct free_lcrecord_header *free_header = |
2228 (struct free_lcrecord_header *) lheader; | 2209 (struct free_lcrecord_header *) lheader; |
2229 | 2210 |
2230 #ifdef ERROR_CHECK_GC | 2211 gc_checking_assert |
2231 CONST struct lrecord_implementation *implementation | 2212 (/* There should be no other pointers to the free list. */ |
2232 = LHEADER_IMPLEMENTATION(lheader); | 2213 ! MARKED_RECORD_HEADER_P (lheader) |
2233 | 2214 && |
2234 /* There should be no other pointers to the free list. */ | 2215 /* Only lcrecords should be here. */ |
2235 assert (!MARKED_RECORD_HEADER_P (lheader)); | 2216 ! LHEADER_IMPLEMENTATION (lheader)->basic_p |
2236 /* Only lcrecords should be here. */ | 2217 && |
2237 assert (!implementation->basic_p); | 2218 /* Only free lcrecords should be here. */ |
2238 /* Only free lcrecords should be here. */ | 2219 free_header->lcheader.free |
2239 assert (free_header->lcheader.free); | 2220 && |
2240 /* The type of the lcrecord must be right. */ | 2221 /* The type of the lcrecord must be right. */ |
2241 assert (implementation == list->implementation); | 2222 LHEADER_IMPLEMENTATION (lheader) == list->implementation |
2242 /* So must the size. */ | 2223 && |
2243 assert (implementation->static_size == 0 | 2224 /* So must the size. */ |
2244 || implementation->static_size == list->size); | 2225 (LHEADER_IMPLEMENTATION (lheader)->static_size == 0 || |
2245 #endif /* ERROR_CHECK_GC */ | 2226 LHEADER_IMPLEMENTATION (lheader)->static_size == list->size) |
2227 ); | |
2246 | 2228 |
2247 MARK_RECORD_HEADER (lheader); | 2229 MARK_RECORD_HEADER (lheader); |
2248 chain = free_header->chain; | 2230 chain = free_header->chain; |
2249 } | 2231 } |
2250 | 2232 |
2254 DEFINE_LRECORD_IMPLEMENTATION ("lcrecord-list", lcrecord_list, | 2236 DEFINE_LRECORD_IMPLEMENTATION ("lcrecord-list", lcrecord_list, |
2255 mark_lcrecord_list, internal_object_printer, | 2237 mark_lcrecord_list, internal_object_printer, |
2256 0, 0, 0, 0, struct lcrecord_list); | 2238 0, 0, 0, 0, struct lcrecord_list); |
2257 Lisp_Object | 2239 Lisp_Object |
2258 make_lcrecord_list (size_t size, | 2240 make_lcrecord_list (size_t size, |
2259 CONST struct lrecord_implementation *implementation) | 2241 const struct lrecord_implementation *implementation) |
2260 { | 2242 { |
2261 struct lcrecord_list *p = alloc_lcrecord_type (struct lcrecord_list, | 2243 struct lcrecord_list *p = alloc_lcrecord_type (struct lcrecord_list, |
2262 &lrecord_lcrecord_list); | 2244 &lrecord_lcrecord_list); |
2263 Lisp_Object val; | 2245 Lisp_Object val; |
2264 | 2246 |
2278 Lisp_Object val = list->free; | 2260 Lisp_Object val = list->free; |
2279 struct free_lcrecord_header *free_header = | 2261 struct free_lcrecord_header *free_header = |
2280 (struct free_lcrecord_header *) XPNTR (val); | 2262 (struct free_lcrecord_header *) XPNTR (val); |
2281 | 2263 |
2282 #ifdef ERROR_CHECK_GC | 2264 #ifdef ERROR_CHECK_GC |
2283 struct lrecord_header *lheader = | 2265 struct lrecord_header *lheader = &free_header->lcheader.lheader; |
2284 (struct lrecord_header *) free_header; | |
2285 CONST struct lrecord_implementation *implementation | |
2286 = LHEADER_IMPLEMENTATION (lheader); | |
2287 | 2266 |
2288 /* There should be no other pointers to the free list. */ | 2267 /* There should be no other pointers to the free list. */ |
2289 assert (!MARKED_RECORD_HEADER_P (lheader)); | 2268 assert (! MARKED_RECORD_HEADER_P (lheader)); |
2290 /* Only lcrecords should be here. */ | 2269 /* Only lcrecords should be here. */ |
2291 assert (!implementation->basic_p); | 2270 assert (! LHEADER_IMPLEMENTATION (lheader)->basic_p); |
2292 /* Only free lcrecords should be here. */ | 2271 /* Only free lcrecords should be here. */ |
2293 assert (free_header->lcheader.free); | 2272 assert (free_header->lcheader.free); |
2294 /* The type of the lcrecord must be right. */ | 2273 /* The type of the lcrecord must be right. */ |
2295 assert (implementation == list->implementation); | 2274 assert (LHEADER_IMPLEMENTATION (lheader) == list->implementation); |
2296 /* So must the size. */ | 2275 /* So must the size. */ |
2297 assert (implementation->static_size == 0 | 2276 assert (LHEADER_IMPLEMENTATION (lheader)->static_size == 0 || |
2298 || implementation->static_size == list->size); | 2277 LHEADER_IMPLEMENTATION (lheader)->static_size == list->size); |
2299 #endif /* ERROR_CHECK_GC */ | 2278 #endif /* ERROR_CHECK_GC */ |
2279 | |
2300 list->free = free_header->chain; | 2280 list->free = free_header->chain; |
2301 free_header->lcheader.free = 0; | 2281 free_header->lcheader.free = 0; |
2302 return val; | 2282 return val; |
2303 } | 2283 } |
2304 else | 2284 else |
2305 { | 2285 { |
2306 Lisp_Object val; | 2286 Lisp_Object val; |
2307 | 2287 |
2308 XSETOBJ (val, Lisp_Type_Record, | 2288 XSETOBJ (val, alloc_lcrecord (list->size, list->implementation)); |
2309 alloc_lcrecord (list->size, list->implementation)); | |
2310 return val; | 2289 return val; |
2311 } | 2290 } |
2312 } | 2291 } |
2313 | 2292 |
2314 void | 2293 void |
2315 free_managed_lcrecord (Lisp_Object lcrecord_list, Lisp_Object lcrecord) | 2294 free_managed_lcrecord (Lisp_Object lcrecord_list, Lisp_Object lcrecord) |
2316 { | 2295 { |
2317 struct lcrecord_list *list = XLCRECORD_LIST (lcrecord_list); | 2296 struct lcrecord_list *list = XLCRECORD_LIST (lcrecord_list); |
2318 struct free_lcrecord_header *free_header = | 2297 struct free_lcrecord_header *free_header = |
2319 (struct free_lcrecord_header *) XPNTR (lcrecord); | 2298 (struct free_lcrecord_header *) XPNTR (lcrecord); |
2320 struct lrecord_header *lheader = | 2299 struct lrecord_header *lheader = &free_header->lcheader.lheader; |
2321 (struct lrecord_header *) free_header; | 2300 const struct lrecord_implementation *implementation |
2322 CONST struct lrecord_implementation *implementation | |
2323 = LHEADER_IMPLEMENTATION (lheader); | 2301 = LHEADER_IMPLEMENTATION (lheader); |
2324 | 2302 |
2325 #ifdef ERROR_CHECK_GC | |
2326 /* Make sure the size is correct. This will catch, for example, | 2303 /* Make sure the size is correct. This will catch, for example, |
2327 putting a window configuration on the wrong free list. */ | 2304 putting a window configuration on the wrong free list. */ |
2328 if (implementation->size_in_bytes_method) | 2305 gc_checking_assert ((implementation->size_in_bytes_method ? |
2329 assert (implementation->size_in_bytes_method (lheader) == list->size); | 2306 implementation->size_in_bytes_method (lheader) : |
2330 else | 2307 implementation->static_size) |
2331 assert (implementation->static_size == list->size); | 2308 == list->size); |
2332 #endif /* ERROR_CHECK_GC */ | |
2333 | 2309 |
2334 if (implementation->finalizer) | 2310 if (implementation->finalizer) |
2335 implementation->finalizer (lheader, 0); | 2311 implementation->finalizer (lheader, 0); |
2336 free_header->chain = list->free; | 2312 free_header->chain = list->free; |
2337 free_header->lcheader.free = 1; | 2313 free_header->lcheader.free = 1; |
2351 (obj)) | 2327 (obj)) |
2352 { | 2328 { |
2353 return obj; | 2329 return obj; |
2354 } | 2330 } |
2355 | 2331 |
2356 | |
2357 | 2332 |
2358 /************************************************************************/ | 2333 /************************************************************************/ |
2359 /* Garbage Collection */ | 2334 /* Garbage Collection */ |
2360 /************************************************************************/ | 2335 /************************************************************************/ |
2361 | 2336 |
2362 /* This will be used more extensively In The Future */ | 2337 /* All the built-in lisp object types are enumerated in `enum lrecord_type'. |
2363 static int last_lrecord_type_index_assigned; | 2338 Additional ones may be defined by a module (none yet). We leave some |
2364 | 2339 room in `lrecord_implementations_table' for such new lisp object types. */ |
2365 CONST struct lrecord_implementation *lrecord_implementations_table[128]; | 2340 const struct lrecord_implementation *lrecord_implementations_table[(unsigned int)lrecord_type_last_built_in_type + MODULE_DEFINABLE_TYPE_COUNT]; |
2366 #define max_lrecord_type (countof (lrecord_implementations_table) - 1) | 2341 unsigned int lrecord_type_count = (unsigned int)lrecord_type_last_built_in_type; |
2342 /* Object marker functions are in the lrecord_implementation structure. | |
2343 But copying them to a parallel array is much more cache-friendly. | |
2344 This hack speeds up (garbage-collect) by about 5%. */ | |
2345 Lisp_Object (*lrecord_markers[countof (lrecord_implementations_table)]) (Lisp_Object); | |
2367 | 2346 |
2368 struct gcpro *gcprolist; | 2347 struct gcpro *gcprolist; |
2369 | 2348 |
2370 /* 415 used Mly 29-Jun-93 */ | 2349 /* 415 used Mly 29-Jun-93 */ |
2371 /* 1327 used slb 28-Feb-98 */ | 2350 /* 1327 used slb 28-Feb-98 */ |
2373 #ifdef HAVE_SHLIB | 2352 #ifdef HAVE_SHLIB |
2374 #define NSTATICS 4000 | 2353 #define NSTATICS 4000 |
2375 #else | 2354 #else |
2376 #define NSTATICS 2000 | 2355 #define NSTATICS 2000 |
2377 #endif | 2356 #endif |
2378 /* Not "static" because of linker lossage on some systems */ | 2357 |
2379 Lisp_Object *staticvec[NSTATICS] | 2358 /* Not "static" because used by dumper.c */ |
2380 /* Force it into data space! */ | 2359 Lisp_Object *staticvec[NSTATICS]; |
2381 = {0}; | 2360 int staticidx; |
2382 static int staticidx; | |
2383 | 2361 |
2384 /* Put an entry in staticvec, pointing at the variable whose address is given | 2362 /* Put an entry in staticvec, pointing at the variable whose address is given |
2385 */ | 2363 */ |
2386 void | 2364 void |
2387 staticpro (Lisp_Object *varaddress) | 2365 staticpro (Lisp_Object *varaddress) |
2388 { | 2366 { |
2389 if (staticidx >= countof (staticvec)) | 2367 /* #### This is now a dubious assert() since this routine may be called */ |
2390 /* #### This is now a dubious abort() since this routine may be called */ | 2368 /* by Lisp attempting to load a DLL. */ |
2391 /* by Lisp attempting to load a DLL. */ | 2369 assert (staticidx < countof (staticvec)); |
2392 abort (); | |
2393 staticvec[staticidx++] = varaddress; | 2370 staticvec[staticidx++] = varaddress; |
2394 } | 2371 } |
2395 | 2372 |
2396 /* Not "static" because of linker lossage on some systems */ | 2373 |
2397 Lisp_Object *staticvec_nodump[200] | 2374 Lisp_Object *staticvec_nodump[200]; |
2398 /* Force it into data space! */ | 2375 int staticidx_nodump; |
2399 = {0}; | |
2400 static int staticidx_nodump; | |
2401 | 2376 |
2402 /* Put an entry in staticvec_nodump, pointing at the variable whose address is given | 2377 /* Put an entry in staticvec_nodump, pointing at the variable whose address is given |
2403 */ | 2378 */ |
2404 void | 2379 void |
2405 staticpro_nodump (Lisp_Object *varaddress) | 2380 staticpro_nodump (Lisp_Object *varaddress) |
2406 { | 2381 { |
2407 if (staticidx_nodump >= countof (staticvec_nodump)) | 2382 /* #### This is now a dubious assert() since this routine may be called */ |
2408 /* #### This is now a dubious abort() since this routine may be called */ | 2383 /* by Lisp attempting to load a DLL. */ |
2409 /* by Lisp attempting to load a DLL. */ | 2384 assert (staticidx_nodump < countof (staticvec_nodump)); |
2410 abort (); | |
2411 staticvec_nodump[staticidx_nodump++] = varaddress; | 2385 staticvec_nodump[staticidx_nodump++] = varaddress; |
2412 } | 2386 } |
2413 | 2387 |
2414 /* Not "static" because of linker lossage on some systems */ | 2388 |
2415 struct | 2389 struct pdump_dumpstructinfo dumpstructvec[200]; |
2416 { | 2390 int dumpstructidx; |
2417 void *data; | |
2418 const struct struct_description *desc; | |
2419 } dumpstructvec[200]; | |
2420 | |
2421 static int dumpstructidx; | |
2422 | 2391 |
2423 /* Put an entry in dumpstructvec, pointing at the variable whose address is given | 2392 /* Put an entry in dumpstructvec, pointing at the variable whose address is given |
2424 */ | 2393 */ |
2425 void | 2394 void |
2426 dumpstruct (void *varaddress, const struct struct_description *desc) | 2395 dumpstruct (void *varaddress, const struct struct_description *desc) |
2427 { | 2396 { |
2428 if (dumpstructidx >= countof (dumpstructvec)) | 2397 assert (dumpstructidx < countof (dumpstructvec)); |
2429 abort (); | |
2430 dumpstructvec[dumpstructidx].data = varaddress; | 2398 dumpstructvec[dumpstructidx].data = varaddress; |
2431 dumpstructvec[dumpstructidx].desc = desc; | 2399 dumpstructvec[dumpstructidx].desc = desc; |
2432 dumpstructidx++; | 2400 dumpstructidx++; |
2433 } | 2401 } |
2434 | 2402 |
2403 struct pdump_dumpopaqueinfo dumpopaquevec[250]; | |
2404 int dumpopaqueidx; | |
2405 | |
2406 /* Put an entry in dumpopaquevec, pointing at the variable whose address is given | |
2407 */ | |
2408 void | |
2409 dumpopaque (void *varaddress, size_t size) | |
2410 { | |
2411 assert (dumpopaqueidx < countof (dumpopaquevec)); | |
2412 | |
2413 dumpopaquevec[dumpopaqueidx].data = varaddress; | |
2414 dumpopaquevec[dumpopaqueidx].size = size; | |
2415 dumpopaqueidx++; | |
2416 } | |
2417 | |
2435 Lisp_Object *pdump_wirevec[50]; | 2418 Lisp_Object *pdump_wirevec[50]; |
2436 static int pdump_wireidx; | 2419 int pdump_wireidx; |
2437 | 2420 |
2438 /* Put an entry in pdump_wirevec, pointing at the variable whose address is given | 2421 /* Put an entry in pdump_wirevec, pointing at the variable whose address is given |
2439 */ | 2422 */ |
2440 void | 2423 void |
2441 pdump_wire (Lisp_Object *varaddress) | 2424 pdump_wire (Lisp_Object *varaddress) |
2442 { | 2425 { |
2443 if (pdump_wireidx >= countof (pdump_wirevec)) | 2426 assert (pdump_wireidx < countof (pdump_wirevec)); |
2444 abort (); | |
2445 pdump_wirevec[pdump_wireidx++] = varaddress; | 2427 pdump_wirevec[pdump_wireidx++] = varaddress; |
2446 } | 2428 } |
2447 | 2429 |
2448 | 2430 |
2449 Lisp_Object *pdump_wirevec_list[50]; | 2431 Lisp_Object *pdump_wirevec_list[50]; |
2450 static int pdump_wireidx_list; | 2432 int pdump_wireidx_list; |
2451 | 2433 |
2452 /* Put an entry in pdump_wirevec_list, pointing at the variable whose address is given | 2434 /* Put an entry in pdump_wirevec_list, pointing at the variable whose address is given |
2453 */ | 2435 */ |
2454 void | 2436 void |
2455 pdump_wire_list (Lisp_Object *varaddress) | 2437 pdump_wire_list (Lisp_Object *varaddress) |
2456 { | 2438 { |
2457 if (pdump_wireidx_list >= countof (pdump_wirevec_list)) | 2439 assert (pdump_wireidx_list < countof (pdump_wirevec_list)); |
2458 abort (); | |
2459 pdump_wirevec_list[pdump_wireidx_list++] = varaddress; | 2440 pdump_wirevec_list[pdump_wireidx_list++] = varaddress; |
2460 } | 2441 } |
2442 | |
2443 #ifdef ERROR_CHECK_GC | |
2444 #define GC_CHECK_LHEADER_INVARIANTS(lheader) do { \ | |
2445 struct lrecord_header * GCLI_lh = (lheader); \ | |
2446 assert (GCLI_lh != 0); \ | |
2447 assert (GCLI_lh->type < lrecord_type_count); \ | |
2448 assert (! C_READONLY_RECORD_HEADER_P (GCLI_lh) || \ | |
2449 (MARKED_RECORD_HEADER_P (GCLI_lh) && \ | |
2450 LISP_READONLY_RECORD_HEADER_P (GCLI_lh))); \ | |
2451 } while (0) | |
2452 #else | |
2453 #define GC_CHECK_LHEADER_INVARIANTS(lheader) | |
2454 #endif | |
2461 | 2455 |
2462 | 2456 |
2463 /* Mark reference to a Lisp_Object. If the object referred to has not been | 2457 /* Mark reference to a Lisp_Object. If the object referred to has not been |
2464 seen yet, recursively mark all the references contained in it. */ | 2458 seen yet, recursively mark all the references contained in it. */ |
2465 | 2459 |
2466 void | 2460 void |
2467 mark_object (Lisp_Object obj) | 2461 mark_object (Lisp_Object obj) |
2468 { | 2462 { |
2469 tail_recurse: | 2463 tail_recurse: |
2470 | 2464 |
2471 #ifdef ERROR_CHECK_GC | |
2472 assert (! (EQ (obj, Qnull_pointer))); | |
2473 #endif | |
2474 /* Checks we used to perform */ | 2465 /* Checks we used to perform */ |
2475 /* if (EQ (obj, Qnull_pointer)) return; */ | 2466 /* if (EQ (obj, Qnull_pointer)) return; */ |
2476 /* if (!POINTER_TYPE_P (XGCTYPE (obj))) return; */ | 2467 /* if (!POINTER_TYPE_P (XGCTYPE (obj))) return; */ |
2477 /* if (PURIFIED (XPNTR (obj))) return; */ | 2468 /* if (PURIFIED (XPNTR (obj))) return; */ |
2478 | 2469 |
2479 if (XTYPE (obj) == Lisp_Type_Record) | 2470 if (XTYPE (obj) == Lisp_Type_Record) |
2480 { | 2471 { |
2481 struct lrecord_header *lheader = XRECORD_LHEADER (obj); | 2472 struct lrecord_header *lheader = XRECORD_LHEADER (obj); |
2482 #if defined (ERROR_CHECK_GC) | 2473 |
2483 assert (lheader->type <= last_lrecord_type_index_assigned); | 2474 GC_CHECK_LHEADER_INVARIANTS (lheader); |
2484 #endif | 2475 |
2485 if (C_READONLY_RECORD_HEADER_P (lheader)) | 2476 gc_checking_assert (LHEADER_IMPLEMENTATION (lheader)->basic_p || |
2486 return; | 2477 ! ((struct lcrecord_header *) lheader)->free); |
2487 | 2478 |
2488 if (! MARKED_RECORD_HEADER_P (lheader) && | 2479 /* All c_readonly objects have their mark bit set, |
2489 ! UNMARKABLE_RECORD_HEADER_P (lheader)) | 2480 so that we only need to check the mark bit here. */ |
2481 if (! MARKED_RECORD_HEADER_P (lheader)) | |
2490 { | 2482 { |
2491 CONST struct lrecord_implementation *implementation = | |
2492 LHEADER_IMPLEMENTATION (lheader); | |
2493 MARK_RECORD_HEADER (lheader); | 2483 MARK_RECORD_HEADER (lheader); |
2494 #ifdef ERROR_CHECK_GC | 2484 |
2495 if (!implementation->basic_p) | 2485 if (RECORD_MARKER (lheader)) |
2496 assert (! ((struct lcrecord_header *) lheader)->free); | |
2497 #endif | |
2498 if (implementation->marker) | |
2499 { | 2486 { |
2500 obj = implementation->marker (obj); | 2487 obj = RECORD_MARKER (lheader) (obj); |
2501 if (!NILP (obj)) goto tail_recurse; | 2488 if (!NILP (obj)) goto tail_recurse; |
2502 } | 2489 } |
2503 } | 2490 } |
2504 } | 2491 } |
2505 } | 2492 } |
2535 static int gc_count_short_string_total_size; | 2522 static int gc_count_short_string_total_size; |
2536 | 2523 |
2537 /* static int gc_count_total_records_used, gc_count_records_total_size; */ | 2524 /* static int gc_count_total_records_used, gc_count_records_total_size; */ |
2538 | 2525 |
2539 | 2526 |
2540 int | |
2541 lrecord_type_index (CONST struct lrecord_implementation *implementation) | |
2542 { | |
2543 int type_index = *(implementation->lrecord_type_index); | |
2544 /* Have to do this circuitous validation test because of problems | |
2545 dumping out initialized variables (ie can't set xxx_type_index to -1 | |
2546 because that would make xxx_type_index read-only in a dumped emacs. */ | |
2547 if (type_index < 0 || type_index > max_lrecord_type | |
2548 || lrecord_implementations_table[type_index] != implementation) | |
2549 { | |
2550 assert (last_lrecord_type_index_assigned < max_lrecord_type); | |
2551 type_index = ++last_lrecord_type_index_assigned; | |
2552 lrecord_implementations_table[type_index] = implementation; | |
2553 *(implementation->lrecord_type_index) = type_index; | |
2554 } | |
2555 return type_index; | |
2556 } | |
2557 | |
2558 /* stats on lcrecords in use - kinda kludgy */ | 2527 /* stats on lcrecords in use - kinda kludgy */ |
2559 | 2528 |
2560 static struct | 2529 static struct |
2561 { | 2530 { |
2562 int instances_in_use; | 2531 int instances_in_use; |
2565 int bytes_freed; | 2534 int bytes_freed; |
2566 int instances_on_free_list; | 2535 int instances_on_free_list; |
2567 } lcrecord_stats [countof (lrecord_implementations_table)]; | 2536 } lcrecord_stats [countof (lrecord_implementations_table)]; |
2568 | 2537 |
2569 static void | 2538 static void |
2570 tick_lcrecord_stats (CONST struct lrecord_header *h, int free_p) | 2539 tick_lcrecord_stats (const struct lrecord_header *h, int free_p) |
2571 { | 2540 { |
2572 CONST struct lrecord_implementation *implementation = | 2541 unsigned int type_index = h->type; |
2573 LHEADER_IMPLEMENTATION (h); | |
2574 int type_index = lrecord_type_index (implementation); | |
2575 | 2542 |
2576 if (((struct lcrecord_header *) h)->free) | 2543 if (((struct lcrecord_header *) h)->free) |
2577 { | 2544 { |
2578 assert (!free_p); | 2545 gc_checking_assert (!free_p); |
2579 lcrecord_stats[type_index].instances_on_free_list++; | 2546 lcrecord_stats[type_index].instances_on_free_list++; |
2580 } | 2547 } |
2581 else | 2548 else |
2582 { | 2549 { |
2583 size_t sz = (implementation->size_in_bytes_method | 2550 const struct lrecord_implementation *implementation = |
2584 ? implementation->size_in_bytes_method (h) | 2551 LHEADER_IMPLEMENTATION (h); |
2585 : implementation->static_size); | 2552 |
2586 | 2553 size_t sz = (implementation->size_in_bytes_method ? |
2554 implementation->size_in_bytes_method (h) : | |
2555 implementation->static_size); | |
2587 if (free_p) | 2556 if (free_p) |
2588 { | 2557 { |
2589 lcrecord_stats[type_index].instances_freed++; | 2558 lcrecord_stats[type_index].instances_freed++; |
2590 lcrecord_stats[type_index].bytes_freed += sz; | 2559 lcrecord_stats[type_index].bytes_freed += sz; |
2591 } | 2560 } |
2619 other object. */ | 2588 other object. */ |
2620 | 2589 |
2621 for (header = *prev; header; header = header->next) | 2590 for (header = *prev; header; header = header->next) |
2622 { | 2591 { |
2623 struct lrecord_header *h = &(header->lheader); | 2592 struct lrecord_header *h = &(header->lheader); |
2624 if (!C_READONLY_RECORD_HEADER_P(h) | 2593 |
2625 && !MARKED_RECORD_HEADER_P (h) | 2594 GC_CHECK_LHEADER_INVARIANTS (h); |
2626 && ! (header->free)) | 2595 |
2596 if (! MARKED_RECORD_HEADER_P (h) && ! header->free) | |
2627 { | 2597 { |
2628 if (LHEADER_IMPLEMENTATION (h)->finalizer) | 2598 if (LHEADER_IMPLEMENTATION (h)->finalizer) |
2629 LHEADER_IMPLEMENTATION (h)->finalizer (h, 0); | 2599 LHEADER_IMPLEMENTATION (h)->finalizer (h, 0); |
2630 } | 2600 } |
2631 } | 2601 } |
2632 | 2602 |
2633 for (header = *prev; header; ) | 2603 for (header = *prev; header; ) |
2634 { | 2604 { |
2635 struct lrecord_header *h = &(header->lheader); | 2605 struct lrecord_header *h = &(header->lheader); |
2636 if (C_READONLY_RECORD_HEADER_P(h) || MARKED_RECORD_HEADER_P (h)) | 2606 if (MARKED_RECORD_HEADER_P (h)) |
2637 { | 2607 { |
2638 if (MARKED_RECORD_HEADER_P (h)) | 2608 if (! C_READONLY_RECORD_HEADER_P (h)) |
2639 UNMARK_RECORD_HEADER (h); | 2609 UNMARK_RECORD_HEADER (h); |
2640 num_used++; | 2610 num_used++; |
2641 /* total_size += n->implementation->size_in_bytes (h);*/ | 2611 /* total_size += n->implementation->size_in_bytes (h);*/ |
2642 /* #### May modify header->next on a C_READONLY lcrecord */ | 2612 /* #### May modify header->next on a C_READONLY lcrecord */ |
2643 prev = &(header->next); | 2613 prev = &(header->next); |
2672 their implementation */ | 2642 their implementation */ |
2673 for (bit_vector = *prev; !EQ (bit_vector, Qzero); ) | 2643 for (bit_vector = *prev; !EQ (bit_vector, Qzero); ) |
2674 { | 2644 { |
2675 Lisp_Bit_Vector *v = XBIT_VECTOR (bit_vector); | 2645 Lisp_Bit_Vector *v = XBIT_VECTOR (bit_vector); |
2676 int len = v->size; | 2646 int len = v->size; |
2677 if (C_READONLY_RECORD_HEADER_P(&(v->lheader)) || MARKED_RECORD_P (bit_vector)) | 2647 if (MARKED_RECORD_P (bit_vector)) |
2678 { | 2648 { |
2679 if (MARKED_RECORD_P (bit_vector)) | 2649 if (! C_READONLY_RECORD_HEADER_P(&(v->lheader))) |
2680 UNMARK_RECORD_HEADER (&(v->lheader)); | 2650 UNMARK_RECORD_HEADER (&(v->lheader)); |
2681 total_size += len; | 2651 total_size += len; |
2682 total_storage += | 2652 total_storage += |
2683 MALLOC_OVERHEAD + | 2653 MALLOC_OVERHEAD + |
2684 STRETCHY_STRUCT_SIZEOF (Lisp_Bit_Vector, bits, | 2654 FLEXIBLE_ARRAY_STRUCT_SIZEOF (Lisp_Bit_Vector, bits, |
2685 BIT_VECTOR_LONG_STORAGE (len)); | 2655 BIT_VECTOR_LONG_STORAGE (len)); |
2686 num_used++; | 2656 num_used++; |
2687 /* #### May modify next on a C_READONLY bitvector */ | 2657 /* #### May modify next on a C_READONLY bitvector */ |
2688 prev = &(bit_vector_next (v)); | 2658 prev = &(bit_vector_next (v)); |
2689 bit_vector = *prev; | 2659 bit_vector = *prev; |
2690 } | 2660 } |
2731 } \ | 2701 } \ |
2732 else if (C_READONLY_RECORD_HEADER_P (&SFTB_victim->lheader)) \ | 2702 else if (C_READONLY_RECORD_HEADER_P (&SFTB_victim->lheader)) \ |
2733 { \ | 2703 { \ |
2734 num_used++; \ | 2704 num_used++; \ |
2735 } \ | 2705 } \ |
2736 else if (!MARKED_RECORD_HEADER_P (&SFTB_victim->lheader)) \ | 2706 else if (! MARKED_RECORD_HEADER_P (&SFTB_victim->lheader)) \ |
2737 { \ | 2707 { \ |
2738 num_free++; \ | 2708 num_free++; \ |
2739 FREE_FIXED_TYPE (typename, obj_type, SFTB_victim); \ | 2709 FREE_FIXED_TYPE (typename, obj_type, SFTB_victim); \ |
2740 } \ | 2710 } \ |
2741 else \ | 2711 else \ |
2786 else if (C_READONLY_RECORD_HEADER_P (&SFTB_victim->lheader)) \ | 2756 else if (C_READONLY_RECORD_HEADER_P (&SFTB_victim->lheader)) \ |
2787 { \ | 2757 { \ |
2788 SFTB_empty = 0; \ | 2758 SFTB_empty = 0; \ |
2789 num_used++; \ | 2759 num_used++; \ |
2790 } \ | 2760 } \ |
2791 else if (!MARKED_RECORD_HEADER_P (&SFTB_victim->lheader)) \ | 2761 else if (! MARKED_RECORD_HEADER_P (&SFTB_victim->lheader)) \ |
2792 { \ | 2762 { \ |
2793 num_free++; \ | 2763 num_free++; \ |
2794 FREE_FIXED_TYPE (typename, obj_type, SFTB_victim); \ | 2764 FREE_FIXED_TYPE (typename, obj_type, SFTB_victim); \ |
2795 } \ | 2765 } \ |
2796 else \ | 2766 else \ |
2965 | 2935 |
2966 /* Explicitly free a marker. */ | 2936 /* Explicitly free a marker. */ |
2967 void | 2937 void |
2968 free_marker (Lisp_Marker *ptr) | 2938 free_marker (Lisp_Marker *ptr) |
2969 { | 2939 { |
2970 #ifdef ERROR_CHECK_GC | |
2971 /* Perhaps this will catch freeing an already-freed marker. */ | 2940 /* Perhaps this will catch freeing an already-freed marker. */ |
2972 Lisp_Object temmy; | 2941 gc_checking_assert (ptr->lheader.type = lrecord_type_marker); |
2973 XSETMARKER (temmy, ptr); | |
2974 assert (MARKERP (temmy)); | |
2975 #endif /* ERROR_CHECK_GC */ | |
2976 | 2942 |
2977 #ifndef ALLOC_NO_POOLS | 2943 #ifndef ALLOC_NO_POOLS |
2978 FREE_FIXED_TYPE_WHEN_NOT_IN_GC (marker, Lisp_Marker, ptr); | 2944 FREE_FIXED_TYPE_WHEN_NOT_IN_GC (marker, Lisp_Marker, ptr); |
2979 #endif /* ALLOC_NO_POOLS */ | 2945 #endif /* ALLOC_NO_POOLS */ |
2980 } | 2946 } |
3071 assert (!(FREE_STRUCT_P (string))); | 3037 assert (!(FREE_STRUCT_P (string))); |
3072 | 3038 |
3073 size = string_length (string); | 3039 size = string_length (string); |
3074 fullsize = STRING_FULLSIZE (size); | 3040 fullsize = STRING_FULLSIZE (size); |
3075 | 3041 |
3076 if (BIG_STRING_FULLSIZE_P (fullsize)) | 3042 gc_checking_assert (! BIG_STRING_FULLSIZE_P (fullsize)); |
3077 abort (); | |
3078 | 3043 |
3079 /* Just skip it if it isn't marked. */ | 3044 /* Just skip it if it isn't marked. */ |
3080 if (! MARKED_RECORD_HEADER_P (&(string->lheader))) | 3045 if (! MARKED_RECORD_HEADER_P (&(string->lheader))) |
3081 { | 3046 { |
3082 from_pos += fullsize; | 3047 from_pos += fullsize; |
3134 static void | 3099 static void |
3135 debug_string_purity_print (Lisp_String *p) | 3100 debug_string_purity_print (Lisp_String *p) |
3136 { | 3101 { |
3137 Charcount i; | 3102 Charcount i; |
3138 Charcount s = string_char_length (p); | 3103 Charcount s = string_char_length (p); |
3139 putc ('\"', stderr); | 3104 stderr_out ("\""); |
3140 for (i = 0; i < s; i++) | 3105 for (i = 0; i < s; i++) |
3141 { | 3106 { |
3142 Emchar ch = string_char (p, i); | 3107 Emchar ch = string_char (p, i); |
3143 if (ch < 32 || ch >= 126) | 3108 if (ch < 32 || ch >= 126) |
3144 stderr_out ("\\%03o", ch); | 3109 stderr_out ("\\%03o", ch); |
3162 Lisp_String *p = (ptr); \ | 3127 Lisp_String *p = (ptr); \ |
3163 size_t size = string_length (p); \ | 3128 size_t size = string_length (p); \ |
3164 UNMARK_RECORD_HEADER (&(p->lheader)); \ | 3129 UNMARK_RECORD_HEADER (&(p->lheader)); \ |
3165 num_bytes += size; \ | 3130 num_bytes += size; \ |
3166 if (!BIG_STRING_SIZE_P (size)) \ | 3131 if (!BIG_STRING_SIZE_P (size)) \ |
3167 { num_small_bytes += size; \ | 3132 { \ |
3168 num_small_used++; \ | 3133 num_small_bytes += size; \ |
3134 num_small_used++; \ | |
3169 } \ | 3135 } \ |
3170 if (debug) \ | 3136 if (debug) \ |
3171 debug_string_purity_print (p); \ | 3137 debug_string_purity_print (p); \ |
3172 } while (0) | 3138 } while (0) |
3173 #define ADDITIONAL_FREE_string(ptr) do { \ | 3139 #define ADDITIONAL_FREE_string(ptr) do { \ |
3186 | 3152 |
3187 /* I hate duplicating all this crap! */ | 3153 /* I hate duplicating all this crap! */ |
3188 int | 3154 int |
3189 marked_p (Lisp_Object obj) | 3155 marked_p (Lisp_Object obj) |
3190 { | 3156 { |
3191 #ifdef ERROR_CHECK_GC | |
3192 assert (! (EQ (obj, Qnull_pointer))); | |
3193 #endif | |
3194 /* Checks we used to perform. */ | 3157 /* Checks we used to perform. */ |
3195 /* if (EQ (obj, Qnull_pointer)) return 1; */ | 3158 /* if (EQ (obj, Qnull_pointer)) return 1; */ |
3196 /* if (!POINTER_TYPE_P (XGCTYPE (obj))) return 1; */ | 3159 /* if (!POINTER_TYPE_P (XGCTYPE (obj))) return 1; */ |
3197 /* if (PURIFIED (XPNTR (obj))) return 1; */ | 3160 /* if (PURIFIED (XPNTR (obj))) return 1; */ |
3198 | 3161 |
3199 if (XTYPE (obj) == Lisp_Type_Record) | 3162 if (XTYPE (obj) == Lisp_Type_Record) |
3200 { | 3163 { |
3201 struct lrecord_header *lheader = XRECORD_LHEADER (obj); | 3164 struct lrecord_header *lheader = XRECORD_LHEADER (obj); |
3202 #if defined (ERROR_CHECK_GC) | 3165 |
3203 assert (lheader->type <= last_lrecord_type_index_assigned); | 3166 GC_CHECK_LHEADER_INVARIANTS (lheader); |
3204 #endif | 3167 |
3205 return C_READONLY_RECORD_HEADER_P (lheader) || MARKED_RECORD_HEADER_P (lheader); | 3168 return MARKED_RECORD_HEADER_P (lheader); |
3206 } | 3169 } |
3207 return 1; | 3170 return 1; |
3208 } | 3171 } |
3209 | 3172 |
3210 static void | 3173 static void |
3265 sweep_markers (); | 3228 sweep_markers (); |
3266 | 3229 |
3267 sweep_events (); | 3230 sweep_events (); |
3268 | 3231 |
3269 #ifdef PDUMP | 3232 #ifdef PDUMP |
3270 /* Unmark all dumped objects */ | 3233 pdump_objects_unmark (); |
3271 { | |
3272 int i; | |
3273 char *p = pdump_rt_list; | |
3274 if (p) | |
3275 for (;;) | |
3276 { | |
3277 pdump_reloc_table *rt = (pdump_reloc_table *)p; | |
3278 p += sizeof (pdump_reloc_table); | |
3279 if (rt->desc) | |
3280 { | |
3281 for (i=0; i<rt->count; i++) | |
3282 { | |
3283 UNMARK_RECORD_HEADER ((struct lrecord_header *)(*(EMACS_INT *)p)); | |
3284 p += sizeof (EMACS_INT); | |
3285 } | |
3286 } else | |
3287 break; | |
3288 } | |
3289 } | |
3290 #endif | 3234 #endif |
3291 } | 3235 } |
3292 | 3236 |
3293 /* Clearing for disksave. */ | 3237 /* Clearing for disksave. */ |
3294 | 3238 |
3437 char *msg = (STRINGP (Vgc_message) | 3381 char *msg = (STRINGP (Vgc_message) |
3438 ? GETTEXT ((char *) XSTRING_DATA (Vgc_message)) | 3382 ? GETTEXT ((char *) XSTRING_DATA (Vgc_message)) |
3439 : 0); | 3383 : 0); |
3440 Lisp_Object args[2], whole_msg; | 3384 Lisp_Object args[2], whole_msg; |
3441 args[0] = build_string (msg ? msg : | 3385 args[0] = build_string (msg ? msg : |
3442 GETTEXT ((CONST char *) gc_default_message)); | 3386 GETTEXT ((const char *) gc_default_message)); |
3443 args[1] = build_string ("..."); | 3387 args[1] = build_string ("..."); |
3444 whole_msg = Fconcat (2, args); | 3388 whole_msg = Fconcat (2, args); |
3445 echo_area_message (f, (Bufbyte *) 0, whole_msg, 0, -1, | 3389 echo_area_message (f, (Bufbyte *) 0, whole_msg, 0, -1, |
3446 Qgarbage_collecting); | 3390 Qgarbage_collecting); |
3447 } | 3391 } |
3589 if (NILP (clear_echo_area (selected_frame (), | 3533 if (NILP (clear_echo_area (selected_frame (), |
3590 Qgarbage_collecting, 0))) | 3534 Qgarbage_collecting, 0))) |
3591 { | 3535 { |
3592 Lisp_Object args[2], whole_msg; | 3536 Lisp_Object args[2], whole_msg; |
3593 args[0] = build_string (msg ? msg : | 3537 args[0] = build_string (msg ? msg : |
3594 GETTEXT ((CONST char *) | 3538 GETTEXT ((const char *) |
3595 gc_default_message)); | 3539 gc_default_message)); |
3596 args[1] = build_string ("... done"); | 3540 args[1] = build_string ("... done"); |
3597 whole_msg = Fconcat (2, args); | 3541 whole_msg = Fconcat (2, args); |
3598 echo_area_message (selected_frame (), (Bufbyte *) 0, | 3542 echo_area_message (selected_frame (), (Bufbyte *) 0, |
3599 whole_msg, 0, -1, | 3543 whole_msg, 0, -1, |
3615 } | 3559 } |
3616 | 3560 |
3617 /* Debugging aids. */ | 3561 /* Debugging aids. */ |
3618 | 3562 |
3619 static Lisp_Object | 3563 static Lisp_Object |
3620 gc_plist_hack (CONST char *name, int value, Lisp_Object tail) | 3564 gc_plist_hack (const char *name, int value, Lisp_Object tail) |
3621 { | 3565 { |
3622 /* C doesn't have local functions (or closures, or GC, or readable syntax, | 3566 /* C doesn't have local functions (or closures, or GC, or readable syntax, |
3623 or portable numeric datatypes, or bit-vectors, or characters, or | 3567 or portable numeric datatypes, or bit-vectors, or characters, or |
3624 arrays, or exceptions, or ...) */ | 3568 arrays, or exceptions, or ...) */ |
3625 return cons3 (intern (name), make_int (value), tail); | 3569 return cons3 (intern (name), make_int (value), tail); |
3649 int i; | 3593 int i; |
3650 int gc_count_vector_total_size = 0; | 3594 int gc_count_vector_total_size = 0; |
3651 | 3595 |
3652 garbage_collect_1 (); | 3596 garbage_collect_1 (); |
3653 | 3597 |
3654 for (i = 0; i <= last_lrecord_type_index_assigned; i++) | 3598 for (i = 0; i < lrecord_type_count; i++) |
3655 { | 3599 { |
3656 if (lcrecord_stats[i].bytes_in_use != 0 | 3600 if (lcrecord_stats[i].bytes_in_use != 0 |
3657 || lcrecord_stats[i].bytes_freed != 0 | 3601 || lcrecord_stats[i].bytes_freed != 0 |
3658 || lcrecord_stats[i].instances_on_free_list != 0) | 3602 || lcrecord_stats[i].instances_on_free_list != 0) |
3659 { | 3603 { |
3660 char buf [255]; | 3604 char buf [255]; |
3661 CONST char *name = lrecord_implementations_table[i]->name; | 3605 const char *name = lrecord_implementations_table[i]->name; |
3662 int len = strlen (name); | 3606 int len = strlen (name); |
3663 /* save this for the FSFmacs-compatible part of the summary */ | 3607 /* save this for the FSFmacs-compatible part of the summary */ |
3664 if (i == *lrecord_vector.lrecord_type_index) | 3608 if (i == lrecord_vector.lrecord_type_index) |
3665 gc_count_vector_total_size = | 3609 gc_count_vector_total_size = |
3666 lcrecord_stats[i].bytes_in_use + lcrecord_stats[i].bytes_freed; | 3610 lcrecord_stats[i].bytes_in_use + lcrecord_stats[i].bytes_freed; |
3667 | 3611 |
3668 sprintf (buf, "%s-storage", name); | 3612 sprintf (buf, "%s-storage", name); |
3669 pl = gc_plist_hack (buf, lcrecord_stats[i].bytes_in_use, pl); | 3613 pl = gc_plist_hack (buf, lcrecord_stats[i].bytes_in_use, pl); |
3963 #if 1 | 3907 #if 1 |
3964 gc_cons_threshold = 500000; /* XEmacs change */ | 3908 gc_cons_threshold = 500000; /* XEmacs change */ |
3965 #else | 3909 #else |
3966 gc_cons_threshold = 15000; /* debugging */ | 3910 gc_cons_threshold = 15000; /* debugging */ |
3967 #endif | 3911 #endif |
3968 #ifdef VIRT_ADDR_VARIES | |
3969 malloc_sbrk_unused = 1<<22; /* A large number */ | |
3970 malloc_sbrk_used = 100000; /* as reasonable as any number */ | |
3971 #endif /* VIRT_ADDR_VARIES */ | |
3972 lrecord_uid_counter = 259; | 3912 lrecord_uid_counter = 259; |
3973 debug_string_purity = 0; | 3913 debug_string_purity = 0; |
3974 gcprolist = 0; | 3914 gcprolist = 0; |
3975 | 3915 |
3976 gc_currently_forbidden = 0; | 3916 gc_currently_forbidden = 0; |
3988 } | 3928 } |
3989 | 3929 |
3990 void | 3930 void |
3991 init_alloc_once_early (void) | 3931 init_alloc_once_early (void) |
3992 { | 3932 { |
3993 int iii; | |
3994 | |
3995 reinit_alloc_once_early (); | 3933 reinit_alloc_once_early (); |
3996 | 3934 |
3997 last_lrecord_type_index_assigned = -1; | 3935 { |
3998 for (iii = 0; iii < countof (lrecord_implementations_table); iii++) | 3936 int i; |
3999 { | 3937 for (i = 0; i < countof (lrecord_implementations_table); i++) |
4000 lrecord_implementations_table[iii] = 0; | 3938 lrecord_implementations_table[i] = 0; |
4001 } | 3939 } |
4002 | 3940 |
4003 /* | 3941 INIT_LRECORD_IMPLEMENTATION (cons); |
4004 * All the staticly | 3942 INIT_LRECORD_IMPLEMENTATION (vector); |
4005 * defined subr lrecords were initialized with lheader->type == 0. | 3943 INIT_LRECORD_IMPLEMENTATION (string); |
4006 * See subr_lheader_initializer in lisp.h. Force type index 0 to be | 3944 INIT_LRECORD_IMPLEMENTATION (lcrecord_list); |
4007 * assigned to lrecord_subr so that those predefined indexes match | |
4008 * reality. | |
4009 */ | |
4010 lrecord_type_index (&lrecord_subr); | |
4011 assert (*(lrecord_subr.lrecord_type_index) == 0); | |
4012 /* | |
4013 * The same is true for symbol_value_forward objects, except the | |
4014 * type is 1. | |
4015 */ | |
4016 lrecord_type_index (&lrecord_symbol_value_forward); | |
4017 assert (*(lrecord_symbol_value_forward.lrecord_type_index) == 1); | |
4018 | 3945 |
4019 staticidx = 0; | 3946 staticidx = 0; |
4020 } | 3947 } |
4021 | 3948 |
4022 int pure_bytes_used = 0; | 3949 int pure_bytes_used = 0; |
4028 } | 3955 } |
4029 | 3956 |
4030 void | 3957 void |
4031 syms_of_alloc (void) | 3958 syms_of_alloc (void) |
4032 { | 3959 { |
4033 defsymbol (&Qpre_gc_hook, "pre-gc-hook"); | 3960 DEFSYMBOL (Qpre_gc_hook); |
4034 defsymbol (&Qpost_gc_hook, "post-gc-hook"); | 3961 DEFSYMBOL (Qpost_gc_hook); |
4035 defsymbol (&Qgarbage_collecting, "garbage-collecting"); | 3962 DEFSYMBOL (Qgarbage_collecting); |
4036 | 3963 |
4037 DEFSUBR (Fcons); | 3964 DEFSUBR (Fcons); |
4038 DEFSUBR (Flist); | 3965 DEFSUBR (Flist); |
4039 DEFSUBR (Fvector); | 3966 DEFSUBR (Fvector); |
4040 DEFSUBR (Fbit_vector); | 3967 DEFSUBR (Fbit_vector); |
4074 | 4001 |
4075 DEFVAR_INT ("pure-bytes-used", &pure_bytes_used /* | 4002 DEFVAR_INT ("pure-bytes-used", &pure_bytes_used /* |
4076 Number of bytes of sharable Lisp data allocated so far. | 4003 Number of bytes of sharable Lisp data allocated so far. |
4077 */ ); | 4004 */ ); |
4078 | 4005 |
4079 #if 0 | |
4080 DEFVAR_INT ("data-bytes-used", &malloc_sbrk_used /* | |
4081 Number of bytes of unshared memory allocated in this session. | |
4082 */ ); | |
4083 | |
4084 DEFVAR_INT ("data-bytes-free", &malloc_sbrk_unused /* | |
4085 Number of bytes of unshared memory remaining available in this session. | |
4086 */ ); | |
4087 #endif | |
4088 | |
4089 #ifdef DEBUG_XEMACS | 4006 #ifdef DEBUG_XEMACS |
4090 DEFVAR_INT ("debug-allocation", &debug_allocation /* | 4007 DEFVAR_INT ("debug-allocation", &debug_allocation /* |
4091 If non-zero, print out information to stderr about all objects allocated. | 4008 If non-zero, print out information to stderr about all objects allocated. |
4092 See also `debug-allocation-backtrace-length'. | 4009 See also `debug-allocation-backtrace-length'. |
4093 */ ); | 4010 */ ); |
4143 void | 4060 void |
4144 complex_vars_of_alloc (void) | 4061 complex_vars_of_alloc (void) |
4145 { | 4062 { |
4146 Vgc_pointer_glyph = Fmake_glyph_internal (Qpointer); | 4063 Vgc_pointer_glyph = Fmake_glyph_internal (Qpointer); |
4147 } | 4064 } |
4148 | |
4149 | |
4150 #ifdef PDUMP | |
4151 | |
4152 /* The structure of the file | |
4153 * | |
4154 * 0 - header | |
4155 * 256 - dumped objects | |
4156 * stab_offset - nb_staticpro*(Lisp_Object *) from staticvec | |
4157 * - nb_staticpro*(relocated Lisp_Object) pointed to by staticpro | |
4158 * - nb_structdmp*pair(void *, adr) for pointers to structures | |
4159 * - lrecord_implementations_table[] | |
4160 * - relocation table | |
4161 * - wired variable address/value couples with the count preceding the list | |
4162 */ | |
4163 typedef struct | |
4164 { | |
4165 char signature[8]; | |
4166 EMACS_UINT stab_offset; | |
4167 EMACS_UINT reloc_address; | |
4168 int nb_staticpro; | |
4169 int nb_structdmp; | |
4170 int last_type; | |
4171 } dump_header; | |
4172 | |
4173 char *pdump_start, *pdump_end; | |
4174 | |
4175 static const unsigned char align_table[256] = | |
4176 { | |
4177 8, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
4178 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
4179 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
4180 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
4181 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
4182 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
4183 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
4184 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
4185 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
4186 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
4187 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
4188 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
4189 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
4190 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
4191 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
4192 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 | |
4193 }; | |
4194 | |
4195 typedef struct pdump_entry_list_elmt | |
4196 { | |
4197 struct pdump_entry_list_elmt *next; | |
4198 const void *obj; | |
4199 size_t size; | |
4200 int count; | |
4201 int is_lrecord; | |
4202 EMACS_INT save_offset; | |
4203 } pdump_entry_list_elmt; | |
4204 | |
4205 typedef struct | |
4206 { | |
4207 pdump_entry_list_elmt *first; | |
4208 int align; | |
4209 int count; | |
4210 } pdump_entry_list; | |
4211 | |
4212 typedef struct pdump_struct_list_elmt | |
4213 { | |
4214 pdump_entry_list list; | |
4215 const struct struct_description *sdesc; | |
4216 } pdump_struct_list_elmt; | |
4217 | |
4218 typedef struct | |
4219 { | |
4220 pdump_struct_list_elmt *list; | |
4221 int count; | |
4222 int size; | |
4223 } pdump_struct_list; | |
4224 | |
4225 static pdump_entry_list pdump_object_table[256]; | |
4226 static pdump_entry_list pdump_opaque_data_list; | |
4227 static pdump_struct_list pdump_struct_table; | |
4228 static pdump_entry_list_elmt *pdump_qnil; | |
4229 | |
4230 static int pdump_alert_undump_object[256]; | |
4231 | |
4232 static unsigned long cur_offset; | |
4233 static size_t max_size; | |
4234 static int pdump_fd; | |
4235 static void *pdump_buf; | |
4236 | |
4237 #define PDUMP_HASHSIZE 200001 | |
4238 | |
4239 static pdump_entry_list_elmt **pdump_hash; | |
4240 | |
4241 /* Since most pointers are eight bytes aligned, the >>3 allows for a better hash */ | |
4242 static int | |
4243 pdump_make_hash (const void *obj) | |
4244 { | |
4245 return ((unsigned long)(obj)>>3) % PDUMP_HASHSIZE; | |
4246 } | |
4247 | |
4248 static pdump_entry_list_elmt * | |
4249 pdump_get_entry (const void *obj) | |
4250 { | |
4251 int pos = pdump_make_hash (obj); | |
4252 pdump_entry_list_elmt *e; | |
4253 | |
4254 assert (obj != 0); | |
4255 | |
4256 while ((e = pdump_hash[pos]) != 0) | |
4257 { | |
4258 if (e->obj == obj) | |
4259 return e; | |
4260 | |
4261 pos++; | |
4262 if (pos == PDUMP_HASHSIZE) | |
4263 pos = 0; | |
4264 } | |
4265 return 0; | |
4266 } | |
4267 | |
4268 static void | |
4269 pdump_add_entry (pdump_entry_list *list, const void *obj, size_t size, int count, int is_lrecord) | |
4270 { | |
4271 pdump_entry_list_elmt *e; | |
4272 int align; | |
4273 int pos = pdump_make_hash (obj); | |
4274 | |
4275 while ((e = pdump_hash[pos]) != 0) | |
4276 { | |
4277 if (e->obj == obj) | |
4278 return; | |
4279 | |
4280 pos++; | |
4281 if (pos == PDUMP_HASHSIZE) | |
4282 pos = 0; | |
4283 } | |
4284 | |
4285 e = xnew (pdump_entry_list_elmt); | |
4286 | |
4287 e->next = list->first; | |
4288 e->obj = obj; | |
4289 e->size = size; | |
4290 e->count = count; | |
4291 e->is_lrecord = is_lrecord; | |
4292 list->first = e; | |
4293 | |
4294 list->count += count; | |
4295 pdump_hash[pos] = e; | |
4296 | |
4297 align = align_table[size & 255]; | |
4298 if (align < 2 && is_lrecord) | |
4299 align = 2; | |
4300 | |
4301 if (align < list->align) | |
4302 list->align = align; | |
4303 } | |
4304 | |
4305 static pdump_entry_list * | |
4306 pdump_get_entry_list (const struct struct_description *sdesc) | |
4307 { | |
4308 int i; | |
4309 for (i=0; i<pdump_struct_table.count; i++) | |
4310 if (pdump_struct_table.list[i].sdesc == sdesc) | |
4311 return &pdump_struct_table.list[i].list; | |
4312 | |
4313 if (pdump_struct_table.size <= pdump_struct_table.count) | |
4314 { | |
4315 if (pdump_struct_table.size == -1) | |
4316 pdump_struct_table.size = 10; | |
4317 else | |
4318 pdump_struct_table.size = pdump_struct_table.size * 2; | |
4319 pdump_struct_table.list = (pdump_struct_list_elmt *) | |
4320 xrealloc (pdump_struct_table.list, | |
4321 pdump_struct_table.size * sizeof (pdump_struct_list_elmt)); | |
4322 } | |
4323 pdump_struct_table.list[pdump_struct_table.count].list.first = 0; | |
4324 pdump_struct_table.list[pdump_struct_table.count].list.align = 8; | |
4325 pdump_struct_table.list[pdump_struct_table.count].list.count = 0; | |
4326 pdump_struct_table.list[pdump_struct_table.count].sdesc = sdesc; | |
4327 | |
4328 return &pdump_struct_table.list[pdump_struct_table.count++].list; | |
4329 } | |
4330 | |
4331 static struct | |
4332 { | |
4333 struct lrecord_header *obj; | |
4334 int position; | |
4335 int offset; | |
4336 } backtrace[65536]; | |
4337 | |
4338 static int depth; | |
4339 | |
4340 static void pdump_backtrace (void) | |
4341 { | |
4342 int i; | |
4343 fprintf (stderr, "pdump backtrace :\n"); | |
4344 for (i=0;i<depth;i++) | |
4345 { | |
4346 if (!backtrace[i].obj) | |
4347 fprintf (stderr, " - ind. (%d, %d)\n", backtrace[i].position, backtrace[i].offset); | |
4348 else | |
4349 { | |
4350 fprintf (stderr, " - %s (%d, %d)\n", | |
4351 LHEADER_IMPLEMENTATION (backtrace[i].obj)->name, | |
4352 backtrace[i].position, | |
4353 backtrace[i].offset); | |
4354 } | |
4355 } | |
4356 } | |
4357 | |
4358 static void pdump_register_object (Lisp_Object obj); | |
4359 static void pdump_register_struct (const void *data, const struct struct_description *sdesc, int count); | |
4360 | |
4361 static EMACS_INT | |
4362 pdump_get_indirect_count (EMACS_INT code, const struct lrecord_description *idesc, const void *idata) | |
4363 { | |
4364 EMACS_INT count; | |
4365 const void *irdata; | |
4366 | |
4367 int line = XD_INDIRECT_VAL (code); | |
4368 int delta = XD_INDIRECT_DELTA (code); | |
4369 | |
4370 irdata = ((char *)idata) + idesc[line].offset; | |
4371 switch (idesc[line].type) | |
4372 { | |
4373 case XD_SIZE_T: | |
4374 count = *(size_t *)irdata; | |
4375 break; | |
4376 case XD_INT: | |
4377 count = *(int *)irdata; | |
4378 break; | |
4379 case XD_LONG: | |
4380 count = *(long *)irdata; | |
4381 break; | |
4382 case XD_BYTECOUNT: | |
4383 count = *(Bytecount *)irdata; | |
4384 break; | |
4385 default: | |
4386 fprintf (stderr, "Unsupported count type : %d (line = %d, code=%ld)\n", idesc[line].type, line, (long)code); | |
4387 pdump_backtrace (); | |
4388 abort (); | |
4389 } | |
4390 count += delta; | |
4391 return count; | |
4392 } | |
4393 | |
4394 static void | |
4395 pdump_register_sub (const void *data, const struct lrecord_description *desc, int me) | |
4396 { | |
4397 int pos; | |
4398 | |
4399 restart: | |
4400 for (pos = 0; desc[pos].type != XD_END; pos++) | |
4401 { | |
4402 const void *rdata = (const char *)data + desc[pos].offset; | |
4403 | |
4404 backtrace[me].position = pos; | |
4405 backtrace[me].offset = desc[pos].offset; | |
4406 | |
4407 switch (desc[pos].type) | |
4408 { | |
4409 case XD_SPECIFIER_END: | |
4410 pos = 0; | |
4411 desc = ((const Lisp_Specifier *)data)->methods->extra_description; | |
4412 goto restart; | |
4413 case XD_SIZE_T: | |
4414 case XD_INT: | |
4415 case XD_LONG: | |
4416 case XD_BYTECOUNT: | |
4417 case XD_LO_RESET_NIL: | |
4418 case XD_INT_RESET: | |
4419 case XD_LO_LINK: | |
4420 break; | |
4421 case XD_OPAQUE_DATA_PTR: | |
4422 { | |
4423 EMACS_INT count = desc[pos].data1; | |
4424 if (XD_IS_INDIRECT (count)) | |
4425 count = pdump_get_indirect_count (count, desc, data); | |
4426 | |
4427 pdump_add_entry (&pdump_opaque_data_list, | |
4428 *(void **)rdata, | |
4429 count, | |
4430 1, | |
4431 0); | |
4432 break; | |
4433 } | |
4434 case XD_C_STRING: | |
4435 { | |
4436 const char *str = *(const char **)rdata; | |
4437 if (str) | |
4438 pdump_add_entry (&pdump_opaque_data_list, str, strlen (str)+1, 1, 0); | |
4439 break; | |
4440 } | |
4441 case XD_DOC_STRING: | |
4442 { | |
4443 const char *str = *(const char **)rdata; | |
4444 if ((EMACS_INT)str > 0) | |
4445 pdump_add_entry (&pdump_opaque_data_list, str, strlen (str)+1, 1, 0); | |
4446 break; | |
4447 } | |
4448 case XD_LISP_OBJECT: | |
4449 { | |
4450 const Lisp_Object *pobj = (const Lisp_Object *)rdata; | |
4451 | |
4452 assert (desc[pos].data1 == 0); | |
4453 | |
4454 backtrace[me].offset = (const char *)pobj - (const char *)data; | |
4455 pdump_register_object (*pobj); | |
4456 break; | |
4457 } | |
4458 case XD_LISP_OBJECT_ARRAY: | |
4459 { | |
4460 int i; | |
4461 EMACS_INT count = desc[pos].data1; | |
4462 if (XD_IS_INDIRECT (count)) | |
4463 count = pdump_get_indirect_count (count, desc, data); | |
4464 | |
4465 for (i = 0; i < count; i++) | |
4466 { | |
4467 const Lisp_Object *pobj = ((const Lisp_Object *)rdata) + i; | |
4468 Lisp_Object dobj = *pobj; | |
4469 | |
4470 backtrace[me].offset = (const char *)pobj - (const char *)data; | |
4471 pdump_register_object (dobj); | |
4472 } | |
4473 break; | |
4474 } | |
4475 case XD_STRUCT_PTR: | |
4476 { | |
4477 EMACS_INT count = desc[pos].data1; | |
4478 const struct struct_description *sdesc = desc[pos].data2; | |
4479 const char *dobj = *(const char **)rdata; | |
4480 if (dobj) | |
4481 { | |
4482 if (XD_IS_INDIRECT (count)) | |
4483 count = pdump_get_indirect_count (count, desc, data); | |
4484 | |
4485 pdump_register_struct (dobj, sdesc, count); | |
4486 } | |
4487 break; | |
4488 } | |
4489 default: | |
4490 fprintf (stderr, "Unsupported dump type : %d\n", desc[pos].type); | |
4491 pdump_backtrace (); | |
4492 abort (); | |
4493 }; | |
4494 } | |
4495 } | |
4496 | |
4497 static void | |
4498 pdump_register_object (Lisp_Object obj) | |
4499 { | |
4500 struct lrecord_header *objh; | |
4501 | |
4502 if (!POINTER_TYPE_P (XTYPE (obj))) | |
4503 return; | |
4504 | |
4505 objh = XRECORD_LHEADER (obj); | |
4506 if (!objh) | |
4507 return; | |
4508 | |
4509 if (pdump_get_entry (objh)) | |
4510 return; | |
4511 | |
4512 if (LHEADER_IMPLEMENTATION (objh)->description) | |
4513 { | |
4514 int me = depth++; | |
4515 if (me>65536) | |
4516 { | |
4517 fprintf (stderr, "Backtrace overflow, loop ?\n"); | |
4518 abort (); | |
4519 } | |
4520 backtrace[me].obj = objh; | |
4521 backtrace[me].position = 0; | |
4522 backtrace[me].offset = 0; | |
4523 | |
4524 pdump_add_entry (pdump_object_table + objh->type, | |
4525 objh, | |
4526 LHEADER_IMPLEMENTATION (objh)->static_size ? | |
4527 LHEADER_IMPLEMENTATION (objh)->static_size : | |
4528 LHEADER_IMPLEMENTATION (objh)->size_in_bytes_method (objh), | |
4529 1, | |
4530 1); | |
4531 pdump_register_sub (objh, | |
4532 LHEADER_IMPLEMENTATION (objh)->description, | |
4533 me); | |
4534 --depth; | |
4535 } | |
4536 else | |
4537 { | |
4538 pdump_alert_undump_object[objh->type]++; | |
4539 fprintf (stderr, "Undumpable object type : %s\n", LHEADER_IMPLEMENTATION (objh)->name); | |
4540 pdump_backtrace (); | |
4541 } | |
4542 } | |
4543 | |
4544 static void | |
4545 pdump_register_struct (const void *data, const struct struct_description *sdesc, int count) | |
4546 { | |
4547 if (data && !pdump_get_entry (data)) | |
4548 { | |
4549 int me = depth++; | |
4550 int i; | |
4551 if (me>65536) | |
4552 { | |
4553 fprintf (stderr, "Backtrace overflow, loop ?\n"); | |
4554 abort (); | |
4555 } | |
4556 backtrace[me].obj = 0; | |
4557 backtrace[me].position = 0; | |
4558 backtrace[me].offset = 0; | |
4559 | |
4560 pdump_add_entry (pdump_get_entry_list (sdesc), | |
4561 data, | |
4562 sdesc->size, | |
4563 count, | |
4564 0); | |
4565 for (i=0; i<count; i++) | |
4566 { | |
4567 pdump_register_sub (((char *)data) + sdesc->size*i, | |
4568 sdesc->description, | |
4569 me); | |
4570 } | |
4571 --depth; | |
4572 } | |
4573 } | |
4574 | |
4575 static void | |
4576 pdump_dump_data (pdump_entry_list_elmt *elmt, const struct lrecord_description *desc) | |
4577 { | |
4578 size_t size = elmt->size; | |
4579 int count = elmt->count; | |
4580 if (desc) | |
4581 { | |
4582 int pos, i; | |
4583 memcpy (pdump_buf, elmt->obj, size*count); | |
4584 | |
4585 for (i=0; i<count; i++) | |
4586 { | |
4587 char *cur = ((char *)pdump_buf) + i*size; | |
4588 restart: | |
4589 for (pos = 0; desc[pos].type != XD_END; pos++) | |
4590 { | |
4591 void *rdata = cur + desc[pos].offset; | |
4592 switch (desc[pos].type) | |
4593 { | |
4594 case XD_SPECIFIER_END: | |
4595 desc = ((const Lisp_Specifier *)(elmt->obj))->methods->extra_description; | |
4596 goto restart; | |
4597 case XD_SIZE_T: | |
4598 case XD_INT: | |
4599 case XD_LONG: | |
4600 case XD_BYTECOUNT: | |
4601 break; | |
4602 case XD_LO_RESET_NIL: | |
4603 { | |
4604 EMACS_INT count = desc[pos].data1; | |
4605 int i; | |
4606 if (XD_IS_INDIRECT (count)) | |
4607 count = pdump_get_indirect_count (count, desc, elmt->obj); | |
4608 for (i=0; i<count; i++) | |
4609 ((EMACS_INT *)rdata)[i] = pdump_qnil->save_offset; | |
4610 break; | |
4611 } | |
4612 case XD_INT_RESET: | |
4613 { | |
4614 EMACS_INT val = desc[pos].data1; | |
4615 if (XD_IS_INDIRECT (val)) | |
4616 val = pdump_get_indirect_count (val, desc, elmt->obj); | |
4617 *(int *)rdata = val; | |
4618 break; | |
4619 } | |
4620 case XD_OPAQUE_DATA_PTR: | |
4621 case XD_C_STRING: | |
4622 case XD_STRUCT_PTR: | |
4623 { | |
4624 void *ptr = *(void **)rdata; | |
4625 if (ptr) | |
4626 *(EMACS_INT *)rdata = pdump_get_entry (ptr)->save_offset; | |
4627 break; | |
4628 } | |
4629 case XD_LO_LINK: | |
4630 { | |
4631 Lisp_Object obj = *(Lisp_Object *)rdata; | |
4632 pdump_entry_list_elmt *elmt1; | |
4633 for (;;) | |
4634 { | |
4635 elmt1 = pdump_get_entry (XRECORD_LHEADER (obj)); | |
4636 if (elmt1) | |
4637 break; | |
4638 obj = *(Lisp_Object *)(desc[pos].offset + (char *)(XRECORD_LHEADER (obj))); | |
4639 } | |
4640 *(EMACS_INT *)rdata = elmt1->save_offset; | |
4641 break; | |
4642 } | |
4643 case XD_LISP_OBJECT: | |
4644 { | |
4645 Lisp_Object *pobj = (Lisp_Object *) rdata; | |
4646 | |
4647 assert (desc[pos].data1 == 0); | |
4648 | |
4649 if (POINTER_TYPE_P (XTYPE (*pobj)) && XRECORD_LHEADER (*pobj)) | |
4650 *(EMACS_INT *)pobj = | |
4651 pdump_get_entry (XRECORD_LHEADER (*pobj))->save_offset; | |
4652 break; | |
4653 } | |
4654 case XD_LISP_OBJECT_ARRAY: | |
4655 { | |
4656 EMACS_INT count = desc[pos].data1; | |
4657 int i; | |
4658 if (XD_IS_INDIRECT (count)) | |
4659 count = pdump_get_indirect_count (count, desc, elmt->obj); | |
4660 | |
4661 for (i=0; i<count; i++) | |
4662 { | |
4663 Lisp_Object *pobj = ((Lisp_Object *)rdata) + i; | |
4664 if (POINTER_TYPE_P (XTYPE (*pobj)) && XRECORD_LHEADER (*pobj)) | |
4665 *(EMACS_INT *)pobj = | |
4666 pdump_get_entry (XRECORD_LHEADER (*pobj))->save_offset; | |
4667 } | |
4668 break; | |
4669 } | |
4670 case XD_DOC_STRING: | |
4671 { | |
4672 EMACS_INT str = *(EMACS_INT *)rdata; | |
4673 if (str > 0) | |
4674 *(EMACS_INT *)rdata = pdump_get_entry ((void *)str)->save_offset; | |
4675 break; | |
4676 } | |
4677 default: | |
4678 fprintf (stderr, "Unsupported dump type : %d\n", desc[pos].type); | |
4679 abort (); | |
4680 }; | |
4681 } | |
4682 } | |
4683 } | |
4684 write (pdump_fd, desc ? pdump_buf : elmt->obj, size*count); | |
4685 if (elmt->is_lrecord && ((size*count) & 3)) | |
4686 write (pdump_fd, "\0\0\0", 4-((size*count) & 3)); | |
4687 } | |
4688 | |
4689 static void | |
4690 pdump_reloc_one (void *data, EMACS_INT delta, const struct lrecord_description *desc) | |
4691 { | |
4692 int pos; | |
4693 | |
4694 restart: | |
4695 for (pos = 0; desc[pos].type != XD_END; pos++) | |
4696 { | |
4697 void *rdata = (char *)data + desc[pos].offset; | |
4698 switch (desc[pos].type) | |
4699 { | |
4700 case XD_SPECIFIER_END: | |
4701 pos = 0; | |
4702 desc = ((const Lisp_Specifier *)data)->methods->extra_description; | |
4703 goto restart; | |
4704 case XD_SIZE_T: | |
4705 case XD_INT: | |
4706 case XD_LONG: | |
4707 case XD_BYTECOUNT: | |
4708 case XD_INT_RESET: | |
4709 break; | |
4710 case XD_OPAQUE_DATA_PTR: | |
4711 case XD_C_STRING: | |
4712 case XD_STRUCT_PTR: | |
4713 case XD_LO_LINK: | |
4714 { | |
4715 EMACS_INT ptr = *(EMACS_INT *)rdata; | |
4716 if (ptr) | |
4717 *(EMACS_INT *)rdata = ptr+delta; | |
4718 break; | |
4719 } | |
4720 case XD_LISP_OBJECT: | |
4721 { | |
4722 Lisp_Object *pobj = (Lisp_Object *) rdata; | |
4723 | |
4724 assert (desc[pos].data1 == 0); | |
4725 | |
4726 if (POINTER_TYPE_P (XTYPE (*pobj)) | |
4727 && ! EQ (*pobj, Qnull_pointer)) | |
4728 XSETOBJ (*pobj, XTYPE (*pobj), (char *) XPNTR (*pobj) + delta); | |
4729 | |
4730 break; | |
4731 } | |
4732 case XD_LISP_OBJECT_ARRAY: | |
4733 case XD_LO_RESET_NIL: | |
4734 { | |
4735 EMACS_INT count = desc[pos].data1; | |
4736 int i; | |
4737 if (XD_IS_INDIRECT (count)) | |
4738 count = pdump_get_indirect_count (count, desc, data); | |
4739 | |
4740 for (i=0; i<count; i++) | |
4741 { | |
4742 Lisp_Object *pobj = (Lisp_Object *) rdata + i; | |
4743 | |
4744 if (POINTER_TYPE_P (XTYPE (*pobj)) | |
4745 && ! EQ (*pobj, Qnull_pointer)) | |
4746 XSETOBJ (*pobj, XTYPE (*pobj), (char *) XPNTR (*pobj) + delta); | |
4747 } | |
4748 break; | |
4749 } | |
4750 case XD_DOC_STRING: | |
4751 { | |
4752 EMACS_INT str = *(EMACS_INT *)rdata; | |
4753 if (str > 0) | |
4754 *(EMACS_INT *)rdata = str + delta; | |
4755 break; | |
4756 } | |
4757 default: | |
4758 fprintf (stderr, "Unsupported dump type : %d\n", desc[pos].type); | |
4759 abort (); | |
4760 }; | |
4761 } | |
4762 } | |
4763 | |
4764 static void | |
4765 pdump_allocate_offset (pdump_entry_list_elmt *elmt, const struct lrecord_description *desc) | |
4766 { | |
4767 size_t size = (elmt->is_lrecord ? (elmt->size + 3) & ~3 : elmt->size)*elmt->count; | |
4768 elmt->save_offset = cur_offset; | |
4769 if (size>max_size) | |
4770 max_size = size; | |
4771 cur_offset += size; | |
4772 } | |
4773 | |
4774 static void | |
4775 pdump_scan_by_alignment (void (*f)(pdump_entry_list_elmt *, const struct lrecord_description *)) | |
4776 { | |
4777 int align, i; | |
4778 const struct lrecord_description *idesc; | |
4779 pdump_entry_list_elmt *elmt; | |
4780 for (align=8; align>=0; align--) | |
4781 { | |
4782 for (i=0; i<=last_lrecord_type_index_assigned; i++) | |
4783 if (pdump_object_table[i].align == align) | |
4784 { | |
4785 elmt = pdump_object_table[i].first; | |
4786 if (!elmt) | |
4787 continue; | |
4788 idesc = lrecord_implementations_table[i]->description; | |
4789 while (elmt) | |
4790 { | |
4791 f (elmt, idesc); | |
4792 elmt = elmt->next; | |
4793 } | |
4794 } | |
4795 | |
4796 for (i=0; i<pdump_struct_table.count; i++) | |
4797 if (pdump_struct_table.list[i].list.align == align) | |
4798 { | |
4799 elmt = pdump_struct_table.list[i].list.first; | |
4800 idesc = pdump_struct_table.list[i].sdesc->description; | |
4801 while (elmt) | |
4802 { | |
4803 f (elmt, idesc); | |
4804 elmt = elmt->next; | |
4805 } | |
4806 } | |
4807 | |
4808 elmt = pdump_opaque_data_list.first; | |
4809 while (elmt) | |
4810 { | |
4811 if (align_table[elmt->size & 255] == align) | |
4812 f (elmt, 0); | |
4813 elmt = elmt->next; | |
4814 } | |
4815 } | |
4816 } | |
4817 | |
4818 static void | |
4819 pdump_dump_staticvec (void) | |
4820 { | |
4821 EMACS_INT *reloc = xnew_array (EMACS_INT, staticidx); | |
4822 int i; | |
4823 write (pdump_fd, staticvec, staticidx*sizeof (Lisp_Object *)); | |
4824 | |
4825 for (i=0; i<staticidx; i++) | |
4826 { | |
4827 Lisp_Object obj = *staticvec[i]; | |
4828 if (POINTER_TYPE_P (XTYPE (obj))) | |
4829 reloc[i] = pdump_get_entry (XRECORD_LHEADER (obj))->save_offset; | |
4830 else | |
4831 reloc[i] = *(EMACS_INT *)(staticvec[i]); | |
4832 } | |
4833 write (pdump_fd, reloc, staticidx*sizeof (Lisp_Object)); | |
4834 free (reloc); | |
4835 } | |
4836 | |
4837 static void | |
4838 pdump_dump_structvec (void) | |
4839 { | |
4840 int i; | |
4841 for (i=0; i<dumpstructidx; i++) | |
4842 { | |
4843 EMACS_INT adr; | |
4844 write (pdump_fd, &(dumpstructvec[i].data), sizeof (void *)); | |
4845 adr = pdump_get_entry (*(void **)(dumpstructvec[i].data))->save_offset; | |
4846 write (pdump_fd, &adr, sizeof (adr)); | |
4847 } | |
4848 } | |
4849 | |
4850 static void | |
4851 pdump_dump_itable (void) | |
4852 { | |
4853 write (pdump_fd, lrecord_implementations_table, sizeof (lrecord_implementations_table)); | |
4854 } | |
4855 | |
4856 static void | |
4857 pdump_dump_rtables (void) | |
4858 { | |
4859 int i, j; | |
4860 pdump_entry_list_elmt *elmt; | |
4861 pdump_reloc_table rt; | |
4862 | |
4863 for (i=0; i<=last_lrecord_type_index_assigned; i++) | |
4864 { | |
4865 elmt = pdump_object_table[i].first; | |
4866 if (!elmt) | |
4867 continue; | |
4868 rt.desc = lrecord_implementations_table[i]->description; | |
4869 rt.count = pdump_object_table[i].count; | |
4870 write (pdump_fd, &rt, sizeof (rt)); | |
4871 while (elmt) | |
4872 { | |
4873 EMACS_INT rdata = pdump_get_entry (elmt->obj)->save_offset; | |
4874 write (pdump_fd, &rdata, sizeof (rdata)); | |
4875 elmt = elmt->next; | |
4876 } | |
4877 } | |
4878 | |
4879 rt.desc = 0; | |
4880 rt.count = 0; | |
4881 write (pdump_fd, &rt, sizeof (rt)); | |
4882 | |
4883 for (i=0; i<pdump_struct_table.count; i++) | |
4884 { | |
4885 elmt = pdump_struct_table.list[i].list.first; | |
4886 rt.desc = pdump_struct_table.list[i].sdesc->description; | |
4887 rt.count = pdump_struct_table.list[i].list.count; | |
4888 write (pdump_fd, &rt, sizeof (rt)); | |
4889 while (elmt) | |
4890 { | |
4891 EMACS_INT rdata = pdump_get_entry (elmt->obj)->save_offset; | |
4892 for (j=0; j<elmt->count; j++) | |
4893 { | |
4894 write (pdump_fd, &rdata, sizeof (rdata)); | |
4895 rdata += elmt->size; | |
4896 } | |
4897 elmt = elmt->next; | |
4898 } | |
4899 } | |
4900 rt.desc = 0; | |
4901 rt.count = 0; | |
4902 write (pdump_fd, &rt, sizeof (rt)); | |
4903 } | |
4904 | |
4905 static void | |
4906 pdump_dump_wired (void) | |
4907 { | |
4908 EMACS_INT count = pdump_wireidx + pdump_wireidx_list; | |
4909 int i; | |
4910 | |
4911 write (pdump_fd, &count, sizeof (count)); | |
4912 | |
4913 for (i=0; i<pdump_wireidx; i++) | |
4914 { | |
4915 EMACS_INT obj = pdump_get_entry (XRECORD_LHEADER (*(pdump_wirevec[i])))->save_offset; | |
4916 write (pdump_fd, &pdump_wirevec[i], sizeof (pdump_wirevec[i])); | |
4917 write (pdump_fd, &obj, sizeof (obj)); | |
4918 } | |
4919 | |
4920 for (i=0; i<pdump_wireidx_list; i++) | |
4921 { | |
4922 Lisp_Object obj = *(pdump_wirevec_list[i]); | |
4923 pdump_entry_list_elmt *elmt; | |
4924 EMACS_INT res; | |
4925 | |
4926 for (;;) | |
4927 { | |
4928 const struct lrecord_description *desc; | |
4929 int pos; | |
4930 elmt = pdump_get_entry (XRECORD_LHEADER (obj)); | |
4931 if (elmt) | |
4932 break; | |
4933 desc = XRECORD_LHEADER_IMPLEMENTATION (obj)->description; | |
4934 for (pos = 0; desc[pos].type != XD_LO_LINK; pos++) | |
4935 if (desc[pos].type == XD_END) | |
4936 abort (); | |
4937 | |
4938 obj = *(Lisp_Object *)(desc[pos].offset + (char *)(XRECORD_LHEADER (obj))); | |
4939 } | |
4940 res = elmt->save_offset; | |
4941 | |
4942 write (pdump_fd, &pdump_wirevec_list[i], sizeof (pdump_wirevec_list[i])); | |
4943 write (pdump_fd, &res, sizeof (res)); | |
4944 } | |
4945 } | |
4946 | |
4947 void | |
4948 pdump (void) | |
4949 { | |
4950 int i; | |
4951 Lisp_Object t_console, t_device, t_frame; | |
4952 int none; | |
4953 dump_header hd; | |
4954 | |
4955 /* These appear in a DEFVAR_LISP, which does a staticpro() */ | |
4956 t_console = Vterminal_console; | |
4957 t_frame = Vterminal_frame; | |
4958 t_device = Vterminal_device; | |
4959 | |
4960 Vterminal_console = Qnil; | |
4961 Vterminal_frame = Qnil; | |
4962 Vterminal_device = Qnil; | |
4963 | |
4964 pdump_hash = xnew_array_and_zero (pdump_entry_list_elmt *, PDUMP_HASHSIZE); | |
4965 | |
4966 for (i=0; i<=last_lrecord_type_index_assigned; i++) | |
4967 { | |
4968 pdump_object_table[i].first = 0; | |
4969 pdump_object_table[i].align = 8; | |
4970 pdump_object_table[i].count = 0; | |
4971 pdump_alert_undump_object[i] = 0; | |
4972 } | |
4973 pdump_struct_table.count = 0; | |
4974 pdump_struct_table.size = -1; | |
4975 | |
4976 pdump_opaque_data_list.first = 0; | |
4977 pdump_opaque_data_list.align = 8; | |
4978 pdump_opaque_data_list.count = 0; | |
4979 depth = 0; | |
4980 | |
4981 for (i=0; i<staticidx; i++) | |
4982 pdump_register_object (*staticvec[i]); | |
4983 for (i=0; i<pdump_wireidx; i++) | |
4984 pdump_register_object (*pdump_wirevec[i]); | |
4985 | |
4986 none = 1; | |
4987 for (i=0; i<=last_lrecord_type_index_assigned; i++) | |
4988 if (pdump_alert_undump_object[i]) | |
4989 { | |
4990 if (none) | |
4991 printf ("Undumpable types list :\n"); | |
4992 none = 0; | |
4993 printf (" - %s (%d)\n", lrecord_implementations_table[i]->name, pdump_alert_undump_object[i]); | |
4994 } | |
4995 if (!none) | |
4996 return; | |
4997 | |
4998 for (i=0; i<dumpstructidx; i++) | |
4999 pdump_register_struct (*(void **)(dumpstructvec[i].data), dumpstructvec[i].desc, 1); | |
5000 | |
5001 memcpy (hd.signature, "XEmacsDP", 8); | |
5002 hd.reloc_address = 0; | |
5003 hd.nb_staticpro = staticidx; | |
5004 hd.nb_structdmp = dumpstructidx; | |
5005 hd.last_type = last_lrecord_type_index_assigned; | |
5006 | |
5007 cur_offset = 256; | |
5008 max_size = 0; | |
5009 | |
5010 pdump_scan_by_alignment (pdump_allocate_offset); | |
5011 pdump_qnil = pdump_get_entry (XRECORD_LHEADER (Qnil)); | |
5012 | |
5013 pdump_buf = xmalloc (max_size); | |
5014 /* Avoid use of the `open' macro. We want the real function. */ | |
5015 #undef open | |
5016 pdump_fd = open ("xemacs.dmp", | |
5017 O_WRONLY | O_CREAT | O_TRUNC | OPEN_BINARY, 0666); | |
5018 hd.stab_offset = (cur_offset + 3) & ~3; | |
5019 | |
5020 write (pdump_fd, &hd, sizeof (hd)); | |
5021 lseek (pdump_fd, 256, SEEK_SET); | |
5022 | |
5023 pdump_scan_by_alignment (pdump_dump_data); | |
5024 | |
5025 lseek (pdump_fd, hd.stab_offset, SEEK_SET); | |
5026 | |
5027 pdump_dump_staticvec (); | |
5028 pdump_dump_structvec (); | |
5029 pdump_dump_itable (); | |
5030 pdump_dump_rtables (); | |
5031 pdump_dump_wired (); | |
5032 | |
5033 close (pdump_fd); | |
5034 free (pdump_buf); | |
5035 | |
5036 free (pdump_hash); | |
5037 | |
5038 Vterminal_console = t_console; | |
5039 Vterminal_frame = t_frame; | |
5040 Vterminal_device = t_device; | |
5041 } | |
5042 | |
5043 int | |
5044 pdump_load (void) | |
5045 { | |
5046 size_t length; | |
5047 int i; | |
5048 char *p; | |
5049 EMACS_INT delta; | |
5050 EMACS_INT count; | |
5051 | |
5052 #define PDUMP_READ(p, type) (p = (char*) (((type *) p) + 1), *((type *) p - 1)) | |
5053 | |
5054 pdump_start = pdump_end = 0; | |
5055 | |
5056 pdump_fd = open ("xemacs.dmp", O_RDONLY | OPEN_BINARY); | |
5057 if (pdump_fd<0) | |
5058 return 0; | |
5059 | |
5060 length = lseek (pdump_fd, 0, SEEK_END); | |
5061 lseek (pdump_fd, 0, SEEK_SET); | |
5062 | |
5063 #ifdef HAVE_MMAP | |
5064 pdump_start = (char *) mmap (0, length, PROT_READ|PROT_WRITE, MAP_PRIVATE, pdump_fd, 0); | |
5065 if (pdump_start == MAP_FAILED) | |
5066 pdump_start = 0; | |
5067 #endif | |
5068 | |
5069 if (!pdump_start) | |
5070 { | |
5071 pdump_start = (char *)((((unsigned long)(xmalloc(length+255))) + 255) & ~255); | |
5072 read (pdump_fd, pdump_start, length); | |
5073 } | |
5074 | |
5075 close (pdump_fd); | |
5076 | |
5077 pdump_end = pdump_start + length; | |
5078 | |
5079 staticidx = ((dump_header *)(pdump_start))->nb_staticpro; | |
5080 last_lrecord_type_index_assigned = ((dump_header *)pdump_start)->last_type; | |
5081 delta = ((EMACS_INT)pdump_start) - ((dump_header *)pdump_start)->reloc_address; | |
5082 p = pdump_start + ((dump_header *)pdump_start)->stab_offset; | |
5083 | |
5084 /* Put back the staticvec in place */ | |
5085 memcpy (staticvec, p, staticidx*sizeof (Lisp_Object *)); | |
5086 p += staticidx*sizeof (Lisp_Object *); | |
5087 for (i=0; i<staticidx; i++) | |
5088 { | |
5089 Lisp_Object obj = PDUMP_READ (p, Lisp_Object); | |
5090 if (POINTER_TYPE_P (XTYPE (obj))) | |
5091 XSETOBJ (obj, XTYPE (obj), (char *) XPNTR (obj) + delta); | |
5092 *staticvec[i] = obj; | |
5093 } | |
5094 | |
5095 /* Put back the dumpstructs */ | |
5096 for (i=0; i<((dump_header *)pdump_start)->nb_structdmp; i++) | |
5097 { | |
5098 void **adr = PDUMP_READ (p, void **); | |
5099 *adr = (void *) (PDUMP_READ (p, char *) + delta); | |
5100 } | |
5101 | |
5102 /* Put back the lrecord_implementations_table */ | |
5103 memcpy (lrecord_implementations_table, p, sizeof (lrecord_implementations_table)); | |
5104 p += sizeof (lrecord_implementations_table); | |
5105 | |
5106 /* Give back their numbers to the lrecord implementations */ | |
5107 for (i = 0; i < countof (lrecord_implementations_table); i++) | |
5108 if (lrecord_implementations_table[i]) | |
5109 { | |
5110 *(lrecord_implementations_table[i]->lrecord_type_index) = i; | |
5111 last_lrecord_type_index_assigned = i; | |
5112 } | |
5113 | |
5114 /* Do the relocations */ | |
5115 pdump_rt_list = p; | |
5116 count = 2; | |
5117 for (;;) | |
5118 { | |
5119 pdump_reloc_table rt = PDUMP_READ (p, pdump_reloc_table); | |
5120 if (rt.desc) | |
5121 { | |
5122 for (i=0; i < rt.count; i++) | |
5123 { | |
5124 char *adr = delta + *(char **)p; | |
5125 *(char **)p = adr; | |
5126 pdump_reloc_one (adr, delta, rt.desc); | |
5127 p += sizeof (char *); | |
5128 } | |
5129 } else | |
5130 if (!(--count)) | |
5131 break; | |
5132 } | |
5133 | |
5134 /* Put the pdump_wire variables in place */ | |
5135 count = PDUMP_READ (p, EMACS_INT); | |
5136 | |
5137 for (i=0; i<count; i++) | |
5138 { | |
5139 Lisp_Object *var = PDUMP_READ (p, Lisp_Object *); | |
5140 Lisp_Object obj = PDUMP_READ (p, Lisp_Object); | |
5141 | |
5142 if (POINTER_TYPE_P (XTYPE (obj))) | |
5143 XSETOBJ (obj, XTYPE (obj), (char *) XPNTR (obj) + delta); | |
5144 | |
5145 *var = obj; | |
5146 } | |
5147 | |
5148 /* Final cleanups */ | |
5149 /* reorganize hash tables */ | |
5150 p = pdump_rt_list; | |
5151 for (;;) | |
5152 { | |
5153 pdump_reloc_table rt = PDUMP_READ (p, pdump_reloc_table); | |
5154 if (!rt.desc) | |
5155 break; | |
5156 if (rt.desc == hash_table_description) | |
5157 { | |
5158 for (i=0; i < rt.count; i++) | |
5159 pdump_reorganize_hash_table (PDUMP_READ (p, Lisp_Object)); | |
5160 break; | |
5161 } else | |
5162 p += sizeof (Lisp_Object) * rt.count; | |
5163 } | |
5164 return 1; | |
5165 } | |
5166 | |
5167 #endif /* PDUMP */ |