+ /* Next in list. */
+ struct sblock *next;
+
+ /* Pointer to the next free sdata block. This points past the end
+ of the sblock if there isn't any space left in this block. */
+ struct sdata *next_free;
+
+ /* Start of data. */
+ struct sdata first_data;
+};
+
+/* Number of Lisp strings in a string_block structure. The 1020 is
+ 1024 minus malloc overhead. */
+
+#define STRINGS_IN_STRING_BLOCK \
+ ((1020 - sizeof (struct string_block *)) / sizeof (struct Lisp_String))
+
+/* Structure describing a block from which Lisp_String structures
+ are allocated. */
+
+struct string_block
+{
+ struct string_block *next;
+ struct Lisp_String strings[STRINGS_IN_STRING_BLOCK];
+};
+
+/* Head and tail of the list of sblock structures holding Lisp string
+ data. We always allocate from current_sblock. The NEXT pointers
+ in the sblock structures go from oldest_sblock to current_sblock. */
+
+static struct sblock *oldest_sblock, *current_sblock;
+
+/* List of sblocks for large strings. */
+
+static struct sblock *large_sblocks;
+
+/* List of string_block structures, and how many there are. */
+
+static struct string_block *string_blocks;
+static int n_string_blocks;
+
+/* Free-list of Lisp_Strings. */
+
+static struct Lisp_String *string_free_list;
+
+/* Number of live and free Lisp_Strings. */
+
+static int total_strings, total_free_strings;
+
+/* Number of bytes used by live strings. */
+
+static int total_string_size;
+
+/* Given a pointer to a Lisp_String S which is on the free-list
+ string_free_list, return a pointer to its successor in the
+ free-list. */
+
+#define NEXT_FREE_LISP_STRING(S) (*(struct Lisp_String **) (S))
+
+/* Return a pointer to the sdata structure belonging to Lisp string S.
+ S must be live, i.e. S->data must not be null. S->data is actually
+ a pointer to the `u.data' member of its sdata structure; the
+ structure starts at a constant offset in front of that. */
+
+#ifdef GC_CHECK_STRING_BYTES
+
+#define SDATA_OF_STRING(S) \
+ ((struct sdata *) ((S)->data - sizeof (struct Lisp_String *) \
+ - sizeof (EMACS_INT)))
+
+#else /* not GC_CHECK_STRING_BYTES */
+
+#define SDATA_OF_STRING(S) \
+ ((struct sdata *) ((S)->data - sizeof (struct Lisp_String *)))
+
+#endif /* not GC_CHECK_STRING_BYTES */
+
+/* Value is the size of an sdata structure large enough to hold NBYTES
+ bytes of string data. The value returned includes a terminating
+ NUL byte, the size of the sdata structure, and padding. */
+
+#ifdef GC_CHECK_STRING_BYTES
+
+#define SDATA_SIZE(NBYTES) \
+ ((sizeof (struct Lisp_String *) \
+ + (NBYTES) + 1 \
+ + sizeof (EMACS_INT) \
+ + sizeof (EMACS_INT) - 1) \
+ & ~(sizeof (EMACS_INT) - 1))
+
+#else /* not GC_CHECK_STRING_BYTES */
+
+#define SDATA_SIZE(NBYTES) \
+ ((sizeof (struct Lisp_String *) \
+ + (NBYTES) + 1 \
+ + sizeof (EMACS_INT) - 1) \
+ & ~(sizeof (EMACS_INT) - 1))
+
+#endif /* not GC_CHECK_STRING_BYTES */
+
+/* Initialize string allocation. Called from init_alloc_once. */
+
+void
+init_strings ()
+{
+ total_strings = total_free_strings = total_string_size = 0;
+ oldest_sblock = current_sblock = large_sblocks = NULL;
+ string_blocks = NULL;
+ n_string_blocks = 0;
+ string_free_list = NULL;
+}
+
+
+#ifdef GC_CHECK_STRING_BYTES
+
+static int check_string_bytes_count;
+
+void check_string_bytes P_ ((int));
+void check_sblock P_ ((struct sblock *));
+
+#define CHECK_STRING_BYTES(S) STRING_BYTES (S)
+
+
+/* Like GC_STRING_BYTES, but with debugging check. */
+
+int
+string_bytes (s)
+ struct Lisp_String *s;
+{
+ int nbytes = (s->size_byte < 0 ? s->size : s->size_byte) & ~MARKBIT;
+ if (!PURE_POINTER_P (s)
+ && s->data
+ && nbytes != SDATA_NBYTES (SDATA_OF_STRING (s)))
+ abort ();
+ return nbytes;
+}
+
+/* Check validity Lisp strings' string_bytes member in B. */
+
+void
+check_sblock (b)
+ struct sblock *b;
+{
+ struct sdata *from, *end, *from_end;
+
+ end = b->next_free;
+
+ for (from = &b->first_data; from < end; from = from_end)
+ {
+ /* Compute the next FROM here because copying below may
+ overwrite data we need to compute it. */
+ int nbytes;
+
+ /* Check that the string size recorded in the string is the
+ same as the one recorded in the sdata structure. */
+ if (from->string)
+ CHECK_STRING_BYTES (from->string);
+
+ if (from->string)
+ nbytes = GC_STRING_BYTES (from->string);
+ else
+ nbytes = SDATA_NBYTES (from);
+
+ nbytes = SDATA_SIZE (nbytes);
+ from_end = (struct sdata *) ((char *) from + nbytes);
+ }
+}
+
+
+/* Check validity of Lisp strings' string_bytes member. ALL_P
+ non-zero means check all strings, otherwise check only most
+ recently allocated strings. Used for hunting a bug. */
+
+void
+check_string_bytes (all_p)
+ int all_p;
+{
+ if (all_p)
+ {
+ struct sblock *b;
+
+ for (b = large_sblocks; b; b = b->next)
+ {
+ struct Lisp_String *s = b->first_data.string;
+ if (s)
+ CHECK_STRING_BYTES (s);
+ }
+
+ for (b = oldest_sblock; b; b = b->next)
+ check_sblock (b);
+ }
+ else
+ check_sblock (current_sblock);
+}
+
+#endif /* GC_CHECK_STRING_BYTES */
+
+
+/* Return a new Lisp_String. */
+
+static struct Lisp_String *
+allocate_string ()
+{
+ struct Lisp_String *s;
+
+ /* If the free-list is empty, allocate a new string_block, and
+ add all the Lisp_Strings in it to the free-list. */
+ if (string_free_list == NULL)
+ {
+ struct string_block *b;
+ int i;
+
+ b = (struct string_block *) lisp_malloc (sizeof *b, MEM_TYPE_STRING);
+ VALIDATE_LISP_STORAGE (b, sizeof *b);
+ bzero (b, sizeof *b);
+ b->next = string_blocks;
+ string_blocks = b;
+ ++n_string_blocks;
+
+ for (i = STRINGS_IN_STRING_BLOCK - 1; i >= 0; --i)
+ {
+ s = b->strings + i;
+ NEXT_FREE_LISP_STRING (s) = string_free_list;
+ string_free_list = s;
+ }
+
+ total_free_strings += STRINGS_IN_STRING_BLOCK;
+ }
+
+ /* Pop a Lisp_String off the free-list. */
+ s = string_free_list;
+ string_free_list = NEXT_FREE_LISP_STRING (s);
+
+ /* Probably not strictly necessary, but play it safe. */
+ bzero (s, sizeof *s);
+
+ --total_free_strings;
+ ++total_strings;
+ ++strings_consed;
+ consing_since_gc += sizeof *s;
+
+#ifdef GC_CHECK_STRING_BYTES
+ if (!noninteractive
+#ifdef macintosh
+ && current_sblock
+#endif
+ )
+ {
+ if (++check_string_bytes_count == 200)
+ {
+ check_string_bytes_count = 0;
+ check_string_bytes (1);
+ }
+ else
+ check_string_bytes (0);
+ }
+#endif /* GC_CHECK_STRING_BYTES */
+
+ return s;
+}
+
+
+/* Set up Lisp_String S for holding NCHARS characters, NBYTES bytes,
+ plus a NUL byte at the end. Allocate an sdata structure for S, and
+ set S->data to its `u.data' member. Store a NUL byte at the end of
+ S->data. Set S->size to NCHARS and S->size_byte to NBYTES. Free
+ S->data if it was initially non-null. */
+
+void
+allocate_string_data (s, nchars, nbytes)
+ struct Lisp_String *s;
+ int nchars, nbytes;
+{
+ struct sdata *data, *old_data;
+ struct sblock *b;
+ int needed, old_nbytes;
+
+ /* Determine the number of bytes needed to store NBYTES bytes
+ of string data. */
+ needed = SDATA_SIZE (nbytes);
+
+ if (nbytes > LARGE_STRING_BYTES)
+ {
+ size_t size = sizeof *b - sizeof (struct sdata) + needed;
+
+#ifdef DOUG_LEA_MALLOC
+ /* Prevent mmap'ing the chunk. Lisp data may not be mmap'ed
+ because mapped region contents are not preserved in
+ a dumped Emacs. */
+ mallopt (M_MMAP_MAX, 0);
+#endif
+
+ b = (struct sblock *) lisp_malloc (size, MEM_TYPE_NON_LISP);
+
+#ifdef DOUG_LEA_MALLOC
+ /* Back to a reasonable maximum of mmap'ed areas. */
+ mallopt (M_MMAP_MAX, MMAP_MAX_AREAS);
+#endif
+
+ b->next_free = &b->first_data;
+ b->first_data.string = NULL;
+ b->next = large_sblocks;
+ large_sblocks = b;
+ }
+ else if (current_sblock == NULL
+ || (((char *) current_sblock + SBLOCK_SIZE
+ - (char *) current_sblock->next_free)
+ < needed))
+ {
+ /* Not enough room in the current sblock. */
+ b = (struct sblock *) lisp_malloc (SBLOCK_SIZE, MEM_TYPE_NON_LISP);
+ b->next_free = &b->first_data;
+ b->first_data.string = NULL;
+ b->next = NULL;
+
+ if (current_sblock)
+ current_sblock->next = b;
+ else
+ oldest_sblock = b;
+ current_sblock = b;
+ }
+ else
+ b = current_sblock;
+
+ old_data = s->data ? SDATA_OF_STRING (s) : NULL;
+ old_nbytes = GC_STRING_BYTES (s);
+
+ data = b->next_free;
+ data->string = s;
+ s->data = SDATA_DATA (data);
+#ifdef GC_CHECK_STRING_BYTES
+ SDATA_NBYTES (data) = nbytes;
+#endif
+ s->size = nchars;
+ s->size_byte = nbytes;
+ s->data[nbytes] = '\0';
+ b->next_free = (struct sdata *) ((char *) data + needed);
+
+ /* If S had already data assigned, mark that as free by setting its
+ string back-pointer to null, and recording the size of the data
+ in it. */
+ if (old_data)
+ {
+ SDATA_NBYTES (old_data) = old_nbytes;
+ old_data->string = NULL;
+ }
+
+ consing_since_gc += needed;
+}
+
+
+/* Sweep and compact strings. */
+
+static void
+sweep_strings ()
+{
+ struct string_block *b, *next;
+ struct string_block *live_blocks = NULL;
+
+ string_free_list = NULL;
+ total_strings = total_free_strings = 0;
+ total_string_size = 0;
+
+ /* Scan strings_blocks, free Lisp_Strings that aren't marked. */
+ for (b = string_blocks; b; b = next)
+ {
+ int i, nfree = 0;
+ struct Lisp_String *free_list_before = string_free_list;
+
+ next = b->next;
+
+ for (i = 0; i < STRINGS_IN_STRING_BLOCK; ++i)
+ {
+ struct Lisp_String *s = b->strings + i;
+
+ if (s->data)
+ {
+ /* String was not on free-list before. */
+ if (STRING_MARKED_P (s))
+ {
+ /* String is live; unmark it and its intervals. */
+ UNMARK_STRING (s);
+
+ if (!NULL_INTERVAL_P (s->intervals))
+ UNMARK_BALANCE_INTERVALS (s->intervals);
+
+ ++total_strings;
+ total_string_size += STRING_BYTES (s);
+ }
+ else
+ {
+ /* String is dead. Put it on the free-list. */
+ struct sdata *data = SDATA_OF_STRING (s);
+
+ /* Save the size of S in its sdata so that we know
+ how large that is. Reset the sdata's string
+ back-pointer so that we know it's free. */
+#ifdef GC_CHECK_STRING_BYTES
+ if (GC_STRING_BYTES (s) != SDATA_NBYTES (data))
+ abort ();
+#else
+ data->u.nbytes = GC_STRING_BYTES (s);
+#endif
+ data->string = NULL;
+
+ /* Reset the strings's `data' member so that we
+ know it's free. */
+ s->data = NULL;
+
+ /* Put the string on the free-list. */
+ NEXT_FREE_LISP_STRING (s) = string_free_list;
+ string_free_list = s;
+ ++nfree;
+ }
+ }
+ else
+ {
+ /* S was on the free-list before. Put it there again. */
+ NEXT_FREE_LISP_STRING (s) = string_free_list;
+ string_free_list = s;
+ ++nfree;
+ }
+ }
+
+ /* Free blocks that contain free Lisp_Strings only, except
+ the first two of them. */
+ if (nfree == STRINGS_IN_STRING_BLOCK
+ && total_free_strings > STRINGS_IN_STRING_BLOCK)
+ {
+ lisp_free (b);
+ --n_string_blocks;
+ string_free_list = free_list_before;
+ }
+ else
+ {
+ total_free_strings += nfree;
+ b->next = live_blocks;
+ live_blocks = b;
+ }
+ }
+
+ string_blocks = live_blocks;
+ free_large_strings ();
+ compact_small_strings ();
+}
+
+
+/* Free dead large strings. */
+
+static void
+free_large_strings ()
+{
+ struct sblock *b, *next;
+ struct sblock *live_blocks = NULL;
+
+ for (b = large_sblocks; b; b = next)
+ {
+ next = b->next;
+
+ if (b->first_data.string == NULL)
+ lisp_free (b);
+ else
+ {
+ b->next = live_blocks;
+ live_blocks = b;
+ }
+ }
+
+ large_sblocks = live_blocks;
+}
+
+
+/* Compact data of small strings. Free sblocks that don't contain
+ data of live strings after compaction. */
+
+static void
+compact_small_strings ()
+{
+ struct sblock *b, *tb, *next;
+ struct sdata *from, *to, *end, *tb_end;
+ struct sdata *to_end, *from_end;
+
+ /* TB is the sblock we copy to, TO is the sdata within TB we copy
+ to, and TB_END is the end of TB. */
+ tb = oldest_sblock;
+ tb_end = (struct sdata *) ((char *) tb + SBLOCK_SIZE);
+ to = &tb->first_data;
+
+ /* Step through the blocks from the oldest to the youngest. We
+ expect that old blocks will stabilize over time, so that less
+ copying will happen this way. */
+ for (b = oldest_sblock; b; b = b->next)
+ {
+ end = b->next_free;
+ xassert ((char *) end <= (char *) b + SBLOCK_SIZE);
+
+ for (from = &b->first_data; from < end; from = from_end)
+ {
+ /* Compute the next FROM here because copying below may
+ overwrite data we need to compute it. */
+ int nbytes;
+
+#ifdef GC_CHECK_STRING_BYTES
+ /* Check that the string size recorded in the string is the
+ same as the one recorded in the sdata structure. */
+ if (from->string
+ && GC_STRING_BYTES (from->string) != SDATA_NBYTES (from))
+ abort ();
+#endif /* GC_CHECK_STRING_BYTES */
+
+ if (from->string)
+ nbytes = GC_STRING_BYTES (from->string);
+ else
+ nbytes = SDATA_NBYTES (from);
+
+ nbytes = SDATA_SIZE (nbytes);
+ from_end = (struct sdata *) ((char *) from + nbytes);
+
+ /* FROM->string non-null means it's alive. Copy its data. */
+ if (from->string)
+ {
+ /* If TB is full, proceed with the next sblock. */
+ to_end = (struct sdata *) ((char *) to + nbytes);
+ if (to_end > tb_end)
+ {
+ tb->next_free = to;
+ tb = tb->next;
+ tb_end = (struct sdata *) ((char *) tb + SBLOCK_SIZE);
+ to = &tb->first_data;
+ to_end = (struct sdata *) ((char *) to + nbytes);
+ }
+
+ /* Copy, and update the string's `data' pointer. */
+ if (from != to)
+ {
+ xassert (tb != b || to <= from);
+ safe_bcopy ((char *) from, (char *) to, nbytes);
+ to->string->data = SDATA_DATA (to);
+ }
+
+ /* Advance past the sdata we copied to. */
+ to = to_end;
+ }
+ }
+ }
+
+ /* The rest of the sblocks following TB don't contain live data, so
+ we can free them. */
+ for (b = tb->next; b; b = next)
+ {
+ next = b->next;
+ lisp_free (b);
+ }
+
+ tb->next_free = to;
+ tb->next = NULL;
+ current_sblock = tb;
+}
+
+
+DEFUN ("make-string", Fmake_string, Smake_string, 2, 2, 0,
+ "Return a newly created string of length LENGTH, with each element being INIT.\n\
+Both LENGTH and INIT must be numbers.")
+ (length, init)
+ Lisp_Object length, init;
+{
+ register Lisp_Object val;
+ register unsigned char *p, *end;
+ int c, nbytes;
+
+ CHECK_NATNUM (length, 0);
+ CHECK_NUMBER (init, 1);
+
+ c = XINT (init);
+ if (SINGLE_BYTE_CHAR_P (c))
+ {
+ nbytes = XINT (length);
+ val = make_uninit_string (nbytes);
+ p = XSTRING (val)->data;
+ end = p + XSTRING (val)->size;
+ while (p != end)
+ *p++ = c;
+ }
+ else
+ {
+ unsigned char str[MAX_MULTIBYTE_LENGTH];
+ int len = CHAR_STRING (c, str);
+
+ nbytes = len * XINT (length);
+ val = make_uninit_multibyte_string (XINT (length), nbytes);
+ p = XSTRING (val)->data;
+ end = p + nbytes;
+ while (p != end)
+ {
+ bcopy (str, p, len);
+ p += len;
+ }
+ }
+
+ *p = 0;
+ return val;
+}
+
+
+DEFUN ("make-bool-vector", Fmake_bool_vector, Smake_bool_vector, 2, 2, 0,
+ "Return a new bool-vector of length LENGTH, using INIT for as each element.\n\
+LENGTH must be a number. INIT matters only in whether it is t or nil.")
+ (length, init)
+ Lisp_Object length, init;
+{
+ register Lisp_Object val;
+ struct Lisp_Bool_Vector *p;
+ int real_init, i;
+ int length_in_chars, length_in_elts, bits_per_value;
+
+ CHECK_NATNUM (length, 0);
+
+ bits_per_value = sizeof (EMACS_INT) * BITS_PER_CHAR;
+
+ length_in_elts = (XFASTINT (length) + bits_per_value - 1) / bits_per_value;
+ length_in_chars = ((XFASTINT (length) + BITS_PER_CHAR - 1) / BITS_PER_CHAR);
+
+ /* We must allocate one more elements than LENGTH_IN_ELTS for the
+ slot `size' of the struct Lisp_Bool_Vector. */
+ val = Fmake_vector (make_number (length_in_elts + 1), Qnil);
+ p = XBOOL_VECTOR (val);
+
+ /* Get rid of any bits that would cause confusion. */
+ p->vector_size = 0;
+ XSETBOOL_VECTOR (val, p);
+ p->size = XFASTINT (length);
+
+ real_init = (NILP (init) ? 0 : -1);
+ for (i = 0; i < length_in_chars ; i++)
+ p->data[i] = real_init;
+
+ /* Clear the extraneous bits in the last byte. */
+ if (XINT (length) != length_in_chars * BITS_PER_CHAR)
+ XBOOL_VECTOR (val)->data[length_in_chars - 1]
+ &= (1 << (XINT (length) % BITS_PER_CHAR)) - 1;
+
+ return val;
+}
+
+
+/* Make a string from NBYTES bytes at CONTENTS, and compute the number
+ of characters from the contents. This string may be unibyte or
+ multibyte, depending on the contents. */
+
+Lisp_Object
+make_string (contents, nbytes)
+ char *contents;
+ int nbytes;
+{
+ register Lisp_Object val;
+ int nchars, multibyte_nbytes;
+
+ parse_str_as_multibyte (contents, nbytes, &nchars, &multibyte_nbytes);
+ if (nbytes == nchars || nbytes != multibyte_nbytes)
+ /* CONTENTS contains no multibyte sequences or contains an invalid
+ multibyte sequence. We must make unibyte string. */
+ val = make_unibyte_string (contents, nbytes);
+ else
+ val = make_multibyte_string (contents, nchars, nbytes);
+ return val;
+}
+
+
+/* Make an unibyte string from LENGTH bytes at CONTENTS. */
+
+Lisp_Object
+make_unibyte_string (contents, length)
+ char *contents;
+ int length;
+{
+ register Lisp_Object val;
+ val = make_uninit_string (length);
+ bcopy (contents, XSTRING (val)->data, length);
+ SET_STRING_BYTES (XSTRING (val), -1);
+ return val;
+}
+
+
+/* Make a multibyte string from NCHARS characters occupying NBYTES
+ bytes at CONTENTS. */
+
+Lisp_Object
+make_multibyte_string (contents, nchars, nbytes)
+ char *contents;
+ int nchars, nbytes;
+{
+ register Lisp_Object val;
+ val = make_uninit_multibyte_string (nchars, nbytes);
+ bcopy (contents, XSTRING (val)->data, nbytes);
+ return val;
+}
+
+
+/* Make a string from NCHARS characters occupying NBYTES bytes at
+ CONTENTS. It is a multibyte string if NBYTES != NCHARS. */
+
+Lisp_Object
+make_string_from_bytes (contents, nchars, nbytes)
+ char *contents;
+ int nchars, nbytes;
+{
+ register Lisp_Object val;
+ val = make_uninit_multibyte_string (nchars, nbytes);
+ bcopy (contents, XSTRING (val)->data, nbytes);
+ if (STRING_BYTES (XSTRING (val)) == XSTRING (val)->size)
+ SET_STRING_BYTES (XSTRING (val), -1);
+ return val;
+}
+
+
+/* Make a string from NCHARS characters occupying NBYTES bytes at
+ CONTENTS. The argument MULTIBYTE controls whether to label the
+ string as multibyte. */
+
+Lisp_Object
+make_specified_string (contents, nchars, nbytes, multibyte)
+ char *contents;
+ int nchars, nbytes;
+ int multibyte;
+{
+ register Lisp_Object val;
+ val = make_uninit_multibyte_string (nchars, nbytes);
+ bcopy (contents, XSTRING (val)->data, nbytes);
+ if (!multibyte)
+ SET_STRING_BYTES (XSTRING (val), -1);
+ return val;
+}
+
+
+/* Make a string from the data at STR, treating it as multibyte if the
+ data warrants. */
+
+Lisp_Object
+build_string (str)
+ char *str;
+{
+ return make_string (str, strlen (str));
+}
+
+
+/* Return an unibyte Lisp_String set up to hold LENGTH characters
+ occupying LENGTH bytes. */
+
+Lisp_Object
+make_uninit_string (length)
+ int length;
+{
+ Lisp_Object val;
+ val = make_uninit_multibyte_string (length, length);
+ SET_STRING_BYTES (XSTRING (val), -1);
+ return val;
+}
+
+
+/* Return a multibyte Lisp_String set up to hold NCHARS characters
+ which occupy NBYTES bytes. */
+
+Lisp_Object
+make_uninit_multibyte_string (nchars, nbytes)
+ int nchars, nbytes;
+{
+ Lisp_Object string;
+ struct Lisp_String *s;
+
+ if (nchars < 0)
+ abort ();
+
+ s = allocate_string ();
+ allocate_string_data (s, nchars, nbytes);
+ XSETSTRING (string, s);
+ string_chars_consed += nbytes;
+ return string;
+}
+
+
+\f
+/***********************************************************************
+ Float Allocation
+ ***********************************************************************/
+
+/* We store float cells inside of float_blocks, allocating a new
+ float_block with malloc whenever necessary. Float cells reclaimed
+ by GC are put on a free list to be reallocated before allocating
+ any new float cells from the latest float_block.
+
+ Each float_block is just under 1020 bytes long, since malloc really
+ allocates in units of powers of two and uses 4 bytes for its own
+ overhead. */
+
+#define FLOAT_BLOCK_SIZE \
+ ((1020 - sizeof (struct float_block *)) / sizeof (struct Lisp_Float))
+
+struct float_block
+{
+ struct float_block *next;
+ struct Lisp_Float floats[FLOAT_BLOCK_SIZE];
+};
+
+/* Current float_block. */
+
+struct float_block *float_block;
+
+/* Index of first unused Lisp_Float in the current float_block. */
+
+int float_block_index;
+
+/* Total number of float blocks now in use. */
+
+int n_float_blocks;
+
+/* Free-list of Lisp_Floats. */
+
+struct Lisp_Float *float_free_list;
+
+
+/* Initialze float allocation. */
+
+void
+init_float ()
+{
+ float_block = (struct float_block *) lisp_malloc (sizeof *float_block,
+ MEM_TYPE_FLOAT);