diff options
| author | Gerd Moellmann | 2000-03-27 19:43:47 +0000 |
|---|---|---|
| committer | Gerd Moellmann | 2000-03-27 19:43:47 +0000 |
| commit | 182ff2422523ba57c925b772c9c564c06a07b3fc (patch) | |
| tree | 2615d2111e35ca77d99c8f45b661c9a53608a6e9 /src/alloc.c | |
| parent | 4b3fd719464fb07dc92ac7584bd7584878e0a8c4 (diff) | |
| download | emacs-182ff2422523ba57c925b772c9c564c06a07b3fc.tar.gz emacs-182ff2422523ba57c925b772c9c564c06a07b3fc.zip | |
(mark_maybe_object): New function.
(mark_memory): Use it.
(SETJMP_WILL_LIKELY_WORK, SETJMP_WILL_NOT_WORK): New macros.
(setjmp_tested_p, longjmp_done): New variables.
(test_setjmp): New function.
(mark_stack) [!GC_SETJMP_WORKS]: Call test_setjmp.
(init_alloc): Initialize setjmp_tested_p and longjmp_done.
Diffstat (limited to 'src/alloc.c')
| -rw-r--r-- | src/alloc.c | 309 |
1 files changed, 234 insertions, 75 deletions
diff --git a/src/alloc.c b/src/alloc.c index 3027e08b467..9b82d45a0bf 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -296,6 +296,7 @@ static int live_cons_p P_ ((struct mem_node *, void *)); | |||
| 296 | static int live_symbol_p P_ ((struct mem_node *, void *)); | 296 | static int live_symbol_p P_ ((struct mem_node *, void *)); |
| 297 | static int live_float_p P_ ((struct mem_node *, void *)); | 297 | static int live_float_p P_ ((struct mem_node *, void *)); |
| 298 | static int live_misc_p P_ ((struct mem_node *, void *)); | 298 | static int live_misc_p P_ ((struct mem_node *, void *)); |
| 299 | static void mark_maybe_object P_ ((Lisp_Object)); | ||
| 299 | static void mark_memory P_ ((void *, void *)); | 300 | static void mark_memory P_ ((void *, void *)); |
| 300 | static void mem_init P_ ((void)); | 301 | static void mem_init P_ ((void)); |
| 301 | static struct mem_node *mem_insert P_ ((void *, void *, enum mem_type)); | 302 | static struct mem_node *mem_insert P_ ((void *, void *, enum mem_type)); |
| @@ -2823,6 +2824,86 @@ DEFUN ("gc-status", Fgc_status, Sgc_status, 0, 0, "", | |||
| 2823 | #endif /* GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES */ | 2824 | #endif /* GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES */ |
| 2824 | 2825 | ||
| 2825 | 2826 | ||
| 2827 | /* Mark OBJ if we can prove it's a Lisp_Object. */ | ||
| 2828 | |||
| 2829 | static INLINE void | ||
| 2830 | mark_maybe_object (obj) | ||
| 2831 | Lisp_Object obj; | ||
| 2832 | { | ||
| 2833 | void *po = (void *) XPNTR (obj); | ||
| 2834 | struct mem_node *m = mem_find (po); | ||
| 2835 | |||
| 2836 | if (m != MEM_NIL) | ||
| 2837 | { | ||
| 2838 | int mark_p = 0; | ||
| 2839 | |||
| 2840 | switch (XGCTYPE (obj)) | ||
| 2841 | { | ||
| 2842 | case Lisp_String: | ||
| 2843 | mark_p = (live_string_p (m, po) | ||
| 2844 | && !STRING_MARKED_P ((struct Lisp_String *) po)); | ||
| 2845 | break; | ||
| 2846 | |||
| 2847 | case Lisp_Cons: | ||
| 2848 | mark_p = (live_cons_p (m, po) | ||
| 2849 | && !XMARKBIT (XCONS (obj)->car)); | ||
| 2850 | break; | ||
| 2851 | |||
| 2852 | case Lisp_Symbol: | ||
| 2853 | mark_p = (live_symbol_p (m, po) | ||
| 2854 | && !XMARKBIT (XSYMBOL (obj)->plist)); | ||
| 2855 | break; | ||
| 2856 | |||
| 2857 | case Lisp_Float: | ||
| 2858 | mark_p = (live_float_p (m, po) | ||
| 2859 | && !XMARKBIT (XFLOAT (obj)->type)); | ||
| 2860 | break; | ||
| 2861 | |||
| 2862 | case Lisp_Vectorlike: | ||
| 2863 | /* Note: can't check GC_BUFFERP before we know it's a | ||
| 2864 | buffer because checking that dereferences the pointer | ||
| 2865 | PO which might point anywhere. */ | ||
| 2866 | if (live_vector_p (m, po)) | ||
| 2867 | mark_p = (!GC_SUBRP (obj) | ||
| 2868 | && !(XVECTOR (obj)->size & ARRAY_MARK_FLAG)); | ||
| 2869 | else if (live_buffer_p (m, po)) | ||
| 2870 | mark_p = GC_BUFFERP (obj) && !XMARKBIT (XBUFFER (obj)->name); | ||
| 2871 | break; | ||
| 2872 | |||
| 2873 | case Lisp_Misc: | ||
| 2874 | if (live_misc_p (m, po)) | ||
| 2875 | { | ||
| 2876 | switch (XMISCTYPE (obj)) | ||
| 2877 | { | ||
| 2878 | case Lisp_Misc_Marker: | ||
| 2879 | mark_p = !XMARKBIT (XMARKER (obj)->chain); | ||
| 2880 | break; | ||
| 2881 | |||
| 2882 | case Lisp_Misc_Buffer_Local_Value: | ||
| 2883 | case Lisp_Misc_Some_Buffer_Local_Value: | ||
| 2884 | mark_p = !XMARKBIT (XBUFFER_LOCAL_VALUE (obj)->realvalue); | ||
| 2885 | break; | ||
| 2886 | |||
| 2887 | case Lisp_Misc_Overlay: | ||
| 2888 | mark_p = !XMARKBIT (XOVERLAY (obj)->plist); | ||
| 2889 | break; | ||
| 2890 | } | ||
| 2891 | } | ||
| 2892 | break; | ||
| 2893 | } | ||
| 2894 | |||
| 2895 | if (mark_p) | ||
| 2896 | { | ||
| 2897 | #if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES | ||
| 2898 | if (nzombies < MAX_ZOMBIES) | ||
| 2899 | zombies[nzombies] = *p; | ||
| 2900 | ++nzombies; | ||
| 2901 | #endif | ||
| 2902 | mark_object (&obj); | ||
| 2903 | } | ||
| 2904 | } | ||
| 2905 | } | ||
| 2906 | |||
| 2826 | /* Mark Lisp objects in the address range START..END. */ | 2907 | /* Mark Lisp objects in the address range START..END. */ |
| 2827 | 2908 | ||
| 2828 | static void | 2909 | static void |
| @@ -2843,84 +2924,91 @@ mark_memory (start, end) | |||
| 2843 | start = end; | 2924 | start = end; |
| 2844 | end = tem; | 2925 | end = tem; |
| 2845 | } | 2926 | } |
| 2846 | 2927 | ||
| 2847 | for (p = (Lisp_Object *) start; (void *) p < end; ++p) | 2928 | for (p = (Lisp_Object *) start; (void *) p < end; ++p) |
| 2929 | mark_maybe_object (*p); | ||
| 2930 | } | ||
| 2931 | |||
| 2932 | |||
| 2933 | #if !defined GC_SAVE_REGISTERS_ON_STACK && !defined GC_SETJMP_WORKS | ||
| 2934 | |||
| 2935 | static int setjmp_tested_p, longjmps_done; | ||
| 2936 | |||
| 2937 | #define SETJMP_WILL_LIKELY_WORK "\ | ||
| 2938 | \n\ | ||
| 2939 | Emacs garbage collector has been changed to use conservative stack\n\ | ||
| 2940 | marking. Emacs has determined that the method it uses to do the\n\ | ||
| 2941 | marking will likely work on your system, but this isn't sure.\n\ | ||
| 2942 | \n\ | ||
| 2943 | If you are a system-programmer, or can get the help of a local wizard\n\ | ||
| 2944 | who is, please take a look at the function mark_stack in alloc.c, and\n\ | ||
| 2945 | verify that the methods used are appropriate for your system.\n\ | ||
| 2946 | \n\ | ||
| 2947 | Please mail the result to <gerd@gnu.org>.\n\ | ||
| 2948 | " | ||
| 2949 | |||
| 2950 | #define SETJMP_WILL_NOT_WORK "\ | ||
| 2951 | \n\ | ||
| 2952 | Emacs garbage collector has been changed to use conservative stack\n\ | ||
| 2953 | marking. Emacs has determined that the default method it uses to do the\n\ | ||
| 2954 | marking will not work on your system. We will need a system-dependent\n\ | ||
| 2955 | solution for your system.\n\ | ||
| 2956 | \n\ | ||
| 2957 | Please take a look at the function mark_stack in alloc.c, and\n\ | ||
| 2958 | try to find a way to make it work on your system.\n\ | ||
| 2959 | Please mail the result to <gerd@gnu.org>.\n\ | ||
| 2960 | " | ||
| 2961 | |||
| 2962 | |||
| 2963 | /* Perform a quick check if it looks like setjmp saves registers in a | ||
| 2964 | jmp_buf. Print a message to stderr saying so. When this test | ||
| 2965 | succeeds, this is _not_ a proof that setjmp is sufficient for | ||
| 2966 | conservative stack marking. Only the sources or a disassembly | ||
| 2967 | can prove that. */ | ||
| 2968 | |||
| 2969 | static void | ||
| 2970 | test_setjmp () | ||
| 2971 | { | ||
| 2972 | char buf[10]; | ||
| 2973 | register int x; | ||
| 2974 | jmp_buf jbuf; | ||
| 2975 | int result = 0; | ||
| 2976 | |||
| 2977 | /* Arrange for X to be put in a register. */ | ||
| 2978 | sprintf (buf, "1"); | ||
| 2979 | x = strlen (buf); | ||
| 2980 | x = 2 * x - 1; | ||
| 2981 | |||
| 2982 | setjmp (jbuf); | ||
| 2983 | if (longjmps_done == 1) | ||
| 2848 | { | 2984 | { |
| 2849 | void *po = (void *) XPNTR (*p); | 2985 | /* Came here after the longjmp at the end of the function. |
| 2850 | struct mem_node *m = mem_find (po); | ||
| 2851 | |||
| 2852 | if (m != MEM_NIL) | ||
| 2853 | { | ||
| 2854 | int mark_p = 0; | ||
| 2855 | 2986 | ||
| 2856 | switch (XGCTYPE (*p)) | 2987 | If x == 1, the longjmp has restored the register to its |
| 2857 | { | 2988 | value before the setjmp, and we can hope that setjmp |
| 2858 | case Lisp_String: | 2989 | saves all such registers in the jmp_buf, although that |
| 2859 | mark_p = (live_string_p (m, po) | 2990 | isn't sure. |
| 2860 | && !STRING_MARKED_P ((struct Lisp_String *) po)); | ||
| 2861 | break; | ||
| 2862 | |||
| 2863 | case Lisp_Cons: | ||
| 2864 | mark_p = (live_cons_p (m, po) | ||
| 2865 | && !XMARKBIT (XCONS (*p)->car)); | ||
| 2866 | break; | ||
| 2867 | |||
| 2868 | case Lisp_Symbol: | ||
| 2869 | mark_p = (live_symbol_p (m, po) | ||
| 2870 | && !XMARKBIT (XSYMBOL (*p)->plist)); | ||
| 2871 | break; | ||
| 2872 | |||
| 2873 | case Lisp_Float: | ||
| 2874 | mark_p = (live_float_p (m, po) | ||
| 2875 | && !XMARKBIT (XFLOAT (*p)->type)); | ||
| 2876 | break; | ||
| 2877 | |||
| 2878 | case Lisp_Vectorlike: | ||
| 2879 | /* Note: can't check GC_BUFFERP before we know it's a | ||
| 2880 | buffer because checking that dereferences the pointer | ||
| 2881 | PO which might point anywhere. */ | ||
| 2882 | if (live_vector_p (m, po)) | ||
| 2883 | mark_p = (!GC_SUBRP (*p) | ||
| 2884 | && !(XVECTOR (*p)->size & ARRAY_MARK_FLAG)); | ||
| 2885 | else if (live_buffer_p (m, po)) | ||
| 2886 | mark_p = GC_BUFFERP (*p) && !XMARKBIT (XBUFFER (*p)->name); | ||
| 2887 | break; | ||
| 2888 | |||
| 2889 | case Lisp_Misc: | ||
| 2890 | if (live_misc_p (m, po)) | ||
| 2891 | { | ||
| 2892 | switch (XMISCTYPE (*p)) | ||
| 2893 | { | ||
| 2894 | case Lisp_Misc_Marker: | ||
| 2895 | mark_p = !XMARKBIT (XMARKER (*p)->chain); | ||
| 2896 | break; | ||
| 2897 | |||
| 2898 | case Lisp_Misc_Buffer_Local_Value: | ||
| 2899 | case Lisp_Misc_Some_Buffer_Local_Value: | ||
| 2900 | mark_p = !XMARKBIT (XBUFFER_LOCAL_VALUE (*p)->realvalue); | ||
| 2901 | break; | ||
| 2902 | |||
| 2903 | case Lisp_Misc_Overlay: | ||
| 2904 | mark_p = !XMARKBIT (XOVERLAY (*p)->plist); | ||
| 2905 | break; | ||
| 2906 | } | ||
| 2907 | } | ||
| 2908 | break; | ||
| 2909 | } | ||
| 2910 | 2991 | ||
| 2911 | if (mark_p) | 2992 | For other values of X, either something really strange is |
| 2912 | { | 2993 | taking place, or the setjmp just didn't save the register. */ |
| 2913 | #if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES | 2994 | |
| 2914 | if (nzombies < MAX_ZOMBIES) | 2995 | if (x == 1) |
| 2915 | zombies[nzombies] = *p; | 2996 | fprintf (stderr, SETJMP_WILL_LIKELY_WORK); |
| 2916 | ++nzombies; | 2997 | else |
| 2917 | #endif | 2998 | { |
| 2918 | mark_object (p); | 2999 | fprintf (stderr, SETJMP_WILL_NOT_WORK); |
| 2919 | } | 3000 | exit (1); |
| 2920 | } | 3001 | } |
| 2921 | } | 3002 | } |
| 3003 | |||
| 3004 | ++longjmps_done; | ||
| 3005 | x = 2; | ||
| 3006 | if (longjmps_done == 1) | ||
| 3007 | longjmp (jbuf, 1); | ||
| 2922 | } | 3008 | } |
| 2923 | 3009 | ||
| 3010 | #endif /* not GC_SAVE_REGISTERS_ON_STACK && not GC_SETJMP_WORKS */ | ||
| 3011 | |||
| 2924 | 3012 | ||
| 2925 | #if GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS | 3013 | #if GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS |
| 2926 | 3014 | ||
| @@ -2956,7 +3044,51 @@ dump_zombies () | |||
| 2956 | #endif /* GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES */ | 3044 | #endif /* GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES */ |
| 2957 | 3045 | ||
| 2958 | 3046 | ||
| 2959 | /* Mark live Lisp objects on the C stack. */ | 3047 | /* Mark live Lisp objects on the C stack. |
| 3048 | |||
| 3049 | There are several system-dependent problems to consider when | ||
| 3050 | porting this to new architectures: | ||
| 3051 | |||
| 3052 | Processor Registers | ||
| 3053 | |||
| 3054 | We have to mark Lisp objects in CPU registers that can hold local | ||
| 3055 | variables or are used to pass parameters. | ||
| 3056 | |||
| 3057 | If GC_SAVE_REGISTERS_ON_STACK is defined, it should expand to | ||
| 3058 | something that either saves relevant registers on the stack, or | ||
| 3059 | calls mark_maybe_object passing it each register's contents. | ||
| 3060 | |||
| 3061 | If GC_SAVE_REGISTERS_ON_STACK is not defined, the current | ||
| 3062 | implementation assumes that calling setjmp saves registers we need | ||
| 3063 | to see in a jmp_buf which itself lies on the stack. This doesn't | ||
| 3064 | have to be true! It must be verified for each system, possibly | ||
| 3065 | by taking a look at the source code of setjmp. | ||
| 3066 | |||
| 3067 | Stack Layout | ||
| 3068 | |||
| 3069 | Architectures differ in the way their processor stack is organized. | ||
| 3070 | For example, the stack might look like this | ||
| 3071 | |||
| 3072 | +----------------+ | ||
| 3073 | | Lisp_Object | size = 4 | ||
| 3074 | +----------------+ | ||
| 3075 | | something else | size = 2 | ||
| 3076 | +----------------+ | ||
| 3077 | | Lisp_Object | size = 4 | ||
| 3078 | +----------------+ | ||
| 3079 | | ... | | ||
| 3080 | |||
| 3081 | In such a case, not every Lisp_Object will be aligned equally. To | ||
| 3082 | find all Lisp_Object on the stack it won't be sufficient to walk | ||
| 3083 | the stack in steps of 4 bytes. Instead, two passes will be | ||
| 3084 | necessary, one starting at the start of the stack, and a second | ||
| 3085 | pass starting at the start of the stack + 2. Likewise, if the | ||
| 3086 | minimal alignment of Lisp_Objects on the stack is 1, four passes | ||
| 3087 | would be necessary, each one starting with one byte more offset | ||
| 3088 | from the stack start. | ||
| 3089 | |||
| 3090 | The current code assumes by default that Lisp_Objects are aligned | ||
| 3091 | equally on the stack. */ | ||
| 2960 | 3092 | ||
| 2961 | static void | 3093 | static void |
| 2962 | mark_stack () | 3094 | mark_stack () |
| @@ -2976,15 +3108,37 @@ mark_stack () | |||
| 2976 | pass parameters. */ | 3108 | pass parameters. */ |
| 2977 | #ifdef GC_SAVE_REGISTERS_ON_STACK | 3109 | #ifdef GC_SAVE_REGISTERS_ON_STACK |
| 2978 | GC_SAVE_REGISTERS_ON_STACK (end); | 3110 | GC_SAVE_REGISTERS_ON_STACK (end); |
| 2979 | #else | 3111 | #else /* not GC_SAVE_REGISTERS_ON_STACK */ |
| 3112 | |||
| 3113 | #ifndef GC_SETJMP_WORKS /* If it hasn't been checked yet that | ||
| 3114 | setjmp will definitely work, test it | ||
| 3115 | and print a message with the result | ||
| 3116 | of the test. */ | ||
| 3117 | if (!setjmp_tested_p) | ||
| 3118 | { | ||
| 3119 | setjmp_tested_p = 1; | ||
| 3120 | test_setjmp (); | ||
| 3121 | } | ||
| 3122 | #endif /* GC_SETJMP_WORKS */ | ||
| 3123 | |||
| 2980 | setjmp (j); | 3124 | setjmp (j); |
| 2981 | end = stack_grows_down_p ? (char *) &j + sizeof j : (char *) &j; | 3125 | end = stack_grows_down_p ? (char *) &j + sizeof j : (char *) &j; |
| 2982 | #endif | 3126 | #endif /* not GC_SAVE_REGISTERS_ON_STACK */ |
| 2983 | 3127 | ||
| 2984 | /* This assumes that the stack is a contiguous region in memory. If | 3128 | /* This assumes that the stack is a contiguous region in memory. If |
| 2985 | that's not the case, something has to be done here to iterate over | 3129 | that's not the case, something has to be done here to iterate |
| 2986 | the stack segments. */ | 3130 | over the stack segments. */ |
| 3131 | #if GC_LISP_OBJECT_ALIGNMENT == 1 | ||
| 3132 | mark_memory (stack_base, end); | ||
| 3133 | mark_memory ((char *) stack_base + 1, end); | ||
| 3134 | mark_memory ((char *) stack_base + 2, end); | ||
| 3135 | mark_memory ((char *) stack_base + 3, end); | ||
| 3136 | #elif GC_LISP_OBJECT_ALIGNMENT == 2 | ||
| 3137 | mark_memory (stack_base, end); | ||
| 3138 | mark_memory ((char *) stack_base + 2, end); | ||
| 3139 | #else | ||
| 2987 | mark_memory (stack_base, end); | 3140 | mark_memory (stack_base, end); |
| 3141 | #endif | ||
| 2988 | 3142 | ||
| 2989 | #if GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS | 3143 | #if GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS |
| 2990 | check_gcpros (); | 3144 | check_gcpros (); |
| @@ -4548,6 +4702,11 @@ init_alloc () | |||
| 4548 | { | 4702 | { |
| 4549 | gcprolist = 0; | 4703 | gcprolist = 0; |
| 4550 | byte_stack_list = 0; | 4704 | byte_stack_list = 0; |
| 4705 | #if GC_MARK_STACK | ||
| 4706 | #if !defined GC_SAVE_REGISTERS_ON_STACK && !defined GC_SETJMP_WORKS | ||
| 4707 | setjmp_tested_p = longjmps_done = 0; | ||
| 4708 | #endif | ||
| 4709 | #endif | ||
| 4551 | } | 4710 | } |
| 4552 | 4711 | ||
| 4553 | void | 4712 | void |