/* -*-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 */
syntax highlighted by Code2HTML, v. 0.9.1