/* -*-C-*- $Id: c.c,v 1.12 1999/01/02 06:11:34 cph Exp $ Copyright (c) 1992-1999 Massachusetts Institute of Technology This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "liarc.h" #include "prims.h" #include "bignum.h" #include "bitstr.h" #include "avltree.h" #ifdef BUG_GCC_LONG_CALLS extern SCHEME_OBJECT EXFUN (memory_to_string, (long, unsigned char *)); extern SCHEME_OBJECT EXFUN (memory_to_symbol, (long, unsigned char *)); extern SCHEME_OBJECT EXFUN (make_vector, (long, SCHEME_OBJECT, Boolean)); extern SCHEME_OBJECT EXFUN (cons, (SCHEME_OBJECT, SCHEME_OBJECT)); extern SCHEME_OBJECT EXFUN (double_to_flonum, (double)); extern SCHEME_OBJECT EXFUN (long_to_integer, (long)); extern SCHEME_OBJECT EXFUN (digit_string_to_integer, (Boolean, long, char *)); extern SCHEME_OBJECT EXFUN (digit_string_to_bit_string, (long, long, char *)); extern SCHEME_OBJECT EXFUN (make_primitive, (char *, int)); SCHEME_OBJECT EXFUN ((* (constructor_kludge [10])), ()) = { ((SCHEME_OBJECT EXFUN ((*), ())) memory_to_string), ((SCHEME_OBJECT EXFUN ((*), ())) memory_to_symbol), ((SCHEME_OBJECT EXFUN ((*), ())) make_vector), ((SCHEME_OBJECT EXFUN ((*), ())) cons), ((SCHEME_OBJECT EXFUN ((*), ())) rconsm), ((SCHEME_OBJECT EXFUN ((*), ())) double_to_flonum), ((SCHEME_OBJECT EXFUN ((*), ())) long_to_integer), ((SCHEME_OBJECT EXFUN ((*), ())) digit_string_to_integer), ((SCHEME_OBJECT EXFUN ((*), ())) digit_string_to_bit_string), ((SCHEME_OBJECT EXFUN ((*), ())) make_primitive) }; #endif /* BUG_GCC_LONG_CALLS */ extern char * interface_to_C_hook; extern long C_return_value, MAX_TRAMPOLINE; extern void EXFUN (C_to_interface, (PTR)); extern void EXFUN (interface_initialize, (void)); extern SCHEME_OBJECT * EXFUN (initialize_C_compiled_block, (int, char *)); extern int EXFUN (initialize_compiled_code_blocks, (void)); extern void * scheme_hooks_low, * scheme_hooks_high; #define TRAMPOLINE_FUDGE 20 typedef SCHEME_OBJECT * EXFUN ((* code_block), (SCHEME_OBJECT *, unsigned long)); typedef SCHEME_OBJECT * EXFUN ((* data_block), (unsigned long)); struct compiled_entry_s { code_block code; unsigned long dispatch; }; struct compiled_block_s { char * name; unsigned long nentries; unsigned long dispatch; data_block constructor; }; int pc_zero_bits; static SCHEME_OBJECT dummy_entry = ((SCHEME_OBJECT) -1L); char * interface_to_C_hook = ((char *) & dummy_entry); void * scheme_hooks_low = NULL, * scheme_hooks_high = NULL; #define PSEUDO_STATIC PSEUDO_STATIC long initial_entry_number = -1; PSEUDO_STATIC unsigned long max_compiled_entries = 0, compiled_entries_size = 0; PSEUDO_STATIC struct compiled_entry_s * compiled_entries = ((struct compiled_entry_s *) NULL); PSEUDO_STATIC unsigned long max_compiled_blocks = 0, compiled_blocks_table_size = 0; PSEUDO_STATIC struct compiled_block_s * compiled_blocks_table = ((struct compiled_block_s *) NULL); PSEUDO_STATIC tree_node compiled_blocks_tree = ((tree_node) NULL); SCHEME_OBJECT * DEFUN (trampoline_procedure, (trampoline, dispatch), SCHEME_OBJECT * trampoline AND unsigned long dispatch) { return (invoke_utility (((int) (* ((unsigned long *) trampoline))), ((long) (TRAMPOLINE_STORAGE (trampoline))), 0, 0, 0)); } int DEFUN_VOID (NO_SUBBLOCKS) { return (0); } SCHEME_OBJECT * DEFUN (no_data, (base_dispatch), unsigned long base_dispatch) { return ((SCHEME_OBJECT *) NULL); } SCHEME_OBJECT * DEFUN (uninitialized_data, (base_dispatch), unsigned long base_dispatch) { /* Not yet assigned. Cannot construct data. */ error_external_return (); } SCHEME_OBJECT * DEFUN (unspecified_code, (entry, dispatch), SCHEME_OBJECT * entry AND unsigned long dispatch) { Store_Expression ((SCHEME_OBJECT) entry); C_return_value = (ERR_EXECUTE_MANIFEST_VECTOR); return (&dummy_entry); } extern PTR EXFUN (malloc, (unsigned long)); extern PTR EXFUN (realloc, (PTR, unsigned long)); PTR DEFUN (lrealloc, (ptr, size), PTR ptr AND unsigned long size) { if (ptr == ((PTR) NULL)) return (malloc (size)); else return (realloc (ptr, size)); } int DEFUN (declare_trampoline_block, (nentries), unsigned long nentries) { int result; result = (declare_compiled_code ("#trampoline_code_block", nentries, NO_SUBBLOCKS, trampoline_procedure)); #if 0 /* trampoline block is special. */ if (result != 0) return (result); result = (declare_compiled_data ("#trampoline_code_block", NO_SUBBLOCKS, no_data)); #endif return (result); } void DEFUN_VOID (interface_initialize) { int i, pow, del; for (i = 0, pow = 1, del = ((sizeof (SCHEME_OBJECT)) / (sizeof (char))); pow < del; i+= 1) pow = (pow << 1); if (pow != del) { /* Not a power of two -- ill-defined pc_zero_bits. */ outf_fatal ("interface_initialize: bad (sizeof (SCHEME_OBJECT)).\n"); Microcode_Termination (TERM_EXIT); } pc_zero_bits = i; if (initial_entry_number == -1) initial_entry_number = (MAX_TRAMPOLINE + TRAMPOLINE_FUDGE); if (((declare_trampoline_block (initial_entry_number)) != 0) || (initialize_compiled_code_blocks ()) != 0) { if (Registers[REGBLOCK_PRIMITIVE] != SHARP_F) signal_error_from_primitive (ERR_FASLOAD_COMPILED_MISMATCH); else { outf_fatal ("interface_initialize: error initializing compiled code.\n"); Microcode_Termination (TERM_EXIT); } } return; } unsigned long DEFUN (find_compiled_block, (name), char * name) { tree_node node = (tree_lookup (compiled_blocks_tree, name)); if (node == ((tree_node) NULL)) return (max_compiled_blocks); else return (node->value); } int DEFUN (declare_compiled_data, (name, decl_data, data_proc), char * name AND int EXFUN ((* decl_data), (void)) AND SCHEME_OBJECT * EXFUN ((* data_proc), (unsigned long))) { unsigned long slot = (find_compiled_block (name)); if (slot == max_compiled_blocks) return (-1); if ((compiled_blocks_table[slot].constructor != uninitialized_data) && (compiled_blocks_table[slot].constructor != data_proc)) return (-1); compiled_blocks_table[slot].constructor = data_proc; return (* decl_data) (); } SCHEME_OBJECT DEFUN (initialize_subblock, (name), char * name) { SCHEME_OBJECT * ep, * block; unsigned long slot = (find_compiled_block (name)); if (slot == max_compiled_blocks) error_external_return (); ep = ((* compiled_blocks_table[slot].constructor) (compiled_blocks_table[slot].dispatch)); Get_Compiled_Block (block, ep); return (MAKE_POINTER_OBJECT (TC_COMPILED_CODE_BLOCK, block)); } SCHEME_OBJECT * DEFUN (initialize_C_compiled_block, (argno, name), int argno AND char * name) { unsigned long slot; slot = (find_compiled_block (name)); if (slot == max_compiled_blocks) return ((SCHEME_OBJECT *) NULL); return ((* compiled_blocks_table[slot].constructor) (compiled_blocks_table[slot].dispatch)); } int DEFUN (declare_compiled_code, (name, nentries, decl_code, code_proc), char * name AND unsigned long nentries AND int EXFUN ((* decl_code), (void)) AND code_block code_proc) { unsigned long slot = (find_compiled_block (name)); if (slot != max_compiled_blocks) { code_block old_code; old_code = (compiled_entries[compiled_blocks_table[slot].dispatch].code); if (((old_code != unspecified_code) && (old_code != code_proc) && (code_proc != unspecified_code)) || (compiled_blocks_table[slot].nentries != nentries)) return (-1); if (old_code == unspecified_code) { unsigned long counter, limit; counter = compiled_blocks_table[slot].dispatch; limit = (counter + nentries); while (counter < limit) compiled_entries[counter++].code = code_proc; } } else { unsigned long dispatch = max_compiled_entries; unsigned long n_dispatch = (dispatch + nentries); unsigned long block_index = max_compiled_blocks; if (n_dispatch < dispatch) /* Wrap around */ return (-1); if (n_dispatch >= compiled_entries_size) { struct compiled_entry_s * new_entries; unsigned long new_entries_size = ((compiled_entries_size == 0) ? 100 : ((compiled_entries_size * 3) / 2)); if (new_entries_size <= n_dispatch) new_entries_size = (n_dispatch + 1); new_entries = ((struct compiled_entry_s *) (lrealloc (compiled_entries, (new_entries_size * (sizeof (struct compiled_entry_s)))))); if (new_entries == ((struct compiled_entry_s *) NULL)) return (-1); compiled_entries_size = new_entries_size; compiled_entries = new_entries; } if (block_index >= compiled_blocks_table_size) { struct compiled_block_s * new_blocks; unsigned long new_blocks_size = ((compiled_blocks_table_size == 0) ? 10 : ((compiled_blocks_table_size * 3) / 2)); new_blocks = ((struct compiled_block_s *) (lrealloc (compiled_blocks_table, (new_blocks_size * (sizeof (struct compiled_block_s)))))); if (new_blocks == ((struct compiled_block_s *) NULL)) return (-1); compiled_blocks_table_size = new_blocks_size; compiled_blocks_table = new_blocks; } { tree_node new_tree; tree_error_message = ((char *) NULL); new_tree = (tree_insert (compiled_blocks_tree, name, block_index)); if (tree_error_message != ((char *) NULL)) return (-1); compiled_blocks_tree = new_tree; } max_compiled_entries = n_dispatch; max_compiled_blocks = (block_index + 1); compiled_blocks_table[block_index].name = name; compiled_blocks_table[block_index].nentries = nentries; compiled_blocks_table[block_index].dispatch = dispatch; compiled_blocks_table[block_index].constructor = uninitialized_data; for (block_index = dispatch; block_index < n_dispatch; block_index++) { compiled_entries[block_index].code = code_proc; compiled_entries[block_index].dispatch = dispatch; } } return (* decl_code) (); } /* For now */ extern SCHEME_OBJECT * EXFUN (cons_c_code_table, (SCHEME_OBJECT *, SCHEME_OBJECT *, long *)); extern Boolean EXFUN (install_c_code_table, (SCHEME_OBJECT *, long)); static SCHEME_OBJECT * DEFUN (copy_c_code_block_information, (index, start, limit), long index AND SCHEME_OBJECT * start AND SCHEME_OBJECT * limit) { long char_count; char * src, * dest; if (start < limit) *start++ = (LONG_TO_UNSIGNED_FIXNUM (compiled_blocks_table[index].nentries)); src = compiled_blocks_table[index].name; dest = ((char *) start); while ((dest < ((char *) limit)) && ((*dest++ = *src++) != '\0')) ; if (dest >= ((char *) limit)) while (*src++ != '\0') dest += 1; char_count = (dest - ((char *) start)); return (start + (BYTES_TO_WORDS (dest - ((char *) start)))); } SCHEME_OBJECT * DEFUN (cons_c_code_table, (start, limit, length), SCHEME_OBJECT * start AND SCHEME_OBJECT * limit AND long * length) { long count; * length = max_compiled_blocks; if (start < limit) *start++ = (LONG_TO_FIXNUM (initial_entry_number)); for (count = 0; ((count < max_compiled_blocks) && (start < limit)); count++) start = (copy_c_code_block_information (count, start, limit)); return (start); } Boolean DEFUN (install_c_code_table, (table, length), SCHEME_OBJECT * table AND long length) { SCHEME_OBJECT the_fixnum; long count, dumped_initial_entry_number; the_fixnum = *table++; dumped_initial_entry_number = (FIXNUM_TO_LONG (the_fixnum)); if (dumped_initial_entry_number < MAX_TRAMPOLINE) return (false); initial_entry_number = dumped_initial_entry_number; if (compiled_entries != ((struct compiled_entry_s *) NULL)) free (compiled_entries); if (compiled_blocks_table != ((struct compiled_block_s *) NULL)) free (compiled_blocks_table); if (compiled_blocks_tree != ((tree_node) NULL)) tree_free (compiled_blocks_tree); max_compiled_entries = 0; compiled_entries_size = 0; compiled_entries = ((struct compiled_entry_s *) NULL); max_compiled_blocks = 0; compiled_blocks_table_size = 0; compiled_blocks_table = ((struct compiled_block_s *) NULL); compiled_blocks_tree = ((tree_node) NULL); if ((declare_trampoline_block (initial_entry_number)) != 0) return (false); for (count = 0; count < length; count++) { long nentries = (UNSIGNED_FIXNUM_TO_LONG (* table++)); int nlen = (strlen ((char *) table)); char * ncopy = ((char *) (malloc (nlen + 1))); if (ncopy == ((char *) NULL)) return (false); strcpy (ncopy, ((char *) table)); if ((declare_compiled_code (ncopy, nentries, NO_SUBBLOCKS, unspecified_code)) != 0) return (false); table += (BYTES_TO_WORDS (nlen + 1)); } return (true); } #define C_COUNT_TRANSFERS unsigned long c_to_interface_transfers = 0; void DEFUN (C_to_interface, (in_entry), PTR in_entry) { SCHEME_OBJECT * entry = ((SCHEME_OBJECT *) in_entry); while (1) { unsigned long entry_index = (* ((unsigned long *) entry)); #ifdef C_COUNT_TRANSFERS c_to_interface_transfers += 1; #endif /* C_COUNT_TRANSFERS */ if (entry_index < ((unsigned long) max_compiled_entries)) entry = ((* (compiled_entries[entry_index].code)) (entry, compiled_entries[entry_index].dispatch)); else { if (entry != &dummy_entry) { Store_Expression ((SCHEME_OBJECT) entry); C_return_value = (ERR_EXECUTE_MANIFEST_VECTOR); } return; } } } DEFINE_PRIMITIVE ("SWAP-C-COUNTER!", Prim_swap_c_counter, 1, 1, "(new-value)\n\ Set the C transfer counter to new-value. Return the old value.") { unsigned long new_counter, old_counter; PRIMITIVE_HEADER (1); new_counter = (arg_integer (1)); old_counter = c_to_interface_transfers; c_to_interface_transfers = new_counter; PRIMITIVE_RETURN (ulong_to_integer (old_counter)); } typedef SCHEME_OBJECT * EXFUN ((* utility_table_entry), (long, long, long, long)); extern utility_table_entry utility_table[]; SCHEME_OBJECT * DEFUN (invoke_utility, (code, arg1, arg2, arg3, arg4), int code AND long arg1 AND long arg2 AND long arg3 AND long arg4) { return ((* utility_table[code]) (arg1, arg2, arg3, arg4)); } int DEFUN (multiply_with_overflow, (x, y, res), long x AND long y AND long * res) { extern SCHEME_OBJECT EXFUN (Mul, (SCHEME_OBJECT, SCHEME_OBJECT)); SCHEME_OBJECT ans; ans = (Mul ((LONG_TO_FIXNUM (x)), (LONG_TO_FIXNUM (y)))); if (ans == SHARP_F) { /* Bogus... */ (* res) = (x * y); return (1); } else { (* res) = (FIXNUM_TO_LONG (ans)); return (0); } } static unsigned int DEFUN (hex_digit_to_int, (h_digit), char h_digit) { unsigned int digit = ((unsigned int) h_digit); return (((digit >= '0') && (digit <= '9')) ? (digit - '0') : (((digit >= 'A') && (digit <= 'F')) ? ((digit - 'A') + 10) : ((digit - 'a') + 10))); } SCHEME_OBJECT DEFUN (digit_string_to_bit_string, (n_bits, n_digits, digits), long n_bits AND long n_digits AND char * digits) { extern void EXFUN (clear_bit_string, (SCHEME_OBJECT)); extern SCHEME_OBJECT EXFUN (allocate_bit_string, (long)); extern void EXFUN (bit_string_set, (SCHEME_OBJECT, long, int)); SCHEME_OBJECT result = (allocate_bit_string (n_bits)); unsigned int digit, mask; long i, posn; int j; posn = 0; clear_bit_string (result); for (i = 0; i < n_digits; i++) { digit = (hex_digit_to_int (*digits++)); for (j = 0, mask = 1; j < 4; j++, mask = (mask << 1), posn++) if ((digit & mask) != 0) bit_string_set (result, posn, 1); } return (result); } /* This avoids consing the string and symbol if it already exists. */ SCHEME_OBJECT DEFUN (memory_to_symbol, (length, string), long length AND unsigned char * string) { extern SCHEME_OBJECT EXFUN (find_symbol, (long, unsigned char *)); extern SCHEME_OBJECT EXFUN (string_to_symbol, (SCHEME_OBJECT)); SCHEME_OBJECT symbol; symbol = (find_symbol (length, string)); if (symbol != SHARP_F) return (symbol); return (string_to_symbol (memory_to_string (length, string))); } static unsigned int DEFUN (digit_string_producer, (digit_ptr), char ** digit_ptr) { char digit = ** digit_ptr; * digit_ptr = ((* digit_ptr) + 1); return (hex_digit_to_int (digit)); } SCHEME_OBJECT DEFUN (digit_string_to_integer, (negative_p, n_digits, digits), Boolean negative_p AND long n_digits AND char * digits) { char * digit = digits; return (digit_stream_to_bignum (((int) n_digits), digit_string_producer, ((PTR) & digit), 16, ((int) negative_p))); } #ifdef USE_STDARG SCHEME_OBJECT DEFUN (rconsm, (nargs, tail DOTS), int nargs AND SCHEME_OBJECT tail DOTS) { va_list arg_ptr; va_start (arg_ptr, tail); { int i; SCHEME_OBJECT result = tail; for (i = 1; i < nargs; i++) result = (cons ((va_arg (arg_ptr, SCHEME_OBJECT)), result)); va_end (arg_ptr); return (result); } } #else /* not USE_STDARG */ SCHEME_OBJECT rconsm (va_alist) va_dcl { va_list arg_ptr; int nargs; SCHEME_OBJECT tail; va_start (arg_ptr); nargs = (va_arg (arg_ptr, int)); tail = (va_arg (arg_ptr, SCHEME_OBJECT)); { int i; SCHEME_OBJECT result = tail; for (i = 1; i < nargs; i++) result = (cons ((va_arg (arg_ptr, SCHEME_OBJECT)), result)); va_end (arg_ptr); return (result); } } #endif /* USE_STDARG */