~ chicken-core (chicken-5) /runtime.c


    1/* runtime.c - Runtime code for compiler generated executables
    2;
    3; Copyright (c) 2008-2022, The CHICKEN Team
    4; Copyright (c) 2000-2007, Felix L. Winkelmann
    5; All rights reserved.
    6;
    7; Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
    8; conditions are met:
    9;
   10;   Redistributions of source code must retain the above copyright notice, this list of conditions and the following
   11;     disclaimer. 
   12;   Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
   13;     disclaimer in the documentation and/or other materials provided with the distribution. 
   14;   Neither the name of the author nor the names of its contributors may be used to endorse or promote
   15;     products derived from this software without specific prior written permission. 
   16;
   17; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
   18; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
   19; AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
   20; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   21; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   22; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   23; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   24; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   25; POSSIBILITY OF SUCH DAMAGE.
   26*/
   27
   28
   29#include "chicken.h"
   30#include <assert.h>
   31#include <float.h>
   32#include <signal.h>
   33#include <sys/stat.h>
   34#include <strings.h>
   35
   36#ifdef HAVE_SYSEXITS_H
   37# include <sysexits.h>
   38#endif
   39
   40#ifdef __ANDROID__
   41# include <android/log.h>
   42#endif
   43
   44#if !defined(PIC)
   45# define NO_DLOAD2
   46#endif
   47
   48#ifndef NO_DLOAD2
   49# ifdef HAVE_DLFCN_H
   50#  include <dlfcn.h>
   51# endif
   52
   53# ifdef HAVE_DL_H
   54#  include <dl.h>
   55# endif
   56#endif
   57
   58#ifndef EX_SOFTWARE
   59# define EX_SOFTWARE  70
   60#endif
   61
   62#ifndef EOVERFLOW
   63# define EOVERFLOW  0
   64#endif
   65
   66/* TODO: Include sys/select.h? Windows doesn't seem to have it... */
   67#ifndef NO_POSIX_POLL
   68#  include <poll.h>
   69#endif
   70
   71#if !defined(C_NONUNIX)
   72
   73# include <sys/time.h>
   74# include <sys/resource.h>
   75# include <sys/wait.h>
   76# include <fcntl.h>
   77
   78/* ITIMER_PROF is more precise, but Cygwin doesn't support it... */
   79# ifdef __CYGWIN__
   80#  define C_PROFILE_SIGNAL SIGALRM
   81#  define C_PROFILE_TIMER  ITIMER_REAL
   82# else
   83#  define C_PROFILE_SIGNAL SIGPROF
   84#  define C_PROFILE_TIMER  ITIMER_PROF
   85# endif
   86
   87#else
   88
   89# define C_PROFILE_SIGNAL -1          /* Stupid way to avoid error */
   90
   91#ifdef ECOS
   92#include <cyg/kernel/kapi.h>
   93static C_TLS int timezone;
   94#define NSIG                          32
   95#endif
   96
   97#endif
   98
   99#ifndef RTLD_GLOBAL
  100# define RTLD_GLOBAL                   0
  101#endif
  102
  103#ifndef RTLD_NOW
  104# define RTLD_NOW                      0
  105#endif
  106
  107#ifndef RTLD_LOCAL
  108# define RTLD_LOCAL                    0
  109#endif
  110
  111#ifndef RTLD_LAZY
  112# define RTLD_LAZY                     0
  113#endif
  114
  115#if defined(_WIN32) && !defined(__CYGWIN__)
  116/* Include winsock2 to get select() for check_fd_ready() */
  117# include <winsock2.h>
  118# include <windows.h>
  119/* Needed for ERROR_OPERATION_ABORTED */
  120# include <winerror.h>
  121#endif
  122
  123/* For image_info retrieval */
  124#if defined(__HAIKU__)
  125# include <kernel/image.h>
  126#endif
  127
  128/* For _NSGetExecutablePath */
  129#if defined(C_MACOSX)
  130# include <mach-o/dyld.h>
  131#endif
  132
  133/* Parameters: */
  134
  135#define RELAX_MULTIVAL_CHECK
  136
  137#ifdef C_SIXTY_FOUR
  138# define DEFAULT_STACK_SIZE            (1024 * 1024)
  139# define DEFAULT_MAXIMAL_HEAP_SIZE     0x7ffffffffffffff0
  140#else
  141# define DEFAULT_STACK_SIZE            (256 * 1024)
  142# define DEFAULT_MAXIMAL_HEAP_SIZE     0x7ffffff0
  143#endif
  144
  145#define DEFAULT_SYMBOL_TABLE_SIZE      2999
  146#define DEFAULT_KEYWORD_TABLE_SIZE      499
  147#define DEFAULT_HEAP_SIZE              DEFAULT_STACK_SIZE
  148#define MINIMAL_HEAP_SIZE              DEFAULT_STACK_SIZE
  149#define DEFAULT_SCRATCH_SPACE_SIZE     256
  150#define DEFAULT_HEAP_GROWTH            200
  151#define DEFAULT_HEAP_SHRINKAGE         50
  152#define DEFAULT_HEAP_SHRINKAGE_USED    25
  153#define DEFAULT_HEAP_MIN_FREE          (4 * 1024 * 1024)
  154#define HEAP_SHRINK_COUNTS             10
  155#define DEFAULT_FORWARDING_TABLE_SIZE  32
  156#define DEFAULT_COLLECTIBLES_SIZE      1024
  157#define DEFAULT_TRACE_BUFFER_SIZE      16
  158#define MIN_TRACE_BUFFER_SIZE          3
  159
  160#define MAX_HASH_PREFIX                64
  161
  162#define DEFAULT_TEMPORARY_STACK_SIZE   256
  163#define STRING_BUFFER_SIZE             4096
  164#define DEFAULT_MUTATION_STACK_SIZE    1024
  165#define PROFILE_TABLE_SIZE             1024
  166
  167#define MAX_PENDING_INTERRUPTS         100
  168
  169#ifdef C_DOUBLE_IS_32_BITS
  170# define FLONUM_PRINT_PRECISION         7
  171#else
  172# define FLONUM_PRINT_PRECISION         15
  173#endif
  174
  175#define WORDS_PER_FLONUM               C_SIZEOF_FLONUM
  176#define INITIAL_TIMER_INTERRUPT_PERIOD 10000
  177#define HDUMP_TABLE_SIZE               1001
  178
  179/* only for relevant for Windows: */
  180
  181#define MAXIMAL_NUMBER_OF_COMMAND_LINE_ARGUMENTS 256
  182
  183
  184/* Constants: */
  185
  186#ifdef C_SIXTY_FOUR
  187# ifdef C_LLP
  188#  define ALIGNMENT_HOLE_MARKER         ((C_word)0xfffffffffffffffeLL)
  189#  define UWORD_FORMAT_STRING           "0x%016llx"
  190#  define UWORD_COUNT_FORMAT_STRING     "%llu"
  191# else
  192#  define ALIGNMENT_HOLE_MARKER         ((C_word)0xfffffffffffffffeL)
  193#  define UWORD_FORMAT_STRING           "0x%016lx"
  194#  define UWORD_COUNT_FORMAT_STRING     "%lu"
  195# endif
  196#else
  197# define ALIGNMENT_HOLE_MARKER         ((C_word)0xfffffffe)
  198# define UWORD_FORMAT_STRING           "0x%08x"
  199# define UWORD_COUNT_FORMAT_STRING     "%u"
  200#endif
  201
  202#ifdef C_LLP
  203# define LONG_FORMAT_STRING            "%lld"
  204#else
  205# define LONG_FORMAT_STRING            "%ld"
  206#endif
  207
  208#define GC_MINOR           0
  209#define GC_MAJOR           1
  210#define GC_REALLOC         2
  211
  212
  213/* Macros: */
  214
  215#define nmax(x, y)                   ((x) > (y) ? (x) : (y))
  216#define nmin(x, y)                   ((x) < (y) ? (x) : (y))
  217#define percentage(n, p)             ((C_long)(((double)(n) * (double)p) / 100))
  218
  219#define clear_buffer_object(buf, obj) C_migrate_buffer_object(NULL, (C_word *)(buf), C_buf_end(buf), (obj))
  220#define move_buffer_object(ptr, buf, obj) C_migrate_buffer_object(ptr, (C_word *)(buf), C_buf_end(buf), (obj))
  221
  222/* The bignum digit representation is fullword- little endian, so on
  223 * LE machines the halfdigits are numbered in the same order.  On BE
  224 * machines, we must swap the odd and even positions.
  225 */
  226#ifdef C_BIG_ENDIAN
  227#define C_uhword_ref(x, p)           ((C_uhword *)(x))[(p)^1]
  228#else
  229#define C_uhword_ref(x, p)           ((C_uhword *)(x))[(p)]
  230#endif
  231#define C_uhword_set(x, p, d)        (C_uhword_ref(x,p) = (d))
  232
  233#define free_tmp_bignum(b)           C_free((void *)(b))
  234
  235/* Forwarding pointers abuse the fact that objects must be
  236 * word-aligned, so we can just drop the lowest bit.
  237 */
  238#define is_fptr(x)                   (((x) & C_GC_FORWARDING_BIT) != 0)
  239#define ptr_to_fptr(x)               (((C_uword)(x) >> 1) | C_GC_FORWARDING_BIT)
  240#define fptr_to_ptr(x)               ((C_uword)(x) << 1)
  241
  242#define C_check_real(x, w, v)       if(((x) & C_FIXNUM_BIT) != 0) v = C_unfix(x); \
  243                                     else if(C_immediatep(x) || C_block_header(x) != C_FLONUM_TAG) \
  244                                       barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, w, x); \
  245                                     else v = C_flonum_magnitude(x);
  246
  247
  248#define C_pte(name)                  pt[ i ].id = #name; pt[ i++ ].ptr = (void *)name;
  249
  250#ifndef SIGBUS
  251# define SIGBUS                      0
  252#endif
  253
  254#define C_thread_id(x)   C_block_item((x), 14)
  255
  256
  257/* Type definitions: */
  258
  259typedef C_regparm C_word C_fcall (*integer_plusmin_op) (C_word **ptr, C_word n, C_word x, C_word y);
  260
  261typedef struct lf_list_struct
  262{
  263  C_word *lf;
  264  int count;
  265  struct lf_list_struct *next, *prev;
  266  C_PTABLE_ENTRY *ptable;
  267  void *module_handle;
  268  char *module_name;
  269} LF_LIST;
  270
  271typedef struct finalizer_node_struct
  272{
  273  struct finalizer_node_struct
  274    *next,
  275    *previous;
  276  C_word
  277    item,
  278    finalizer;
  279} FINALIZER_NODE;
  280
  281typedef struct trace_info_struct
  282{
  283  /* Either raw_location is set to a C string or NULL */
  284  C_char *raw_location;
  285  /* cooked_location is C_SCHEME_FALSE or a Scheme string (when raw_location is NULL) */
  286  C_word cooked_location, cooked1, cooked2, thread;
  287} TRACE_INFO;
  288
  289typedef struct hdump_bucket_struct
  290{
  291  C_word key;
  292  int count, total;
  293  struct hdump_bucket_struct *next;
  294} HDUMP_BUCKET;
  295
  296typedef struct profile_bucket_struct
  297{
  298  C_char *key;
  299  C_uword sample_count; /* Multiplied by profile freq = time spent */
  300  C_uword call_count;   /* Distinct calls seen while sampling */
  301  struct profile_bucket_struct *next;
  302} PROFILE_BUCKET;
  303
  304
  305/* Variables: */
  306
  307C_TLS C_word
  308  *C_temporary_stack,
  309  *C_temporary_stack_bottom,
  310  *C_temporary_stack_limit,
  311  *C_stack_limit,         /* "Soft" limit, may be reset to force GC */
  312  *C_stack_hard_limit,    /* Actual stack limit */
  313  *C_scratchspace_start,
  314  *C_scratchspace_top,
  315  *C_scratchspace_limit,
  316   C_scratch_usage;
  317C_TLS C_long
  318  C_timer_interrupt_counter,
  319  C_initial_timer_interrupt_period;
  320C_TLS C_byte 
  321  *C_fromspace_top,
  322  *C_fromspace_limit;
  323#ifdef HAVE_SIGSETJMP
  324C_TLS sigjmp_buf C_restart;
  325#else
  326C_TLS jmp_buf C_restart;
  327#endif
  328C_TLS void *C_restart_trampoline;
  329C_TLS C_word C_restart_c;
  330C_TLS int C_entry_point_status;
  331C_TLS int (*C_gc_mutation_hook)(C_word *slot, C_word val);
  332C_TLS void (*C_gc_trace_hook)(C_word *var, int mode);
  333C_TLS void (*C_panic_hook)(C_char *msg) = NULL;
  334C_TLS void (*C_pre_gc_hook)(int mode) = NULL;
  335C_TLS void (*C_post_gc_hook)(int mode, C_long ms) = NULL;
  336C_TLS C_word (*C_debugger_hook)(C_DEBUG_INFO *cell, C_word c, C_word *av, C_char *cloc) = NULL;
  337
  338C_TLS int
  339  C_gui_mode = 0,
  340  C_abort_on_thread_exceptions,
  341  C_interrupts_enabled,
  342  C_disable_overflow_check,
  343  C_heap_size_is_fixed,
  344  C_trace_buffer_size = DEFAULT_TRACE_BUFFER_SIZE,
  345  C_max_pending_finalizers = C_DEFAULT_MAX_PENDING_FINALIZERS,
  346  C_debugging = 0,
  347  C_main_argc;
  348C_TLS C_uword 
  349  C_heap_growth = DEFAULT_HEAP_GROWTH,
  350  C_heap_shrinkage = DEFAULT_HEAP_SHRINKAGE,
  351  C_heap_shrinkage_used = DEFAULT_HEAP_SHRINKAGE_USED,
  352  C_heap_half_min_free = DEFAULT_HEAP_MIN_FREE,
  353  C_maximal_heap_size = DEFAULT_MAXIMAL_HEAP_SIZE,
  354  heap_shrink_counter = 0;
  355C_TLS time_t
  356  C_startup_time_sec,
  357  C_startup_time_msec,
  358  profile_frequency = 10000;
  359C_TLS char 
  360  **C_main_argv,
  361#ifdef SEARCH_EXE_PATH
  362  *C_main_exe = NULL,
  363#endif
  364  *C_dlerror;
  365
  366static C_TLS TRACE_INFO
  367  *trace_buffer,
  368  *trace_buffer_limit,
  369  *trace_buffer_top;
  370
  371static C_TLS C_byte 
  372  *heapspace1, 
  373  *heapspace2,
  374  *fromspace_start,
  375  *tospace_start,
  376  *tospace_top,
  377  *tospace_limit,
  378  *new_tospace_start,
  379  *new_tospace_top,
  380  *new_tospace_limit;
  381static C_TLS C_uword
  382  heapspace1_size,
  383  heapspace2_size,
  384  heap_size,
  385  scratchspace_size,
  386  temporary_stack_size,
  387  fixed_temporary_stack_size = 0,
  388  maximum_heap_usage;
  389static C_TLS C_char
  390  buffer[ STRING_BUFFER_SIZE ],
  391  *private_repository = NULL,
  392  *current_module_name,
  393  *save_string;
  394static C_TLS C_SYMBOL_TABLE
  395  *symbol_table,
  396  *symbol_table_list,
  397  *keyword_table;
  398static C_TLS C_word 
  399  **collectibles,
  400  **collectibles_top,
  401  **collectibles_limit,
  402  **mutation_stack_bottom,
  403  **mutation_stack_limit,
  404  **mutation_stack_top,
  405  *stack_bottom,
  406  weak_pair_chain,
  407  locative_chain,
  408  error_location,
  409  interrupt_hook_symbol,
  410  current_thread_symbol,
  411  error_hook_symbol,
  412  pending_finalizers_symbol,
  413  callback_continuation_stack_symbol,
  414  core_provided_symbol,
  415  u8vector_symbol,
  416  s8vector_symbol,
  417  u16vector_symbol,
  418  s16vector_symbol,
  419  u32vector_symbol,
  420  s32vector_symbol,
  421  u64vector_symbol,
  422  s64vector_symbol,
  423  f32vector_symbol,
  424  f64vector_symbol,
  425  *forwarding_table;
  426static C_TLS int 
  427  trace_buffer_full,
  428  forwarding_table_size,
  429  return_to_host,
  430  page_size,
  431  show_trace,
  432  fake_tty_flag,
  433  debug_mode,
  434  dump_heap_on_exit,
  435  gc_bell,
  436  gc_report_flag = 0,
  437  gc_mode,
  438  gc_count_1,
  439  gc_count_1_total,
  440  gc_count_2,
  441  stack_size_changed,
  442  dlopen_flags,
  443  heap_size_changed,
  444  random_state_initialized = 0,
  445  chicken_is_running,
  446  chicken_ran_once,
  447  pass_serious_signals = 1,
  448  callback_continuation_level;
  449static volatile C_TLS int
  450  serious_signal_occurred = 0,
  451  profiling = 0;
  452static C_TLS unsigned int
  453  mutation_count,
  454  tracked_mutation_count,
  455  stack_check_demand,
  456  stack_size;
  457static C_TLS int chicken_is_initialized;
  458#ifdef HAVE_SIGSETJMP
  459static C_TLS sigjmp_buf gc_restart;
  460#else
  461static C_TLS jmp_buf gc_restart;
  462#endif
  463static C_TLS double
  464  timer_start_ms,
  465  gc_ms,
  466  timer_accumulated_gc_ms,
  467  interrupt_time,
  468  last_interrupt_latency;
  469static C_TLS LF_LIST *lf_list;
  470static C_TLS int signal_mapping_table[ NSIG ];
  471static C_TLS int
  472  live_finalizer_count,
  473  allocated_finalizer_count,
  474  pending_finalizer_count,
  475  callback_returned_flag;
  476static C_TLS C_GC_ROOT *gc_root_list = NULL;
  477static C_TLS FINALIZER_NODE 
  478  *finalizer_list,
  479  *finalizer_free_list,
  480  **pending_finalizer_indices;
  481static C_TLS void *current_module_handle;
  482static C_TLS int flonum_print_precision = FLONUM_PRINT_PRECISION;
  483static C_TLS HDUMP_BUCKET **hdump_table;
  484static C_TLS PROFILE_BUCKET
  485  *next_profile_bucket = NULL,
  486  **profile_table = NULL;
  487static C_TLS int 
  488  pending_interrupts[ MAX_PENDING_INTERRUPTS ],
  489  pending_interrupts_count,
  490  handling_interrupts;
  491static C_TLS C_uword random_state[ C_RANDOM_STATE_SIZE / sizeof(C_uword) ]; 
  492static C_TLS int random_state_index = 0;
  493
  494
  495/* Prototypes: */
  496
  497static void parse_argv(C_char *cmds);
  498static void initialize_symbol_table(void);
  499static void global_signal_handler(int signum);
  500static C_word arg_val(C_char *arg);
  501static void barf(int code, char *loc, ...) C_noret;
  502static void try_extended_number(char *ext_proc_name, C_word c, C_word k, ...) C_noret;
  503static void panic(C_char *msg) C_noret;
  504static void usual_panic(C_char *msg) C_noret;
  505static void horror(C_char *msg) C_noret;
  506static void C_fcall really_mark(C_word *x, C_byte *tgt_space_start, C_byte **tgt_space_top, C_byte *tgt_space_limit) C_regparm;
  507static C_cpsproc(values_continuation) C_noret;
  508static C_word add_symbol(C_word **ptr, C_word key, C_word string, C_SYMBOL_TABLE *stable);
  509static C_regparm int C_fcall C_in_new_heapp(C_word x);
  510static C_regparm C_word bignum_times_bignum_unsigned(C_word **ptr, C_word x, C_word y, C_word negp);
  511static C_regparm C_word bignum_extract_digits(C_word **ptr, C_word n, C_word x, C_word start, C_word end);
  512
  513static C_regparm C_word bignum_times_bignum_karatsuba(C_word **ptr, C_word x, C_word y, C_word negp);
  514static C_word bignum_plus_unsigned(C_word **ptr, C_word x, C_word y, C_word negp);
  515static C_word rat_plusmin_integer(C_word **ptr, C_word rat, C_word i, integer_plusmin_op plusmin_op);
  516static C_word integer_minus_rat(C_word **ptr, C_word i, C_word rat);
  517static C_word rat_plusmin_rat(C_word **ptr, C_word x, C_word y, integer_plusmin_op plusmin_op);
  518static C_word rat_times_integer(C_word **ptr, C_word x, C_word y);
  519static C_word rat_times_rat(C_word **ptr, C_word x, C_word y);
  520static C_word cplx_times(C_word **ptr, C_word rx, C_word ix, C_word ry, C_word iy);
  521static C_word bignum_minus_unsigned(C_word **ptr, C_word x, C_word y);
  522static C_regparm void integer_divrem(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r);
  523static C_regparm C_word bignum_remainder_unsigned_halfdigit(C_word x, C_word y);
  524static C_regparm void bignum_divrem(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r);
  525static C_regparm C_word bignum_divide_burnikel_ziegler(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r);
  526static C_regparm void burnikel_ziegler_3n_div_2n(C_word **ptr, C_word a12, C_word a3, C_word b, C_word b1, C_word b2, C_word n, C_word *q, C_word *r);
  527static C_regparm void burnikel_ziegler_2n_div_1n(C_word **ptr, C_word a, C_word b, C_word b1, C_word b2, C_word n, C_word *q, C_word *r);
  528static C_word rat_cmp(C_word x, C_word y);
  529static void fabs_frexp_to_digits(C_uword exp, double sign, C_uword *start, C_uword *scan);
  530static C_word int_flo_cmp(C_word intnum, C_word flonum);
  531static C_word flo_int_cmp(C_word flonum, C_word intnum);
  532static C_word rat_flo_cmp(C_word ratnum, C_word flonum);
  533static C_word flo_rat_cmp(C_word flonum, C_word ratnum);
  534static C_word basic_cmp(C_word x, C_word y, char *loc, int eqp);
  535static int bignum_cmp_unsigned(C_word x, C_word y);
  536static C_word C_fcall hash_string(int len, C_char *str, C_word m, C_word r, int ci) C_regparm;
  537static C_word C_fcall lookup(C_word key, int len, C_char *str, C_SYMBOL_TABLE *stable) C_regparm;
  538static C_word C_fcall lookup_bucket(C_word sym, C_SYMBOL_TABLE *stable) C_regparm;
  539static double compute_symbol_table_load(double *avg_bucket_len, int *total);
  540static double C_fcall decode_flonum_literal(C_char *str) C_regparm;
  541static C_regparm C_word str_to_bignum(C_word bignum, char *str, char *str_end, int radix);
  542static void C_fcall mark_nested_objects(C_byte *heap_scan_top, C_byte *tgt_space_start, C_byte **tgt_space_top, C_byte *tgt_space_limit) C_regparm;
  543static void C_fcall mark_live_objects(C_byte *tgt_space_start, C_byte **tgt_space_top, C_byte *tgt_space_limit) C_regparm;
  544static void C_fcall mark_live_heap_only_objects(C_byte *tgt_space_start, C_byte **tgt_space_top, C_byte *tgt_space_limit) C_regparm;
  545static C_word C_fcall intern0(C_char *name) C_regparm;
  546static void C_fcall update_weak_pairs(int mode, C_byte *undead_start, C_byte *undead_end) C_regparm;
  547static void C_fcall update_locatives(int mode, C_byte *undead_start, C_byte *undead_end) C_regparm;
  548static LF_LIST *find_module_handle(C_char *name);
  549static void set_profile_timer(C_uword freq);
  550static void take_profile_sample();
  551
  552static C_cpsproc(call_cc_wrapper) C_noret;
  553static C_cpsproc(call_cc_values_wrapper) C_noret;
  554static C_cpsproc(gc_2) C_noret;
  555static C_cpsproc(allocate_vector_2) C_noret;
  556static C_cpsproc(generic_trampoline) C_noret;
  557static void handle_interrupt(void *trampoline) C_noret;
  558static C_cpsproc(callback_return_continuation) C_noret;
  559static C_cpsproc(termination_continuation) C_noret;
  560static C_cpsproc(become_2) C_noret;
  561static C_cpsproc(copy_closure_2) C_noret;
  562static C_cpsproc(dump_heap_state_2) C_noret;
  563static C_cpsproc(sigsegv_trampoline) C_noret;
  564static C_cpsproc(sigill_trampoline) C_noret;
  565static C_cpsproc(sigfpe_trampoline) C_noret;
  566static C_cpsproc(sigbus_trampoline) C_noret;
  567static C_cpsproc(bignum_to_str_2) C_noret;
  568
  569static C_word allocate_tmp_bignum(C_word size, C_word negp, C_word initp);
  570static C_word allocate_scratch_bignum(C_word **ptr, C_word size, C_word negp, C_word initp);
  571static void bignum_digits_destructive_negate(C_word bignum);
  572static C_uword bignum_digits_destructive_scale_up_with_carry(C_uword *start, C_uword *end, C_uword factor, C_uword carry);
  573static C_uword bignum_digits_destructive_scale_down(C_uword *start, C_uword *end, C_uword denominator);
  574static C_uword bignum_digits_destructive_shift_right(C_uword *start, C_uword *end, int shift_right, int negp);
  575static C_uword bignum_digits_destructive_shift_left(C_uword *start, C_uword *end, int shift_left);
  576static C_regparm void bignum_digits_multiply(C_word x, C_word y, C_word result);
  577static void bignum_divide_unsigned(C_word **ptr, C_word num, C_word denom, C_word *q, C_word q_negp, C_word *r, C_word r_negp);
  578static C_regparm void bignum_destructive_divide_unsigned_small(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r);
  579static C_regparm void bignum_destructive_divide_full(C_word numerator, C_word denominator, C_word quotient, C_word remainder, C_word return_remainder);
  580static C_regparm void bignum_destructive_divide_normalized(C_word big_u, C_word big_v, C_word big_q);
  581
  582static C_PTABLE_ENTRY *create_initial_ptable();
  583
  584#if !defined(NO_DLOAD2) && (defined(HAVE_DLFCN_H) || defined(HAVE_DL_H) || (defined(HAVE_LOADLIBRARY) && defined(HAVE_GETPROCADDRESS)))
  585static void C_ccall dload_2(C_word, C_word *) C_noret;
  586#endif
  587
  588static void
  589C_dbg(C_char *prefix, C_char *fstr, ...)
  590{
  591  va_list va;
  592
  593  va_start(va, fstr);
  594#ifdef __ANDROID__
  595  __android_log_vprint(ANDROID_LOG_DEBUG, prefix, fstr, va);
  596#else
  597  C_fflush(C_stdout);
  598  C_fprintf(C_stderr, "[%s] ", prefix);
  599  C_vfprintf(C_stderr, fstr, va);
  600  C_fflush(C_stderr);
  601#endif
  602  va_end(va);
  603}
  604
  605/* Startup code: */
  606
  607int CHICKEN_main(int argc, char *argv[], void *toplevel) 
  608{
  609  C_word h, s, n;
  610
  611  if(C_gui_mode) {
  612#ifdef _WIN32
  613    parse_argv(GetCommandLine());
  614    argc = C_main_argc;
  615    argv = C_main_argv;
  616#else
  617    /* ??? */
  618#endif
  619  }
  620
  621  pass_serious_signals = 0;
  622  CHICKEN_parse_command_line(argc, argv, &h, &s, &n);
  623  
  624  if(!CHICKEN_initialize(h, s, n, toplevel))
  625    panic(C_text("cannot initialize - out of memory"));
  626
  627  CHICKEN_run(NULL);
  628  return 0;
  629}
  630
  631
  632/* Custom argv parser for Windoze: */
  633
  634void parse_argv(C_char *cmds)
  635{
  636  C_char *ptr = cmds,
  637         *bptr0, *bptr, *aptr;
  638  int n = 0;
  639
  640  C_main_argv = (C_char **)malloc(MAXIMAL_NUMBER_OF_COMMAND_LINE_ARGUMENTS * sizeof(C_char *));
  641
  642  if(C_main_argv == NULL)
  643    panic(C_text("cannot allocate argument-list buffer"));
  644
  645  C_main_argc = 0;
  646
  647  for(;;) {
  648    while(isspace((int)(*ptr))) ++ptr;
  649
  650    if(*ptr == '\0') break;
  651
  652    for(bptr0 = bptr = buffer; !isspace((int)(*ptr)) && *ptr != '\0'; *(bptr++) = *(ptr++))
  653      ++n;
  654
  655    *bptr = '\0';
  656
  657    aptr = (C_char*) malloc(sizeof(C_char) * (n + 1));
  658    if (!aptr)
  659      panic(C_text("cannot allocate argument buffer"));
  660
  661    C_strlcpy(aptr, bptr0, sizeof(C_char) * (n + 1));
  662
  663    C_main_argv[ C_main_argc++ ] = aptr;
  664  }
  665}
  666
  667
  668/* Initialize runtime system: */
  669
  670int CHICKEN_initialize(int heap, int stack, int symbols, void *toplevel)
  671{
  672  C_SCHEME_BLOCK *k0;
  673  int i;
  674#ifdef HAVE_SIGACTION
  675  struct sigaction sa;
  676#endif
  677
  678  /* FIXME Should have C_tzset in chicken.h? */
  679#if defined(__MINGW32__)
  680# if defined(__MINGW64_VERSION_MAJOR)
  681    ULONGLONG tick_count = GetTickCount64();
  682# else
  683    /* mingw32 doesn't yet have GetTickCount64 support */
  684    ULONGLONG tick_count = GetTickCount();
  685# endif
  686  C_startup_time_sec = tick_count / 1000;
  687  C_startup_time_msec = tick_count % 1000;
  688  /* Make sure _tzname, _timezone, and _daylight are set */
  689  _tzset();
  690#else
  691  struct timeval tv;
  692  C_gettimeofday(&tv, NULL);
  693  C_startup_time_sec = tv.tv_sec;
  694  C_startup_time_msec = tv.tv_usec / 1000;
  695  /* Make sure tzname, timezone, and daylight are set */
  696  tzset();
  697#endif
  698
  699  if(chicken_is_initialized) return 1;
  700  else chicken_is_initialized = 1;
  701
  702#if defined(__ANDROID__) && defined(DEBUGBUILD)
  703  debug_mode = 2;
  704#endif
  705
  706  if(debug_mode) 
  707    C_dbg(C_text("debug"), C_text("application startup...\n"));
  708
  709  C_panic_hook = usual_panic;
  710  symbol_table_list = NULL;
  711
  712  symbol_table = C_new_symbol_table(".", symbols ? symbols : DEFAULT_SYMBOL_TABLE_SIZE);
  713
  714  if(symbol_table == NULL)
  715    return 0;
  716
  717  keyword_table = C_new_symbol_table("kw", symbols ? symbols / 4 : DEFAULT_KEYWORD_TABLE_SIZE);
  718
  719  if(keyword_table == NULL)
  720    return 0;
  721
  722  page_size = 0;
  723  stack_size = stack ? stack : DEFAULT_STACK_SIZE;
  724  C_set_or_change_heap_size(heap ? heap : DEFAULT_HEAP_SIZE, 0);
  725
  726  /* Allocate temporary stack: */
  727  temporary_stack_size = fixed_temporary_stack_size ? fixed_temporary_stack_size : DEFAULT_TEMPORARY_STACK_SIZE;
  728  if((C_temporary_stack_limit = (C_word *)C_malloc(temporary_stack_size * sizeof(C_word))) == NULL)
  729    return 0;
  730  
  731  C_temporary_stack_bottom = C_temporary_stack_limit + temporary_stack_size;
  732  C_temporary_stack = C_temporary_stack_bottom;
  733  
  734  /* Allocate mutation stack: */
  735  mutation_stack_bottom = (C_word **)C_malloc(DEFAULT_MUTATION_STACK_SIZE * sizeof(C_word *));
  736
  737  if(mutation_stack_bottom == NULL) return 0;
  738
  739  mutation_stack_top = mutation_stack_bottom;
  740  mutation_stack_limit = mutation_stack_bottom + DEFAULT_MUTATION_STACK_SIZE;
  741  C_gc_mutation_hook = NULL;
  742  C_gc_trace_hook = NULL;
  743
  744  /* Initialize finalizer lists: */
  745  finalizer_list = NULL;
  746  finalizer_free_list = NULL;
  747  pending_finalizer_indices =
  748      (FINALIZER_NODE **)C_malloc(C_max_pending_finalizers * sizeof(FINALIZER_NODE *));
  749
  750  if(pending_finalizer_indices == NULL) return 0;
  751
  752  /* Initialize forwarding table: */
  753  forwarding_table =
  754      (C_word *)C_malloc((DEFAULT_FORWARDING_TABLE_SIZE + 1) * 2 * sizeof(C_word));
  755
  756  if(forwarding_table == NULL) return 0;
  757  
  758  *forwarding_table = 0;
  759  forwarding_table_size = DEFAULT_FORWARDING_TABLE_SIZE;
  760
  761  /* Setup collectibles: */
  762  collectibles = (C_word **)C_malloc(sizeof(C_word *) * DEFAULT_COLLECTIBLES_SIZE);
  763
  764  if(collectibles == NULL) return 0;
  765
  766  collectibles_top = collectibles;
  767  collectibles_limit = collectibles + DEFAULT_COLLECTIBLES_SIZE;
  768  gc_root_list = NULL;
  769 
  770#if !defined(NO_DLOAD2) && defined(HAVE_DLFCN_H)
  771  dlopen_flags = RTLD_LAZY | RTLD_GLOBAL;
  772#else
  773  dlopen_flags = 0;
  774#endif
  775
  776#ifdef HAVE_SIGACTION
  777    sa.sa_flags = 0;
  778    sigfillset(&sa.sa_mask); /* See note in C_establish_signal_handler() */
  779    sa.sa_handler = global_signal_handler;
  780#endif
  781
  782  /* setup signal handlers */
  783  if(!pass_serious_signals) {
  784#ifdef HAVE_SIGACTION
  785    C_sigaction(SIGBUS, &sa, NULL);
  786    C_sigaction(SIGFPE, &sa, NULL);
  787    C_sigaction(SIGILL, &sa, NULL);
  788    C_sigaction(SIGSEGV, &sa, NULL);
  789#else
  790    C_signal(SIGBUS, global_signal_handler);
  791    C_signal(SIGILL, global_signal_handler);
  792    C_signal(SIGFPE, global_signal_handler);
  793    C_signal(SIGSEGV, global_signal_handler);
  794#endif
  795  }
  796
  797  tracked_mutation_count = mutation_count = gc_count_1 = gc_count_1_total = gc_count_2 = maximum_heap_usage = 0;
  798  lf_list = NULL;
  799  C_register_lf2(NULL, 0, create_initial_ptable());
  800  C_restart_trampoline = (void *)toplevel;
  801  trace_buffer = NULL;
  802  C_clear_trace_buffer();
  803  chicken_is_running = chicken_ran_once = 0;
  804  pending_interrupts_count = 0;
  805  handling_interrupts = 0;
  806  last_interrupt_latency = 0;
  807  C_interrupts_enabled = 1;
  808  C_initial_timer_interrupt_period = INITIAL_TIMER_INTERRUPT_PERIOD;
  809  C_timer_interrupt_counter = INITIAL_TIMER_INTERRUPT_PERIOD;
  810  memset(signal_mapping_table, 0, sizeof(int) * NSIG);
  811  C_dlerror = "cannot load compiled code dynamically - this is a statically linked executable";
  812  error_location = C_SCHEME_FALSE;
  813  C_pre_gc_hook = NULL;
  814  C_post_gc_hook = NULL;
  815  C_scratchspace_start = NULL;
  816  C_scratchspace_top = NULL;
  817  C_scratchspace_limit = NULL;
  818  C_scratch_usage = 0;
  819  scratchspace_size = 0;
  820  live_finalizer_count = 0;
  821  allocated_finalizer_count = 0;
  822  current_module_name = NULL;
  823  current_module_handle = NULL;
  824  callback_continuation_level = 0;
  825  weak_pair_chain = (C_word)NULL;
  826  locative_chain = (C_word)NULL;
  827  gc_ms = 0;
  828  if (!random_state_initialized) {
  829    srand(time(NULL));
  830    random_state_initialized = 1;
  831  }
  832
  833  for(i = 0; i < C_RANDOM_STATE_SIZE / sizeof(C_uword); ++i)
  834    random_state[ i ] = rand();
  835
  836  initialize_symbol_table();
  837
  838  if (profiling) {
  839#ifndef C_NONUNIX
  840# ifdef HAVE_SIGACTION
  841    C_sigaction(C_PROFILE_SIGNAL, &sa, NULL);
  842# else
  843    C_signal(C_PROFILE_SIGNAL, global_signal_handler);
  844# endif
  845#endif
  846
  847    profile_table = (PROFILE_BUCKET **)C_malloc(PROFILE_TABLE_SIZE * sizeof(PROFILE_BUCKET *));
  848
  849    if(profile_table == NULL)
  850      panic(C_text("out of memory - can not allocate profile table"));
  851
  852    C_memset(profile_table, 0, sizeof(PROFILE_BUCKET *) * PROFILE_TABLE_SIZE);
  853  }
  854  
  855  /* create k to invoke code for system-startup: */
  856  k0 = (C_SCHEME_BLOCK *)C_align((C_word)C_fromspace_top);
  857  C_fromspace_top += C_align(2 * sizeof(C_word));
  858  k0->header = C_CLOSURE_TYPE | 1;
  859  C_set_block_item(k0, 0, (C_word)termination_continuation);
  860  C_save(k0);
  861  C_save(C_SCHEME_UNDEFINED);
  862  C_restart_c = 2;
  863  return 1;
  864}
  865
  866
  867void *C_get_statistics(void) {
  868  static void *stats[ 8 ];
  869
  870  stats[ 0 ] = fromspace_start;
  871  stats[ 1 ] = C_fromspace_limit;
  872  stats[ 2 ] = C_scratchspace_start;
  873  stats[ 3 ] = C_scratchspace_limit;
  874  stats[ 4 ] = C_stack_limit;
  875  stats[ 5 ] = stack_bottom;
  876  stats[ 6 ] = C_fromspace_top;
  877  stats[ 7 ] = C_scratchspace_top;
  878  return stats;
  879}
  880
  881
  882static C_PTABLE_ENTRY *create_initial_ptable()
  883{
  884  /* IMPORTANT: hardcoded table size -
  885     this must match the number of C_pte calls + 1 (NULL terminator)! */
  886  C_PTABLE_ENTRY *pt = (C_PTABLE_ENTRY *)C_malloc(sizeof(C_PTABLE_ENTRY) * 63);
  887  int i = 0;
  888
  889  if(pt == NULL)
  890    panic(C_text("out of memory - cannot create initial ptable"));
  891
  892  C_pte(termination_continuation);
  893  C_pte(callback_return_continuation);
  894  C_pte(values_continuation);
  895  C_pte(call_cc_values_wrapper);
  896  C_pte(call_cc_wrapper);
  897  C_pte(C_gc);
  898  C_pte(C_allocate_vector);
  899  C_pte(C_make_structure);
  900  C_pte(C_ensure_heap_reserve);
  901  C_pte(C_return_to_host);
  902  C_pte(C_get_symbol_table_info);
  903  C_pte(C_get_memory_info);
  904  C_pte(C_decode_seconds);
  905  C_pte(C_stop_timer);
  906  C_pte(C_dload);
  907  C_pte(C_set_dlopen_flags);
  908  C_pte(C_become);
  909  C_pte(C_apply_values);
  910  C_pte(C_times);
  911  C_pte(C_minus);
  912  C_pte(C_plus);
  913  C_pte(C_nequalp);
  914  C_pte(C_greaterp);
  915  /* IMPORTANT: have you read the comments at the start and the end of this function? */
  916  C_pte(C_lessp);
  917  C_pte(C_greater_or_equal_p);
  918  C_pte(C_less_or_equal_p);
  919  C_pte(C_number_to_string);
  920  C_pte(C_make_symbol);
  921  C_pte(C_string_to_symbol);
  922  C_pte(C_string_to_keyword);
  923  C_pte(C_apply);
  924  C_pte(C_call_cc);
  925  C_pte(C_values);
  926  C_pte(C_call_with_values);
  927  C_pte(C_continuation_graft);
  928  C_pte(C_open_file_port);
  929  C_pte(C_software_type);
  930  C_pte(C_machine_type);
  931  C_pte(C_machine_byte_order);
  932  C_pte(C_software_version);
  933  C_pte(C_build_platform);
  934  C_pte(C_make_pointer);
  935  /* IMPORTANT: have you read the comments at the start and the end of this function? */
  936  C_pte(C_make_tagged_pointer);
  937  C_pte(C_peek_signed_integer);
  938  C_pte(C_peek_unsigned_integer);
  939  C_pte(C_peek_int64);
  940  C_pte(C_peek_uint64);
  941  C_pte(C_context_switch);
  942  C_pte(C_register_finalizer);
  943  C_pte(C_copy_closure);
  944  C_pte(C_dump_heap_state);
  945  C_pte(C_filter_heap_objects);
  946  C_pte(C_fixnum_to_string);
  947  C_pte(C_integer_to_string);
  948  C_pte(C_flonum_to_string);
  949  C_pte(C_signum);
  950  C_pte(C_quotient_and_remainder);
  951  C_pte(C_u_integer_quotient_and_remainder);
  952  C_pte(C_bitwise_and);
  953  C_pte(C_bitwise_ior);
  954  C_pte(C_bitwise_xor);
  955
  956  /* IMPORTANT: did you remember the hardcoded pte table size? */
  957  pt[ i ].id = NULL;
  958  return pt;
  959}
  960
  961
  962void *CHICKEN_new_gc_root_2(int finalizable)
  963{
  964  C_GC_ROOT *r = (C_GC_ROOT *)C_malloc(sizeof(C_GC_ROOT));
  965
  966  if(r == NULL)
  967    panic(C_text("out of memory - cannot allocate GC root"));
  968
  969  r->value = C_SCHEME_UNDEFINED;
  970  r->next = gc_root_list;
  971  r->prev = NULL;
  972  r->finalizable = finalizable;
  973
  974  if(gc_root_list != NULL) gc_root_list->prev = r;
  975
  976  gc_root_list = r;
  977  return (void *)r;
  978}
  979
  980
  981void *CHICKEN_new_gc_root()
  982{
  983  return CHICKEN_new_gc_root_2(0);
  984}
  985
  986
  987void *CHICKEN_new_finalizable_gc_root()
  988{
  989  return CHICKEN_new_gc_root_2(1);
  990}
  991
  992
  993void CHICKEN_delete_gc_root(void *root)
  994{
  995  C_GC_ROOT *r = (C_GC_ROOT *)root;
  996
  997  if(r->prev == NULL) gc_root_list = r->next;
  998  else r->prev->next = r->next;
  999
  1000  if(r->next != NULL) r->next->prev = r->prev;
 1001
 1002  C_free(root);
 1003}
 1004
 1005
 1006void *CHICKEN_global_lookup(char *name)
 1007{
 1008  int 
 1009    len = C_strlen(name),
 1010    key = hash_string(len, name, symbol_table->size, symbol_table->rand, 0);
 1011  C_word s;
 1012  void *root = CHICKEN_new_gc_root();
 1013
 1014  if(C_truep(s = lookup(key, len, name, symbol_table))) {
 1015    if(C_block_item(s, 0) != C_SCHEME_UNBOUND) {
 1016      CHICKEN_gc_root_set(root, s);
 1017      return root;
 1018    }
 1019  }
 1020
 1021  return NULL;
 1022}
 1023
 1024
 1025int CHICKEN_is_running()
 1026{
 1027  return chicken_is_running;
 1028}
 1029
 1030
 1031void CHICKEN_interrupt()
 1032{
 1033  C_timer_interrupt_counter = 0;
 1034}
 1035
 1036
 1037C_regparm C_SYMBOL_TABLE *C_new_symbol_table(char *name, unsigned int size)
 1038{
 1039  C_SYMBOL_TABLE *stp;
 1040  int i;
 1041
 1042  if((stp = C_find_symbol_table(name)) != NULL) return stp;
 1043
 1044  if((stp = (C_SYMBOL_TABLE *)C_malloc(sizeof(C_SYMBOL_TABLE))) == NULL)
 1045    return NULL;
 1046
 1047  stp->name = name;
 1048  stp->size = size;
 1049  stp->next = symbol_table_list;
 1050  stp->rand = rand();
 1051
 1052  if((stp->table = (C_word *)C_malloc(size * sizeof(C_word))) == NULL)
 1053    return NULL;
 1054
 1055  for(i = 0; i < stp->size; stp->table[ i++ ] = C_SCHEME_END_OF_LIST);
 1056
 1057  symbol_table_list = stp;
 1058  return stp;
 1059}  
 1060
 1061
 1062C_regparm C_SYMBOL_TABLE *C_find_symbol_table(char *name)
 1063{
 1064  C_SYMBOL_TABLE *stp;
 1065
 1066  for(stp = symbol_table_list; stp != NULL; stp = stp->next)
 1067    if(!C_strcmp(name, stp->name)) return stp;
 1068
 1069  return NULL;
 1070}
 1071
 1072
 1073C_regparm C_word C_find_symbol(C_word str, C_SYMBOL_TABLE *stable)
 1074{
 1075  C_char *sptr = C_c_string(str);
 1076  int len = C_header_size(str);
 1077  int key;
 1078  C_word s;
 1079
 1080  if(stable == NULL) stable = symbol_table;
 1081
 1082  key = hash_string(len, sptr, stable->size, stable->rand, 0);
 1083
 1084  if(C_truep(s = lookup(key, len, sptr, stable))) return s;
 1085  else return C_SCHEME_FALSE;
 1086}
 1087
 1088
 1089/* Setup symbol-table with internally used symbols; */
 1090
 1091void initialize_symbol_table(void)
 1092{
 1093  int i;
 1094
 1095  for(i = 0; i < symbol_table->size; symbol_table->table[ i++ ] = C_SCHEME_END_OF_LIST);
 1096
 1097  /* Obtain reference to hooks for later: */
 1098  core_provided_symbol = C_intern2(C_heaptop, C_text("##core#provided"));
 1099  interrupt_hook_symbol = C_intern2(C_heaptop, C_text("##sys#interrupt-hook"));
 1100  error_hook_symbol = C_intern2(C_heaptop, C_text("##sys#error-hook"));
 1101  callback_continuation_stack_symbol = C_intern3(C_heaptop, C_text("##sys#callback-continuation-stack"), C_SCHEME_END_OF_LIST);
 1102  pending_finalizers_symbol = C_intern2(C_heaptop, C_text("##sys#pending-finalizers"));
 1103  current_thread_symbol = C_intern3(C_heaptop, C_text("##sys#current-thread"), C_SCHEME_FALSE);
 1104
 1105  /* SRFI-4 tags */
 1106  u8vector_symbol = C_intern2(C_heaptop, C_text("u8vector"));
 1107  s8vector_symbol = C_intern2(C_heaptop, C_text("s8vector"));
 1108  u16vector_symbol = C_intern2(C_heaptop, C_text("u16vector"));
 1109  s16vector_symbol = C_intern2(C_heaptop, C_text("s16vector"));
 1110  u32vector_symbol = C_intern2(C_heaptop, C_text("u32vector"));
 1111  s32vector_symbol = C_intern2(C_heaptop, C_text("s32vector"));
 1112  u64vector_symbol = C_intern2(C_heaptop, C_text("u64vector"));
 1113  s64vector_symbol = C_intern2(C_heaptop, C_text("s64vector"));
 1114  f32vector_symbol = C_intern2(C_heaptop, C_text("f32vector"));
 1115  f64vector_symbol = C_intern2(C_heaptop, C_text("f64vector"));
 1116}
 1117
 1118
 1119C_regparm C_word C_find_keyword(C_word str, C_SYMBOL_TABLE *kwtable)
 1120{
 1121  C_char *sptr = C_c_string(str);
 1122  int len = C_header_size(str);
 1123  int key;
 1124  C_word s;
 1125
 1126  if(kwtable == NULL) kwtable = keyword_table;
 1127
 1128  key = hash_string(len, sptr, kwtable->size, kwtable->rand, 0);
 1129
 1130  if(C_truep(s = lookup(key, len, sptr, kwtable))) return s;
 1131  else return C_SCHEME_FALSE;
 1132}
 1133
 1134
 1135void C_ccall sigsegv_trampoline(C_word c, C_word *av)
 1136{
 1137  barf(C_MEMORY_VIOLATION_ERROR, NULL);
 1138}
 1139
 1140
 1141void C_ccall sigbus_trampoline(C_word c, C_word *av)
 1142{
 1143  barf(C_BUS_ERROR, NULL);
 1144}
 1145
 1146
 1147void C_ccall sigfpe_trampoline(C_word c, C_word *av)
 1148{
 1149  barf(C_FLOATING_POINT_EXCEPTION_ERROR, NULL);
 1150}
 1151
 1152
 1153void C_ccall sigill_trampoline(C_word c, C_word *av)
 1154{
 1155  barf(C_ILLEGAL_INSTRUCTION_ERROR, NULL);
 1156}
 1157
 1158
 1159/* This is called from POSIX signals: */
 1160
 1161void global_signal_handler(int signum)
 1162{
 1163#if defined(HAVE_SIGPROCMASK)
 1164  if(signum == SIGSEGV || signum == SIGFPE || signum == SIGILL || signum == SIGBUS) {
 1165    sigset_t sset;
 1166    
 1167    if(serious_signal_occurred || !chicken_is_running) {
 1168      switch(signum) {
 1169      case SIGSEGV: panic(C_text("unrecoverable segmentation violation"));
 1170      case SIGFPE: panic(C_text("unrecoverable floating-point exception"));
 1171      case SIGILL: panic(C_text("unrecoverable illegal instruction error"));
 1172      case SIGBUS: panic(C_text("unrecoverable bus error"));
 1173      default: panic(C_text("unrecoverable serious condition"));
 1174      }
 1175    }
 1176    else serious_signal_occurred = 1;
 1177
 1178    /* unblock signal to avoid nested invocation of the handler */
 1179    sigemptyset(&sset);
 1180    sigaddset(&sset, signum);
 1181    C_sigprocmask(SIG_UNBLOCK, &sset, NULL);
 1182
 1183    switch(signum) {
 1184    case SIGSEGV: C_reclaim(sigsegv_trampoline, 0);
 1185    case SIGFPE: C_reclaim(sigfpe_trampoline, 0);
 1186    case SIGILL: C_reclaim(sigill_trampoline, 0);
 1187    case SIGBUS: C_reclaim(sigbus_trampoline, 0);
 1188    default: panic(C_text("invalid serious signal"));
 1189    }
 1190  }
 1191#endif
 1192
 1193  /* TODO: Make full use of sigaction: check that /our/ timer expired */
 1194  if (signum == C_PROFILE_SIGNAL && profiling) take_profile_sample();
 1195  else C_raise_interrupt(signal_mapping_table[ signum ]);
 1196
 1197#ifndef HAVE_SIGACTION
 1198  /* not necessarily needed, but older UNIXen may not leave the handler installed: */
 1199  C_signal(signum, global_signal_handler);
 1200#endif
 1201}
 1202
 1203
 1204/* Align memory to page boundary */
 1205
 1206static void *align_to_page(void *mem)
 1207{
 1208  return (void *)C_align((C_uword)mem);
 1209}
 1210
 1211
 1212static C_byte *
 1213heap_alloc (size_t size, C_byte **page_aligned)
 1214{
 1215  C_byte *p;
 1216  p = (C_byte *)C_malloc (size + page_size);
 1217
 1218  if (p != NULL && page_aligned) *page_aligned = align_to_page (p);
 1219
 1220  return p;
 1221}
 1222
 1223
 1224static void
 1225heap_free (C_byte *ptr, size_t size)
 1226{
 1227  C_free (ptr);
 1228}
 1229
 1230
 1231static C_byte *
 1232heap_realloc (C_byte *ptr, size_t old_size,
 1233	      size_t new_size, C_byte **page_aligned)
 1234{
 1235  C_byte *p;
 1236  p = (C_byte *)C_realloc (ptr, new_size + page_size);
 1237
 1238  if (p != NULL && page_aligned) *page_aligned = align_to_page (p);
 1239
 1240  return p;
 1241}
 1242
 1243
 1244/* Modify heap size at runtime: */
 1245
 1246void C_set_or_change_heap_size(C_word heap, int reintern)
 1247{
 1248  C_byte *ptr1, *ptr2, *ptr1a, *ptr2a;
 1249  C_word size = heap / 2;
 1250
 1251  if(heap_size_changed && fromspace_start) return;
 1252
 1253  if(fromspace_start && heap_size >= heap) return;
 1254
 1255  if(debug_mode)
 1256    C_dbg(C_text("debug"), C_text("heap resized to " UWORD_COUNT_FORMAT_STRING " bytes\n"), heap);
 1257
 1258  heap_size = heap;
 1259
 1260  if((ptr1 = heap_realloc (fromspace_start,
 1261			   C_fromspace_limit - fromspace_start,
 1262			   size, &ptr1a)) == NULL ||
 1263     (ptr2 = heap_realloc (tospace_start,
 1264			   tospace_limit - tospace_start,
 1265			   size, &ptr2a)) == NULL)
 1266    panic(C_text("out of memory - cannot allocate heap"));
 1267
 1268  heapspace1 = ptr1;
 1269  heapspace1_size = size;
 1270  heapspace2 = ptr2;
 1271  heapspace2_size = size;
 1272  fromspace_start = ptr1a;
 1273  C_fromspace_top = fromspace_start;
 1274  C_fromspace_limit = fromspace_start + size;
 1275  tospace_start = ptr2a;
 1276  tospace_top = tospace_start;
 1277  tospace_limit = tospace_start + size;
 1278  mutation_stack_top = mutation_stack_bottom;
 1279
 1280  if(reintern) initialize_symbol_table();
 1281}
 1282 
 1283
 1284/* Modify stack-size at runtime: */
 1285
 1286void C_do_resize_stack(C_word stack)
 1287{
 1288  C_uword old = stack_size,
 1289          diff = stack - old;
 1290
 1291  if(diff != 0 && !stack_size_changed) {
 1292    if(debug_mode) 
 1293      C_dbg(C_text("debug"), C_text("stack resized to " UWORD_COUNT_FORMAT_STRING " bytes\n"), stack);
 1294
 1295    stack_size = stack;
 1296
 1297#if C_STACK_GROWS_DOWNWARD
 1298    C_stack_hard_limit = (C_word *)((C_byte *)C_stack_hard_limit - diff);
 1299#else
 1300    C_stack_hard_limit = (C_word *)((C_byte *)C_stack_hard_limit + diff);
 1301#endif
 1302    C_stack_limit = C_stack_hard_limit;
 1303  }
 1304}
 1305
 1306
 1307/* Check whether nursery is sufficiently big: */
 1308
 1309void C_check_nursery_minimum(C_word words)
 1310{
 1311  if(words >= C_bytestowords(stack_size))
 1312    panic(C_text("nursery is too small - try higher setting using the `-:s' option"));
 1313}
 1314
 1315C_word C_resize_pending_finalizers(C_word size) {
 1316  int sz = C_num_to_int(size);
 1317
 1318  FINALIZER_NODE **newmem = 
 1319    (FINALIZER_NODE **)C_realloc(pending_finalizer_indices, sz * sizeof(FINALIZER_NODE *));
 1320  
 1321  if (newmem == NULL)
 1322    return C_SCHEME_FALSE;
 1323
 1324  pending_finalizer_indices = newmem;
 1325  C_max_pending_finalizers = sz;
 1326  return C_SCHEME_TRUE;
 1327}
 1328
 1329
 1330/* Parse runtime options from command-line: */
 1331
 1332void CHICKEN_parse_command_line(int argc, char *argv[], C_word *heap, C_word *stack, C_word *symbols)
 1333{
 1334  int i;
 1335  char *ptr;
 1336  C_word x;
 1337
 1338  C_main_argc = argc;
 1339  C_main_argv = argv;
 1340
 1341  *heap = DEFAULT_HEAP_SIZE;
 1342  *stack = DEFAULT_STACK_SIZE;
 1343  *symbols = DEFAULT_SYMBOL_TABLE_SIZE;
 1344
 1345  for(i = 1; i < C_main_argc; ++i) {
 1346    if (strncmp(C_main_argv[ i ], C_text("-:"), 2))
 1347      break; /* Stop parsing on first non-runtime option */
 1348
 1349    ptr = &C_main_argv[ i ][ 2 ];
 1350    if (*ptr == '\0')
 1351      break; /* Also stop parsing on first "empty" option (i.e. "-:") */
 1352
 1353    do {
 1354      switch(*(ptr++)) {
 1355      case '?':
 1356        C_dbg("Runtime options", "\n\n"
 1357              " -:?              display this text\n"
 1358              " -:c              always treat stdin as console\n"
 1359              " -:d              enable debug output\n"
 1360              " -:D              enable more debug output\n"
 1361              " -:g              show GC information\n"
 1362              " -:o              disable stack overflow checks\n"
 1363              " -:hiSIZE         set initial heap size\n"
 1364              " -:hmSIZE         set maximal heap size\n"
 1365              " -:hfSIZE         set minimum unused heap size\n"
 1366              " -:hgPERCENTAGE   set heap growth percentage\n"
 1367              " -:hsPERCENTAGE   set heap shrink percentage\n"
 1368              " -:huPERCENTAGE   set percentage of memory used at which heap will be shrunk\n"
 1369              " -:hSIZE          set fixed heap size\n"
 1370              " -:r              write trace output to stderr\n"
 1371              " -:RSEED          initialize rand() seed with SEED (helpful for benchmark stability)\n"
 1372              " -:p              collect statistical profile and write to file at exit\n"
 1373              " -:PFREQUENCY     like -:p, specifying sampling frequency in us (default: 10000)\n"
 1374              " -:sSIZE          set nursery (stack) size\n"
 1375              " -:tSIZE          set symbol-table size\n"
 1376              " -:fSIZE          set maximal number of pending finalizers\n"
 1377              " -:x              deliver uncaught exceptions of other threads to primordial one\n"
 1378              " -:B              sound bell on major GC\n"
 1379              " -:G              force GUI mode\n"
 1380              " -:aSIZE          set trace-buffer/call-chain size\n"
 1381              " -:ASIZE          set fixed temporary stack size\n"
 1382              " -:H              dump heap state on exit\n"
 1383              " -:S              do not handle segfaults or other serious conditions\n"
 1384              "\n  SIZE may have a `k' (`K'), `m' (`M') or `g' (`G') suffix, meaning size\n"
 1385              "  times 1024, 1048576, and 1073741824, respectively.\n\n");
 1386        C_exit_runtime(C_fix(0));
 1387
 1388      case 'h':
 1389        switch(*ptr) {
 1390        case 'i':
 1391          *heap = arg_val(ptr + 1); 
 1392          heap_size_changed = 1;
 1393          goto next;
 1394        case 'f':
 1395          C_heap_half_min_free = arg_val(ptr + 1);
 1396          goto next;
 1397        case 'g':
 1398          C_heap_growth = arg_val(ptr + 1);
 1399          goto next;
 1400        case 'm':
 1401          C_maximal_heap_size = arg_val(ptr + 1);
 1402          goto next;
 1403        case 's':
 1404          C_heap_shrinkage = arg_val(ptr + 1);
 1405          goto next;
 1406        case 'u':
 1407          C_heap_shrinkage_used = arg_val(ptr + 1);
 1408          goto next;
 1409        default:
 1410          *heap = arg_val(ptr); 
 1411          heap_size_changed = 1;
 1412          C_heap_size_is_fixed = 1;
 1413          goto next;
 1414        }
 1415
 1416      case 'o':
 1417        C_disable_overflow_check = 1;
 1418        break;
 1419
 1420      case 'B':
 1421        gc_bell = 1;
 1422        break;
 1423
 1424      case 'G':
 1425        C_gui_mode = 1;
 1426        break;
 1427
 1428      case 'H':
 1429        dump_heap_on_exit = 1;
 1430        break;
 1431
 1432      case 'S':
 1433        pass_serious_signals = 1;
 1434        break;
 1435
 1436      case 's':
 1437        *stack = arg_val(ptr);
 1438        stack_size_changed = 1;
 1439        goto next;
 1440
 1441      case 'f':
 1442        C_max_pending_finalizers = arg_val(ptr);
 1443        goto next;
 1444
 1445      case 'a':
 1446        C_trace_buffer_size = arg_val(ptr);
 1447        goto next;
 1448
 1449      case 'A':
 1450        fixed_temporary_stack_size = arg_val(ptr);
 1451        goto next;
 1452
 1453      case 't':
 1454        *symbols = arg_val(ptr);
 1455        goto next;
 1456
 1457      case 'c':
 1458        fake_tty_flag = 1;
 1459        break;
 1460
 1461      case 'd':
 1462        debug_mode = 1;
 1463        break;
 1464
 1465      case 'D':
 1466        debug_mode = 2;
 1467        break;
 1468
 1469      case 'g':
 1470        gc_report_flag = 2;
 1471        break;
 1472
 1473      case 'P':
 1474        profiling = 1;
 1475        profile_frequency = arg_val(ptr);
 1476        goto next;
 1477
 1478      case 'p':
 1479        profiling = 1;
 1480        break;
 1481
 1482      case 'r':
 1483        show_trace = 1;
 1484        break;
 1485
 1486      case 'R':
 1487        srand((unsigned int)arg_val(ptr));
 1488        random_state_initialized = 1;
 1489        goto next;
 1490
 1491      case 'x':
 1492        C_abort_on_thread_exceptions = 1;
 1493        break;
 1494
 1495      default: panic(C_text("illegal runtime option"));
 1496      }
 1497    } while(*ptr != '\0');
 1498
 1499    next:;
 1500    }
 1501}
 1502
 1503
 1504C_word arg_val(C_char *arg)
 1505{
 1506  int len;
 1507  C_char *end;
 1508  C_long val, mul = 1;
 1509
 1510  if (arg == NULL) panic(C_text("illegal runtime-option argument"));
 1511      
 1512  len = C_strlen(arg);
 1513      
 1514  if(len < 1) panic(C_text("illegal runtime-option argument"));
 1515      
 1516  switch(arg[ len - 1 ]) {
 1517  case 'k':
 1518  case 'K': mul = 1024; break;
 1519 	  
 1520  case 'm':
 1521  case 'M': mul = 1024 * 1024; break;
 1522 	  
 1523  case 'g':
 1524  case 'G': mul = 1024 * 1024 * 1024; break;
 1525
 1526  default: mul = 1;
 1527  }
 1528
 1529  val = C_strtow(arg, &end, 10);
 1530
 1531  if((mul != 1 ? end[ 1 ] != '\0' : end[ 0 ] != '\0')) 
 1532    panic(C_text("invalid runtime-option argument suffix"));
 1533
 1534  return val * mul;
 1535}
 1536
 1537
 1538/* Run embedded code with arguments: */
 1539
 1540C_word CHICKEN_run(void *toplevel)
 1541{
 1542  if(!chicken_is_initialized && !CHICKEN_initialize(0, 0, 0, toplevel))
 1543    panic(C_text("could not initialize"));
 1544
 1545  if(chicken_is_running)
 1546    panic(C_text("re-invocation of Scheme world while process is already running"));
 1547
 1548  chicken_is_running = chicken_ran_once = 1;
 1549  return_to_host = 0;
 1550
 1551  if(profiling) set_profile_timer(profile_frequency);
 1552
 1553#if C_STACK_GROWS_DOWNWARD
 1554  C_stack_hard_limit = (C_word *)((C_byte *)C_stack_pointer - stack_size);
 1555#else
 1556  C_stack_hard_limit = (C_word *)((C_byte *)C_stack_pointer + stack_size);
 1557#endif
 1558  C_stack_limit = C_stack_hard_limit;
 1559
 1560  stack_bottom = C_stack_pointer;
 1561
 1562  if(debug_mode)
 1563    C_dbg(C_text("debug"), C_text("stack bottom is 0x%lx\n"), (C_word)stack_bottom);
 1564
 1565  /* The point of (usually) no return... */
 1566#ifdef HAVE_SIGSETJMP
 1567  C_sigsetjmp(C_restart, 0);
 1568#else
 1569  C_setjmp(C_restart);
 1570#endif
 1571
 1572  serious_signal_occurred = 0;
 1573
 1574  if(!return_to_host) {
 1575    /* We must copy the argvector onto the stack, because
 1576     * any subsequent save() will otherwise clobber it.
 1577     */
 1578    C_word *p = C_alloc(C_restart_c);
 1579    assert(C_restart_c == (C_temporary_stack_bottom - C_temporary_stack));
 1580    C_memcpy(p, C_temporary_stack, C_restart_c * sizeof(C_word));
 1581    C_temporary_stack = C_temporary_stack_bottom;
 1582    ((C_proc)C_restart_trampoline)(C_restart_c, p);
 1583  }
 1584
 1585  if(profiling) set_profile_timer(0);
 1586
 1587  chicken_is_running = 0;
 1588  return C_restore;
 1589}
 1590
 1591
 1592C_word CHICKEN_continue(C_word k)
 1593{
 1594  if(C_temporary_stack_bottom != C_temporary_stack)
 1595    panic(C_text("invalid temporary stack level"));
 1596
 1597  if(!chicken_is_initialized)
 1598    panic(C_text("runtime system has not been initialized - `CHICKEN_run' has probably not been called"));
 1599
 1600  C_save(k);
 1601  return CHICKEN_run(NULL);
 1602}
 1603
 1604
 1605/* The final continuation: */
 1606
 1607void C_ccall termination_continuation(C_word c, C_word *av)
 1608{
 1609  if(debug_mode) {
 1610    C_dbg(C_text("debug"), C_text("application terminated normally\n"));
 1611  }
 1612
 1613  C_exit_runtime(C_fix(0));
 1614}
 1615
 1616
 1617/* Signal unrecoverable runtime error: */
 1618
 1619void panic(C_char *msg)
 1620{
 1621  if(C_panic_hook != NULL) C_panic_hook(msg);
 1622
 1623  usual_panic(msg);
 1624}
 1625
 1626
 1627void usual_panic(C_char *msg)
 1628{
 1629  C_char *dmp = C_dump_trace(0);
 1630
 1631  C_dbg_hook(C_SCHEME_UNDEFINED);
 1632
 1633  if(C_gui_mode) {
 1634    C_snprintf(buffer, sizeof(buffer), C_text("%s\n\n%s"), msg, dmp);
 1635#if defined(_WIN32) && !defined(__CYGWIN__)
 1636    MessageBox(NULL, buffer, C_text("CHICKEN runtime"), MB_OK | MB_ICONERROR);
 1637    ExitProcess(1);
 1638#endif
 1639  } /* fall through if not WIN32 GUI app */
 1640
 1641  C_dbg("panic", C_text("%s - execution terminated\n\n%s"), msg, dmp);
 1642  C_exit_runtime(C_fix(1));
 1643}
 1644
 1645
 1646void horror(C_char *msg)
 1647{
 1648  C_dbg_hook(C_SCHEME_UNDEFINED);
 1649
 1650  if(C_gui_mode) {
 1651    C_snprintf(buffer, sizeof(buffer), C_text("%s"), msg);
 1652#if defined(_WIN32) && !defined(__CYGWIN__)
 1653    MessageBox(NULL, buffer, C_text("CHICKEN runtime"), MB_OK | MB_ICONERROR);
 1654    ExitProcess(1);
 1655#endif
 1656  } /* fall through */
 1657
 1658  C_dbg("horror", C_text("\n%s - execution terminated"), msg);  
 1659  C_exit_runtime(C_fix(1));
 1660}
 1661
 1662
 1663/* Error-hook, called from C-level runtime routines: */
 1664
 1665void barf(int code, char *loc, ...)
 1666{
 1667  C_char *msg;
 1668  C_word err = error_hook_symbol;
 1669  int c, i;
 1670  va_list v;
 1671  C_word *av; 
 1672
 1673  C_dbg_hook(C_SCHEME_UNDEFINED);
 1674
 1675  C_temporary_stack = C_temporary_stack_bottom;
 1676  err = C_block_item(err, 0);
 1677
 1678  switch(code) {
 1679  case C_BAD_ARGUMENT_COUNT_ERROR:
 1680    msg = C_text("bad argument count");
 1681    c = 3;
 1682    break;
 1683
 1684  case C_BAD_MINIMUM_ARGUMENT_COUNT_ERROR:
 1685    msg = C_text("too few arguments");
 1686    c = 3;
 1687    break;
 1688  
 1689  case C_BAD_ARGUMENT_TYPE_ERROR:
 1690    msg = C_text("bad argument type");
 1691    c = 1;
 1692    break;
 1693
 1694  case C_UNBOUND_VARIABLE_ERROR:
 1695    msg = C_text("unbound variable");
 1696    c = 1;
 1697    break;
 1698
 1699  case C_BAD_ARGUMENT_TYPE_NO_KEYWORD_ERROR:
 1700    msg = C_text("bad argument type - not a keyword");
 1701    c = 1;
 1702    break;
 1703
 1704  case C_OUT_OF_MEMORY_ERROR:
 1705    msg = C_text("not enough memory");
 1706    c = 0;
 1707    break;
 1708
 1709  case C_DIVISION_BY_ZERO_ERROR:
 1710    msg = C_text("division by zero");
 1711    c = 0;
 1712    break;
 1713
 1714  case C_OUT_OF_RANGE_ERROR:
 1715    msg = C_text("out of range");
 1716    c = 2;
 1717    break;
 1718
 1719  case C_NOT_A_CLOSURE_ERROR:
 1720    msg = C_text("call of non-procedure");
 1721    c = 1;
 1722    break;
 1723
 1724  case C_CONTINUATION_CANT_RECEIVE_VALUES_ERROR:
 1725    msg = C_text("continuation cannot receive multiple values");
 1726    c = 1;
 1727    break;
 1728
 1729  case C_BAD_ARGUMENT_TYPE_CYCLIC_LIST_ERROR:
 1730    msg = C_text("bad argument type - not a non-cyclic list");
 1731    c = 1;
 1732    break;
 1733
 1734  case C_TOO_DEEP_RECURSION_ERROR:
 1735    msg = C_text("recursion too deep");
 1736    c = 0;
 1737    break;
 1738
 1739  case C_CANT_REPRESENT_INEXACT_ERROR:
 1740    msg = C_text("inexact number cannot be represented as an exact number");
 1741    c = 1;
 1742    break;
 1743
 1744  case C_NOT_A_PROPER_LIST_ERROR:
 1745    msg = C_text("bad argument type - not a proper list");
 1746    c = 1;
 1747    break;
 1748
 1749  case C_BAD_ARGUMENT_TYPE_NO_FIXNUM_ERROR:
 1750    msg = C_text("bad argument type - not a fixnum");
 1751    c = 1;
 1752    break;
 1753
 1754  case C_BAD_ARGUMENT_TYPE_NO_STRING_ERROR:
 1755    msg = C_text("bad argument type - not a string");
 1756    c = 1;
 1757    break;
 1758
 1759  case C_BAD_ARGUMENT_TYPE_NO_PAIR_ERROR:
 1760    msg = C_text("bad argument type - not a pair");
 1761    c = 1;
 1762    break;
 1763
 1764  case C_BAD_ARGUMENT_TYPE_NO_BOOLEAN_ERROR:
 1765    msg = C_text("bad argument type - not a boolean");
 1766    c = 1;
 1767    break;
 1768
 1769  case C_BAD_ARGUMENT_TYPE_NO_LOCATIVE_ERROR:
 1770    msg = C_text("bad argument type - not a locative");
 1771    c = 1;
 1772    break;
 1773
 1774  case C_BAD_ARGUMENT_TYPE_NO_LIST_ERROR:
 1775    msg = C_text("bad argument type - not a list");
 1776    c = 1;
 1777    break;
 1778
 1779  case C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR:
 1780    msg = C_text("bad argument type - not a number");
 1781    c = 1;
 1782    break;
 1783
 1784  case C_BAD_ARGUMENT_TYPE_NO_SYMBOL_ERROR:
 1785    msg = C_text("bad argument type - not a symbol");
 1786    c = 1;
 1787    break;
 1788
 1789  case C_BAD_ARGUMENT_TYPE_NO_VECTOR_ERROR:
 1790    msg = C_text("bad argument type - not a vector");
 1791    c = 1;
 1792    break;
 1793
 1794  case C_BAD_ARGUMENT_TYPE_NO_CHAR_ERROR:
 1795    msg = C_text("bad argument type - not a character");
 1796    c = 1;
 1797    break;
 1798
 1799  case C_STACK_OVERFLOW_ERROR:
 1800    msg = C_text("stack overflow");
 1801    c = 0;
 1802    break;
 1803
 1804  case C_BAD_ARGUMENT_TYPE_BAD_STRUCT_ERROR:
 1805    msg = C_text("bad argument type - not a structure of the required type");
 1806    c = 2;
 1807    break;
 1808
 1809  case C_BAD_ARGUMENT_TYPE_NO_BYTEVECTOR_ERROR:
 1810    msg = C_text("bad argument type - not a blob");
 1811    c = 1;
 1812    break;
 1813
 1814  case C_LOST_LOCATIVE_ERROR:
 1815    msg = C_text("locative refers to reclaimed object");
 1816    c = 1;
 1817    break;
 1818
 1819  case C_BAD_ARGUMENT_TYPE_NO_BLOCK_ERROR:
 1820    msg = C_text("bad argument type - not a object");
 1821    c = 1;
 1822    break;
 1823
 1824  case C_BAD_ARGUMENT_TYPE_NO_NUMBER_VECTOR_ERROR:
 1825    msg = C_text("bad argument type - not a number vector");
 1826    c = 2;
 1827    break;
 1828
 1829  case C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR:
 1830    msg = C_text("bad argument type - not an integer");
 1831    c = 1;
 1832    break;
 1833
 1834  case C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR:
 1835    msg = C_text("bad argument type - not an unsigned integer");
 1836    c = 1;
 1837    break;
 1838
 1839  case C_BAD_ARGUMENT_TYPE_NO_POINTER_ERROR:
 1840    msg = C_text("bad argument type - not a pointer");
 1841    c = 1;
 1842    break;
 1843
 1844  case C_BAD_ARGUMENT_TYPE_NO_TAGGED_POINTER_ERROR:
 1845    msg = C_text("bad argument type - not a tagged pointer");
 1846    c = 2;
 1847    break;
 1848
 1849  case C_BAD_ARGUMENT_TYPE_NO_FLONUM_ERROR:
 1850    msg = C_text("bad argument type - not a flonum");
 1851    c = 1;
 1852    break;
 1853
 1854  case C_BAD_ARGUMENT_TYPE_NO_CLOSURE_ERROR:
 1855    msg = C_text("bad argument type - not a procedure");
 1856    c = 1;
 1857    break;
 1858
 1859  case C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR:
 1860    msg = C_text("bad argument type - invalid base");
 1861    c = 1;
 1862    break;
 1863
 1864  case C_CIRCULAR_DATA_ERROR:
 1865    msg = C_text("recursion too deep or circular data encountered");
 1866    c = 0;
 1867    break;
 1868
 1869  case C_BAD_ARGUMENT_TYPE_NO_PORT_ERROR:
 1870    msg = C_text("bad argument type - not a port");
 1871    c = 1;
 1872    break;
 1873
 1874  case C_BAD_ARGUMENT_TYPE_PORT_DIRECTION_ERROR:
 1875    msg = C_text("bad argument type - not a port of the correct type");
 1876    c = 1;
 1877    break;
 1878
 1879  case C_BAD_ARGUMENT_TYPE_PORT_NO_INPUT_ERROR:
 1880    msg = C_text("bad argument type - not an input-port");
 1881    c = 1;
 1882    break;
 1883
 1884  case C_BAD_ARGUMENT_TYPE_PORT_NO_OUTPUT_ERROR:
 1885    msg = C_text("bad argument type - not an output-port");
 1886    c = 1;
 1887    break;
 1888
 1889  case C_PORT_CLOSED_ERROR:
 1890    msg = C_text("port already closed");
 1891    c = 1;
 1892    break;
 1893 
 1894  case C_ASCIIZ_REPRESENTATION_ERROR:
 1895    msg = C_text("cannot represent string with NUL bytes as C string");
 1896    c = 1;
 1897    break;
 1898
 1899  case C_MEMORY_VIOLATION_ERROR:
 1900    msg = C_text("segmentation violation");
 1901    c = 0;
 1902    break;
 1903
 1904  case C_FLOATING_POINT_EXCEPTION_ERROR:
 1905    msg = C_text("floating point exception");
 1906    c = 0;
 1907    break;
 1908
 1909  case C_ILLEGAL_INSTRUCTION_ERROR:
 1910    msg = C_text("illegal instruction");
 1911    c = 0;
 1912    break;
 1913
 1914  case C_BUS_ERROR:
 1915    msg = C_text("bus error");
 1916    c = 0;
 1917    break;
 1918
 1919  case C_BAD_ARGUMENT_TYPE_NO_EXACT_ERROR:
 1920    msg = C_text("bad argument type - not an exact number");
 1921    c = 1;
 1922    break;
 1923
 1924  case C_BAD_ARGUMENT_TYPE_NO_INEXACT_ERROR:
 1925    msg = C_text("bad argument type - not an inexact number");
 1926    c = 1;
 1927    break;
 1928
 1929  case C_BAD_ARGUMENT_TYPE_NO_REAL_ERROR:
 1930    msg = C_text("bad argument type - not an real");
 1931    c = 1;
 1932    break;
 1933
 1934  case C_BAD_ARGUMENT_TYPE_COMPLEX_NO_ORDERING_ERROR:
 1935    msg = C_text("bad argument type - complex number has no ordering");
 1936    c = 1;
 1937    break;
 1938
 1939  case C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR:
 1940    msg = C_text("bad argument type - not an exact integer");
 1941    c = 1;
 1942    break;
 1943
 1944  case C_BAD_ARGUMENT_TYPE_FOREIGN_LIMITATION:
 1945    msg = C_text("number does not fit in foreign type");
 1946    c = 1;
 1947    break;
 1948
 1949  case C_BAD_ARGUMENT_TYPE_COMPLEX_ABS:
 1950    msg = C_text("cannot compute absolute value of complex number");
 1951    c = 1;
 1952    break;
 1953
 1954  case C_REST_ARG_OUT_OF_BOUNDS_ERROR:
 1955    msg = C_text("attempted rest argument access beyond end of list");
 1956    c = 3;
 1957    break;
 1958
 1959  default: panic(C_text("illegal internal error code"));
 1960  }
 1961
 1962  if(C_immediatep(err)) {
 1963    C_dbg(C_text("error"), C_text("%s\n"), msg);
 1964    panic(C_text("`##sys#error-hook' is not defined - the `library' unit was probably not linked with this executable"));
 1965  } else {
 1966    av = C_alloc(c + 4);
 1967    va_start(v, loc);
 1968    av[ 0 ] = err;
 1969    /* No continuation is passed: '##sys#error-hook' may not return: */
 1970    av[ 1 ] = C_SCHEME_UNDEFINED;
 1971    av[ 2 ] = C_fix(code);
 1972    
 1973    if(loc != NULL)
 1974      av[ 3 ] = intern0(loc);
 1975    else {
 1976      av[ 3 ] = error_location;
 1977      error_location = C_SCHEME_FALSE;
 1978    }
 1979
 1980    for(i = 0; i < c; ++i)
 1981      av[ i + 4 ] = va_arg(v, C_word);
 1982
 1983    va_end(v);
 1984    C_do_apply(c + 4, av);
 1985  }
 1986}
 1987
 1988
 1989/* Never use extended number hook procedure names longer than this! */
 1990/* Current longest name: ##sys#integer->string/recursive */
 1991#define MAX_EXTNUM_HOOK_NAME 32
 1992
 1993/* This exists so that we don't have to create any extra closures */
 1994static void try_extended_number(char *ext_proc_name, C_word c, C_word k, ...)
 1995{
 1996  static C_word ab[C_SIZEOF_STRING(MAX_EXTNUM_HOOK_NAME)];
 1997  int i;
 1998  va_list v;
 1999  C_word ext_proc_sym, ext_proc = C_SCHEME_FALSE, *a = ab;
 2000
 2001  ext_proc_sym = C_lookup_symbol(C_intern2(&a, ext_proc_name));
 2002
 2003  if(!C_immediatep(ext_proc_sym))
 2004    ext_proc = C_block_item(ext_proc_sym, 0);
 2005
 2006  if (!C_immediatep(ext_proc) && C_closurep(ext_proc)) {
 2007    C_word *av = C_alloc(c + 1);
 2008    av[ 0 ] = ext_proc;
 2009    av[ 1 ] = k;
 2010    va_start(v, k);
 2011
 2012    for(i = 0; i < c - 1; ++i)
 2013      av[ i + 2 ] = va_arg(v, C_word);
 2014
 2015    va_end(v);
 2016    C_do_apply(c + 1, av);
 2017  } else {
 2018    barf(C_UNBOUND_VARIABLE_ERROR, NULL, ext_proc_sym);
 2019  }
 2020}
 2021
 2022
 2023/* Hook for setting breakpoints */
 2024
 2025C_word C_dbg_hook(C_word dummy)
 2026{
 2027  return dummy;
 2028}
 2029
 2030
 2031/* Timing routines: */
 2032
 2033/* DEPRECATED */
 2034C_regparm C_u64 C_fcall C_milliseconds(void)
 2035{
 2036  return C_current_process_milliseconds();
 2037}
 2038
 2039C_regparm C_u64 C_fcall C_current_process_milliseconds(void)
 2040{
 2041#if defined(__MINGW32__)
 2042# if defined(__MINGW64_VERSION_MAJOR)
 2043    ULONGLONG tick_count = GetTickCount64();
 2044# else
 2045    ULONGLONG tick_count = GetTickCount();
 2046# endif
 2047    return tick_count - (C_startup_time_sec * 1000) - C_startup_time_msec;
 2048#else
 2049    struct timeval tv;
 2050
 2051    if(C_gettimeofday(&tv, NULL) == -1) return 0;
 2052    else return (tv.tv_sec - C_startup_time_sec) * 1000 + tv.tv_usec / 1000 - C_startup_time_msec;
 2053#endif
 2054}
 2055
 2056
 2057C_regparm time_t C_fcall C_seconds(C_long *ms)
 2058{
 2059#ifdef C_NONUNIX
 2060  if(ms != NULL) *ms = 0;
 2061
 2062  return (time_t)(clock() / CLOCKS_PER_SEC);
 2063#else
 2064  struct timeval tv;
 2065
 2066  if(C_gettimeofday(&tv, NULL) == -1) {
 2067    if(ms != NULL) *ms = 0;
 2068
 2069    return (time_t)0;
 2070  }
 2071  else {
 2072    if(ms != NULL) *ms = tv.tv_usec / 1000;
 2073
 2074    return tv.tv_sec;
 2075  }
 2076#endif
 2077}
 2078
 2079
 2080C_regparm C_u64 C_fcall C_cpu_milliseconds(void)
 2081{
 2082#if defined(C_NONUNIX) || defined(__CYGWIN__)
 2083    if(CLOCKS_PER_SEC == 1000) return clock();
 2084    else return ((C_u64)clock() / CLOCKS_PER_SEC) * 1000;
 2085#else
 2086    struct rusage ru;
 2087
 2088    if(C_getrusage(RUSAGE_SELF, &ru) == -1) return 0;
 2089    else return (((C_u64)ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) * 1000
 2090                 + ((C_u64)ru.ru_utime.tv_usec + ru.ru_stime.tv_usec) / 1000);
 2091#endif
 2092}
 2093
 2094
 2095/* Support code for callbacks: */
 2096
 2097int C_fcall C_save_callback_continuation(C_word **ptr, C_word k)
 2098{
 2099  C_word p = C_a_pair(ptr, k, C_block_item(callback_continuation_stack_symbol, 0));
 2100  
 2101  C_mutate_slot(&C_block_item(callback_continuation_stack_symbol, 0), p);
 2102  return ++callback_continuation_level;
 2103}
 2104
 2105
 2106C_word C_fcall C_restore_callback_continuation(void) 
 2107{
 2108  /* obsolete, but retained for keeping old code working */
 2109  C_word p = C_block_item(callback_continuation_stack_symbol, 0),
 2110         k;
 2111
 2112  assert(!C_immediatep(p) && C_header_type(p) == C_PAIR_TYPE);
 2113  k = C_u_i_car(p);
 2114
 2115  C_mutate(&C_block_item(callback_continuation_stack_symbol, 0), C_u_i_cdr(p));
 2116  --callback_continuation_level;
 2117  return k;
 2118}
 2119
 2120
 2121C_word C_fcall C_restore_callback_continuation2(int level) 
 2122{
 2123  C_word p = C_block_item(callback_continuation_stack_symbol, 0),
 2124         k;
 2125
 2126  if(level != callback_continuation_level || C_immediatep(p) || C_header_type(p) != C_PAIR_TYPE)
 2127    panic(C_text("unbalanced callback continuation stack"));
 2128
 2129  k = C_u_i_car(p);
 2130
 2131  C_mutate(&C_block_item(callback_continuation_stack_symbol, 0), C_u_i_cdr(p));
 2132  --callback_continuation_level;
 2133  return k;
 2134}
 2135
 2136
 2137C_word C_fcall C_callback(C_word closure, int argc)
 2138{
 2139#ifdef HAVE_SIGSETJMP
 2140  sigjmp_buf prev;
 2141#else
 2142  jmp_buf prev;
 2143#endif
 2144  C_word 
 2145    *a = C_alloc(C_SIZEOF_CLOSURE(2)),
 2146    k = C_closure(&a, 2, (C_word)callback_return_continuation, C_SCHEME_FALSE),
 2147    *av;
 2148  int old = chicken_is_running;
 2149
 2150  if(old && C_block_item(callback_continuation_stack_symbol, 0) == C_SCHEME_END_OF_LIST)
 2151    panic(C_text("callback invoked in non-safe context"));
 2152
 2153  C_memcpy(&prev, &C_restart, sizeof(C_restart));
 2154  callback_returned_flag = 0;       
 2155  chicken_is_running = 1;
 2156  av = C_alloc(argc + 2);
 2157  av[ 0 ] = closure;
 2158  av[ 1 ] = k;
 2159  /*XXX is the order of arguments an issue? */
 2160  C_memcpy(av + 2, C_temporary_stack, argc * sizeof(C_word));
 2161  C_temporary_stack = C_temporary_stack_bottom;
 2162  
 2163#ifdef HAVE_SIGSETJMP
 2164  if(!C_sigsetjmp(C_restart, 0)) C_do_apply(argc + 2, av);
 2165#else
 2166  if(!C_setjmp(C_restart)) C_do_apply(argc + 2, av);
 2167#endif
 2168
 2169  serious_signal_occurred = 0;
 2170
 2171  if(!callback_returned_flag) {
 2172    /* We must copy the argvector onto the stack, because
 2173     * any subsequent save() will otherwise clobber it.
 2174     */
 2175    C_word *p = C_alloc(C_restart_c);
 2176    assert(C_restart_c == (C_temporary_stack_bottom - C_temporary_stack));
 2177    C_memcpy(p, C_temporary_stack, C_restart_c * sizeof(C_word));
 2178    C_temporary_stack = C_temporary_stack_bottom;
 2179    ((C_proc)C_restart_trampoline)(C_restart_c, p);
 2180  }
 2181  else {
 2182    C_memcpy(&C_restart, &prev, sizeof(C_restart));
 2183    callback_returned_flag = 0;
 2184  }
 2185 
 2186  chicken_is_running = old;
 2187  return C_restore;
 2188}
 2189
 2190
 2191void C_fcall C_callback_adjust_stack(C_word *a, int size)
 2192{
 2193  if(!chicken_is_running && !C_in_stackp((C_word)a)) {
 2194    if(debug_mode)
 2195      C_dbg(C_text("debug"), 
 2196	    C_text("callback invoked in lower stack region - adjusting limits:\n"
 2197		   "[debug]   current:  \t%p\n"
 2198		   "[debug]   previous: \t%p (bottom) - %p (limit)\n"),
 2199	    a, stack_bottom, C_stack_limit);
 2200
 2201#if C_STACK_GROWS_DOWNWARD
 2202    C_stack_hard_limit = (C_word *)((C_byte *)a - stack_size);
 2203    stack_bottom = a + size;
 2204#else
 2205    C_stack_hard_limit = (C_word *)((C_byte *)a + stack_size);
 2206    stack_bottom = a;
 2207#endif
 2208    C_stack_limit = C_stack_hard_limit;
 2209
 2210    if(debug_mode)
 2211      C_dbg(C_text("debug"), C_text("new:      \t%p (bottom) - %p (limit)\n"),
 2212	    stack_bottom, C_stack_limit);
 2213  }
 2214}
 2215
 2216
 2217C_word C_fcall C_callback_wrapper(void *proc, int argc)
 2218{
 2219  C_word
 2220    *a = C_alloc(C_SIZEOF_CLOSURE(1)),
 2221    closure = C_closure(&a, 1, (C_word)proc),
 2222    result;
 2223
 2224  result = C_callback(closure, argc);
 2225  assert(C_temporary_stack == C_temporary_stack_bottom);
 2226  return result;
 2227}
 2228
 2229
 2230void C_ccall callback_return_continuation(C_word c, C_word *av)
 2231{
 2232  C_word self = av[0];
 2233  C_word r = av[1];
 2234
 2235  if(C_block_item(self, 1) == C_SCHEME_TRUE)
 2236    panic(C_text("callback returned twice"));
 2237
 2238  assert(callback_returned_flag == 0);
 2239  callback_returned_flag = 1;
 2240  C_set_block_item(self, 1, C_SCHEME_TRUE);
 2241  C_save(r);
 2242  C_reclaim(NULL, 0);
 2243}
 2244
 2245
 2246/* Register/unregister literal frame: */
 2247
 2248void C_initialize_lf(C_word *lf, int count)
 2249{
 2250  while(count-- > 0)
 2251    *(lf++) = C_SCHEME_UNBOUND;
 2252}
 2253
 2254
 2255void *C_register_lf(C_word *lf, int count)
 2256{
 2257  return C_register_lf2(lf, count, NULL);
 2258}
 2259
 2260
 2261void *C_register_lf2(C_word *lf, int count, C_PTABLE_ENTRY *ptable)
 2262{
 2263  LF_LIST *node = (LF_LIST *)C_malloc(sizeof(LF_LIST));
 2264  LF_LIST *np;
 2265  int status = 0;
 2266
 2267  node->lf = lf;
 2268  node->count = count;
 2269  node->ptable = ptable;
 2270  node->module_name = current_module_name;
 2271  node->module_handle = current_module_handle;
 2272  current_module_handle = NULL;
 2273
 2274  if(lf_list) lf_list->prev = node;
 2275
 2276  node->next = lf_list;
 2277  node->prev = NULL;
 2278  lf_list = node;
 2279  return (void *)node;
 2280}
 2281
 2282
 2283LF_LIST *find_module_handle(char *name)
 2284{
 2285  LF_LIST *np;
 2286
 2287  for(np = lf_list; np != NULL; np = np->next) {
 2288    if(np->module_name != NULL && !C_strcmp(np->module_name, name)) 
 2289      return np;
 2290  }
 2291
 2292  return NULL;
 2293}
 2294
 2295
 2296void C_unregister_lf(void *handle)
 2297{
 2298  LF_LIST *node = (LF_LIST *) handle;
 2299
 2300  if (node->next) node->next->prev = node->prev;
 2301
 2302  if (node->prev) node->prev->next = node->next;
 2303
 2304  if (lf_list == node) lf_list = node->next;
 2305
 2306  C_free(node->module_name);
 2307  C_free(node);
 2308}
 2309
 2310
 2311/* Intern symbol into symbol-table: */
 2312
 2313C_regparm C_word C_fcall C_intern(C_word **ptr, int len, C_char *str) 
 2314{
 2315  return C_intern_in(ptr, len, str, symbol_table);
 2316}
 2317
 2318
 2319C_regparm C_word C_fcall C_h_intern(C_word *slot, int len, C_char *str)
 2320{
 2321  return C_h_intern_in(slot, len, str, symbol_table);
 2322}
 2323
 2324
 2325C_regparm C_word C_fcall C_intern_kw(C_word **ptr, int len, C_char *str) 
 2326{
 2327  C_word kw = C_intern_in(ptr, len, str, keyword_table);
 2328  C_set_block_item(kw, 0, kw); /* Keywords evaluate to themselves */
 2329  C_set_block_item(kw, 2, C_SCHEME_FALSE); /* Keywords have no plists */
 2330  return kw;
 2331}
 2332
 2333
 2334C_regparm C_word C_fcall C_h_intern_kw(C_word *slot, int len, C_char *str)
 2335{
 2336  C_word kw = C_h_intern_in(slot, len, str, keyword_table);
 2337  C_set_block_item(kw, 0, kw); /* Keywords evaluate to themselves */
 2338  C_set_block_item(kw, 2, C_SCHEME_FALSE); /* Keywords have no plists */
 2339  return kw;
 2340}
 2341
 2342C_regparm C_word C_fcall C_intern_in(C_word **ptr, int len, C_char *str, C_SYMBOL_TABLE *stable)
 2343{
 2344  int key;
 2345  C_word s;
 2346
 2347  if(stable == NULL) stable = symbol_table;
 2348
 2349  key = hash_string(len, str, stable->size, stable->rand, 0);
 2350
 2351  if(C_truep(s = lookup(key, len, str, stable))) return s;
 2352
 2353  s = C_string(ptr, len, str);
 2354  return add_symbol(ptr, key, s, stable);
 2355}
 2356
 2357
 2358C_regparm C_word C_fcall C_h_intern_in(C_word *slot, int len, C_char *str, C_SYMBOL_TABLE *stable)
 2359{
 2360  /* Intern as usual, but remember slot, and allocate in static
 2361   * memory.  If symbol already exists, replace its string by a fresh
 2362   * statically allocated string to ensure it never gets collected, as
 2363   * lf[] entries are not tracked by the GC.
 2364   */
 2365  int key;
 2366  C_word s;
 2367
 2368  if(stable == NULL) stable = symbol_table;
 2369
 2370  key = hash_string(len, str, stable->size, stable->rand, 0);
 2371
 2372  if(C_truep(s = lookup(key, len, str, stable))) {
 2373    if(C_in_stackp(s)) C_mutate_slot(slot, s);
 2374    
 2375    if(!C_truep(C_permanentp(C_symbol_name(s)))) {
 2376      /* Replace by statically allocated string, and persist it */
 2377      C_set_block_item(s, 1, C_static_string(C_heaptop, len, str));
 2378      C_i_persist_symbol(s);
 2379    }
 2380    return s;
 2381  }
 2382
 2383  s = C_static_string(C_heaptop, len, str);
 2384  return add_symbol(C_heaptop, key, s, stable);
 2385}
 2386
 2387
 2388C_regparm C_word C_fcall intern0(C_char *str)
 2389{
 2390  int len = C_strlen(str);
 2391  int key = hash_string(len, str, symbol_table->size, symbol_table->rand, 0);
 2392  C_word s;
 2393
 2394  if(C_truep(s = lookup(key, len, str, symbol_table))) return s;
 2395  else return C_SCHEME_FALSE;
 2396}
 2397
 2398
 2399C_regparm C_word C_fcall C_lookup_symbol(C_word sym)
 2400{
 2401  int key;
 2402  C_word str = C_block_item(sym, 1);
 2403  int len = C_header_size(str);
 2404
 2405  key = hash_string(len, C_c_string(str), symbol_table->size, symbol_table->rand, 0);
 2406
 2407  return lookup(key, len, C_c_string(str), symbol_table);
 2408}
 2409
 2410
 2411C_regparm C_word C_fcall C_intern2(C_word **ptr, C_char *str)
 2412{
 2413  return C_intern_in(ptr, C_strlen(str), str, symbol_table);
 2414}
 2415
 2416
 2417C_regparm C_word C_fcall C_intern3(C_word **ptr, C_char *str, C_word value)
 2418{
 2419  C_word s = C_intern_in(ptr, C_strlen(str), str, symbol_table);
 2420  
 2421  C_mutate(&C_block_item(s,0), value);
 2422  C_i_persist_symbol(s); /* Symbol has a value now; persist it */
 2423  return s;
 2424}
 2425
 2426
 2427C_regparm C_word C_fcall hash_string(int len, C_char *str, C_word m, C_word r, int ci)
 2428{
 2429  C_uword key = r;
 2430
 2431  if (ci)
 2432    while(len--) key ^= (key << 6) + (key >> 2) + C_tolower((int)(*str++));
 2433  else
 2434    while(len--) key ^= (key << 6) + (key >> 2) + *(str++);
 2435
 2436  return (C_word)(key % (C_uword)m);
 2437}
 2438
 2439
 2440C_regparm C_word C_fcall lookup(C_word key, int len, C_char *str, C_SYMBOL_TABLE *stable)
 2441{
 2442  C_word bucket, last = 0, sym, s;
 2443
 2444  for(bucket = stable->table[ key ]; bucket != C_SCHEME_END_OF_LIST; 
 2445      bucket = C_block_item(bucket,1)) {
 2446    sym = C_block_item(bucket,0);
 2447
 2448    /* If the symbol is unreferenced, drop it: */
 2449    if (sym == C_SCHEME_BROKEN_WEAK_PTR) {
 2450       if (last) C_set_block_item(last, 1, C_block_item(bucket, 1));
 2451       else stable->table[ key ] = C_block_item(bucket,1);
 2452    } else {
 2453      last = bucket;
 2454      s = C_block_item(sym, 1);
 2455
 2456      if(C_header_size(s) == (C_word)len
 2457         && !C_memcmp(str, (C_char *)C_data_pointer(s), len))
 2458        return sym;
 2459    }
 2460  }
 2461
 2462  return C_SCHEME_FALSE;
 2463}
 2464
 2465/* Mark a symbol as "persistent", to prevent it from being GC'ed */
 2466C_regparm C_word C_fcall C_i_persist_symbol(C_word sym)
 2467{
 2468  C_word bucket;
 2469  C_SYMBOL_TABLE *stp;
 2470
 2471  /* Normally, this will get called with a symbol, but in
 2472   * C_h_intern_kw we may call it with keywords too.
 2473   */
 2474  if(!C_truep(C_i_symbolp(sym)) && !C_truep(C_i_keywordp(sym))) {
 2475    error_location = C_SCHEME_FALSE;
 2476    barf(C_BAD_ARGUMENT_TYPE_NO_SYMBOL_ERROR, NULL, sym);
 2477  }
 2478
 2479  for(stp = symbol_table_list; stp != NULL; stp = stp->next) {
 2480    bucket = lookup_bucket(sym, stp);
 2481
 2482    if (C_truep(bucket)) {
 2483      /* Change weak to strong ref to ensure long-term survival */
 2484      C_block_header(bucket) = C_block_header(bucket) & ~C_SPECIALBLOCK_BIT;
 2485      /* Ensure survival on next minor GC */
 2486      if (C_in_stackp(sym)) C_mutate_slot(&C_block_item(bucket, 0), sym);
 2487    }
 2488  }
 2489  return C_SCHEME_UNDEFINED;
 2490}
 2491
 2492/* Possibly remove "persistence" of symbol, to allowed it to be GC'ed.
 2493 * This is only done if the symbol is unbound, has an empty plist and
 2494 * is allocated in managed memory.
 2495 */
 2496C_regparm C_word C_fcall C_i_unpersist_symbol(C_word sym)
 2497{
 2498  C_word bucket;
 2499  C_SYMBOL_TABLE *stp;
 2500
 2501  C_i_check_symbol(sym);
 2502
 2503  if (C_persistable_symbol(sym) ||
 2504      C_truep(C_permanentp(C_symbol_name(sym)))) {
 2505    return C_SCHEME_FALSE;
 2506  }
 2507
 2508  for(stp = symbol_table_list; stp != NULL; stp = stp->next) {
 2509    bucket = lookup_bucket(sym, NULL);
 2510
 2511    if (C_truep(bucket)) {
 2512      /* Turn it into a weak ref */
 2513      C_block_header(bucket) = C_block_header(bucket) | C_SPECIALBLOCK_BIT;
 2514      return C_SCHEME_TRUE;
 2515    }
 2516  }
 2517  return C_SCHEME_FALSE;
 2518}
 2519
 2520C_regparm C_word C_fcall lookup_bucket(C_word sym, C_SYMBOL_TABLE *stable)
 2521{
 2522  C_word bucket, str = C_block_item(sym, 1);
 2523  int key, len = C_header_size(str);
 2524
 2525  if (stable == NULL) stable = symbol_table;
 2526
 2527  key = hash_string(len, C_c_string(str), stable->size, stable->rand, 0);
 2528
 2529  for(bucket = stable->table[ key ]; bucket != C_SCHEME_END_OF_LIST;
 2530      bucket = C_block_item(bucket,1)) {
 2531    if (C_block_item(bucket,0) == sym) return bucket;
 2532  }
 2533  return C_SCHEME_FALSE;
 2534}
 2535
 2536
 2537double compute_symbol_table_load(double *avg_bucket_len, int *total_n)
 2538{
 2539  C_word bucket, last;
 2540  int i, j, alen = 0, bcount = 0, total = 0;
 2541
 2542  for(i = 0; i < symbol_table->size; ++i) {
 2543    last = 0;
 2544    j = 0;
 2545    for(bucket = symbol_table->table[ i ]; bucket != C_SCHEME_END_OF_LIST; 
 2546        bucket = C_block_item(bucket,1)) {
 2547      /* If the symbol is unreferenced, drop it: */
 2548      if (C_block_item(bucket,0) == C_SCHEME_BROKEN_WEAK_PTR) {
 2549         if (last) C_set_block_item(last, 1, C_block_item(bucket, 1));
 2550         else symbol_table->table[ i ] = C_block_item(bucket,1);
 2551      } else {
 2552        last = bucket;
 2553        ++j;
 2554      }
 2555    }
 2556
 2557    if(j > 0) {
 2558      alen += j;
 2559      ++bcount;
 2560    }
 2561
 2562    total += j;
 2563  }
 2564
 2565  if(avg_bucket_len != NULL)
 2566    *avg_bucket_len = (double)alen / (double)bcount;
 2567
 2568  *total_n = total;
 2569
 2570  /* return load: */
 2571  return (double)total / (double)symbol_table->size;
 2572}
 2573
 2574
 2575C_word add_symbol(C_word **ptr, C_word key, C_word string, C_SYMBOL_TABLE *stable)
 2576{
 2577  C_word bucket, sym, b2, *p;
 2578
 2579  p = *ptr;
 2580  sym = (C_word)p;
 2581  p += C_SIZEOF_SYMBOL;
 2582  C_block_header_init(sym, C_SYMBOL_TYPE | (C_SIZEOF_SYMBOL - 1));
 2583  C_set_block_item(sym, 0, C_SCHEME_UNBOUND);
 2584  C_set_block_item(sym, 1, string);
 2585  C_set_block_item(sym, 2, C_SCHEME_END_OF_LIST);
 2586  *ptr = p;
 2587  b2 = stable->table[ key ];	/* previous bucket */
 2588
 2589  /* Create new weak or strong bucket depending on persistability */
 2590  if (C_truep(C_permanentp(string))) {
 2591    bucket = C_a_pair(ptr, sym, b2);
 2592  } else {
 2593    bucket = C_a_weak_pair(ptr, sym, b2);
 2594  }
 2595
 2596  if(ptr != C_heaptop) C_mutate_slot(&stable->table[ key ], bucket);
 2597  else {
 2598    /* If a stack-allocated bucket was here, and we allocate from 
 2599       heap-top (say, in a toplevel literal frame allocation) then we have
 2600       to inform the memory manager that a 2nd gen. block points to a 
 2601       1st gen. block, hence the mutation: */
 2602    C_mutate(&C_block_item(bucket,1), b2);
 2603    stable->table[ key ] = bucket;
 2604  }
 2605
 2606  return sym;
 2607}
 2608
 2609
 2610C_regparm int C_in_stackp(C_word x)
 2611{
 2612  C_word *ptr = (C_word *)(C_uword)x;
 2613
 2614#if C_STACK_GROWS_DOWNWARD
 2615  return ptr >= C_stack_pointer_test && ptr <= stack_bottom;
 2616#else
 2617  return ptr < C_stack_pointer_test && ptr >= stack_bottom;
 2618#endif
 2619}
 2620
 2621
 2622C_regparm int C_fcall C_in_heapp(C_word x)
 2623{
 2624  C_byte *ptr = (C_byte *)(C_uword)x;
 2625  return (ptr >= fromspace_start && ptr < C_fromspace_limit) ||
 2626         (ptr >= tospace_start && ptr < tospace_limit);
 2627}
 2628
 2629/* Only used during major GC (heap realloc) */
 2630static C_regparm int C_fcall C_in_new_heapp(C_word x)
 2631{
 2632  C_byte *ptr = (C_byte *)(C_uword)x;
 2633  return (ptr >= new_tospace_start && ptr < new_tospace_limit);
 2634}
 2635
 2636C_regparm int C_fcall C_in_fromspacep(C_word x)
 2637{
 2638  C_byte *ptr = (C_byte *)(C_uword)x;
 2639  return (ptr >= fromspace_start && ptr < C_fromspace_limit);
 2640}
 2641
 2642C_regparm int C_fcall C_in_scratchspacep(C_word x)
 2643{
 2644  C_word *ptr = (C_word *)(C_uword)x;
 2645  return (ptr >= C_scratchspace_start && ptr < C_scratchspace_limit);
 2646}
 2647
 2648/* Cons the rest-aguments together: */
 2649
 2650C_regparm C_word C_fcall C_build_rest(C_word **ptr, C_word c, C_word n, C_word *av)
 2651{
 2652  C_word
 2653    x = C_SCHEME_END_OF_LIST,
 2654    *p = *ptr;
 2655  C_SCHEME_BLOCK *node;
 2656
 2657  av += c;
 2658
 2659  while(--c >= n) {
 2660    node = (C_SCHEME_BLOCK *)p;
 2661    p += 3;
 2662    node->header = C_PAIR_TYPE | (C_SIZEOF_PAIR - 1);
 2663    node->data[ 0 ] = *(--av);
 2664    node->data[ 1 ] = x;
 2665    x = (C_word)node;
 2666  }
 2667
 2668  *ptr = p;
 2669  return x;
 2670}
 2671
 2672
 2673/* Print error messages and exit: */
 2674
 2675void C_bad_memory(void)
 2676{
 2677  panic(C_text("there is not enough stack-space to run this executable"));
 2678}
 2679
 2680
 2681void C_bad_memory_2(void)
 2682{
 2683  panic(C_text("there is not enough heap-space to run this executable - try using the '-:h...' option"));
 2684}
 2685
 2686
 2687/* The following two can be thrown out in the next release... */
 2688
 2689void C_bad_argc(int c, int n)
 2690{
 2691  C_bad_argc_2(c, n, C_SCHEME_FALSE);
 2692}
 2693
 2694
 2695void C_bad_min_argc(int c, int n)
 2696{
 2697  C_bad_min_argc_2(c, n, C_SCHEME_FALSE);
 2698}
 2699
 2700
 2701void C_bad_argc_2(int c, int n, C_word closure)
 2702{
 2703  barf(C_BAD_ARGUMENT_COUNT_ERROR, NULL, C_fix(n - 2), C_fix(c - 2), closure);
 2704}
 2705
 2706
 2707void C_bad_min_argc_2(int c, int n, C_word closure)
 2708{
 2709  barf(C_BAD_MINIMUM_ARGUMENT_COUNT_ERROR, NULL, C_fix(n - 2), C_fix(c - 2), closure);
 2710}
 2711
 2712
 2713void C_stack_overflow(C_char *loc)
 2714{
 2715  barf(C_STACK_OVERFLOW_ERROR, loc);
 2716}
 2717
 2718
 2719void C_unbound_error(C_word sym)
 2720{
 2721  barf(C_UNBOUND_VARIABLE_ERROR, NULL, sym);
 2722}
 2723
 2724
 2725void C_no_closure_error(C_word x)
 2726{
 2727  barf(C_NOT_A_CLOSURE_ERROR, NULL, x);
 2728}
 2729
 2730
 2731void C_div_by_zero_error(char *loc)
 2732{
 2733  barf(C_DIVISION_BY_ZERO_ERROR, loc);
 2734}
 2735
 2736void C_not_an_integer_error(char *loc, C_word x)
 2737{
 2738  barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, loc, x);
 2739}
 2740
 2741void C_not_an_uinteger_error(char *loc, C_word x)
 2742{
 2743  barf(C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR, loc, x);
 2744}
 2745
 2746void C_rest_arg_out_of_bounds_error(C_word c, C_word n, C_word ka)
 2747{
 2748  C_rest_arg_out_of_bounds_error_2(c, n, ka, C_SCHEME_FALSE);
 2749}
 2750
 2751void C_rest_arg_out_of_bounds_error_2(C_word c, C_word n, C_word ka, C_word closure)
 2752{
 2753  barf(C_REST_ARG_OUT_OF_BOUNDS_ERROR, NULL, C_u_fixnum_difference(c, ka), C_u_fixnum_difference(n, ka), closure);
 2754}
 2755
 2756/* Allocate and initialize record: */
 2757
 2758C_regparm C_word C_fcall C_string(C_word **ptr, int len, C_char *str)
 2759{
 2760  C_word strblock = (C_word)(*ptr);
 2761
 2762  *ptr = (C_word *)((C_word)(*ptr) + sizeof(C_header) + C_align(len));
 2763  C_block_header_init(strblock, C_STRING_TYPE | len);
 2764  C_memcpy(C_data_pointer(strblock), str, len);
 2765  return strblock;
 2766}
 2767
 2768
 2769C_regparm C_word C_fcall C_static_string(C_word **ptr, int len, C_char *str)
 2770{
 2771  C_word *dptr = (C_word *)C_malloc(sizeof(C_header) + C_align(len));
 2772  C_word strblock;
 2773
 2774  if(dptr == NULL)
 2775    panic(C_text("out of memory - cannot allocate static string"));
 2776    
 2777  strblock = (C_word)dptr;
 2778  C_block_header_init(strblock, C_STRING_TYPE | len);
 2779  C_memcpy(C_data_pointer(strblock), str, len);
 2780  return strblock;
 2781}
 2782
 2783C_regparm C_word C_fcall C_static_bignum(C_word **ptr, int len, C_char *str)
 2784{
 2785  C_word *dptr, bignum, bigvec, retval, size, negp = 0;
 2786
 2787  if (*str == '+' || *str == '-') {
 2788    negp = ((*str++) == '-') ? 1 : 0;
 2789    --len;
 2790  }
 2791  size = C_BIGNUM_BITS_TO_DIGITS((unsigned int)len << 2);
 2792
 2793  dptr = (C_word *)C_malloc(C_wordstobytes(C_SIZEOF_INTERNAL_BIGNUM_VECTOR(size)));
 2794  if(dptr == NULL)
 2795    panic(C_text("out of memory - cannot allocate static bignum"));
 2796
 2797  bigvec = (C_word)dptr;
 2798  C_block_header_init(bigvec, C_STRING_TYPE | C_wordstobytes(size + 1));
 2799  C_set_block_item(bigvec, 0, negp);
 2800  /* This needs to be allocated at ptr, not dptr, because GC moves type tag */
 2801  bignum = C_a_i_bignum_wrapper(ptr, bigvec);
 2802
 2803  retval = str_to_bignum(bignum, str, str + len, 16);
 2804  if (retval & C_FIXNUM_BIT)
 2805    C_free(dptr); /* Might have been simplified */
 2806  return retval;
 2807}
 2808
 2809C_regparm C_word C_fcall C_static_lambda_info(C_word **ptr, int len, C_char *str)
 2810{
 2811  int dlen = sizeof(C_header) + C_align(len);
 2812  void *dptr = C_malloc(dlen);
 2813  C_word strblock;
 2814
 2815  if(dptr == NULL)
 2816    panic(C_text("out of memory - cannot allocate static lambda info"));
 2817
 2818  strblock = (C_word)dptr;
 2819  C_block_header_init(strblock, C_LAMBDA_INFO_TYPE | len);
 2820  C_memcpy(C_data_pointer(strblock), str, len);
 2821  return strblock;
 2822}
 2823
 2824
 2825C_regparm C_word C_fcall C_bytevector(C_word **ptr, int len, C_char *str)
 2826{
 2827  C_word strblock = C_string(ptr, len, str);
 2828
 2829  (void)C_string_to_bytevector(strblock);
 2830  return strblock;
 2831}
 2832
 2833
 2834C_regparm C_word C_fcall C_static_bytevector(C_word **ptr, int len, C_char *str)
 2835{
 2836  C_word strblock = C_static_string(ptr, len, str);
 2837
 2838  C_block_header_init(strblock, C_BYTEVECTOR_TYPE | len);
 2839  return strblock;
 2840}
 2841
 2842
 2843C_regparm C_word C_fcall C_pbytevector(int len, C_char *str)
 2844{
 2845  C_SCHEME_BLOCK *pbv = C_malloc(len + sizeof(C_header));
 2846
 2847  if(pbv == NULL) panic(C_text("out of memory - cannot allocate permanent blob"));
 2848
 2849  pbv->header = C_BYTEVECTOR_TYPE | len;
 2850  C_memcpy(pbv->data, str, len);
 2851  return (C_word)pbv;
 2852}
 2853
 2854
 2855C_regparm C_word C_fcall C_string_aligned8(C_word **ptr, int len, C_char *str)
 2856{
 2857  C_word *p = *ptr,
 2858         *p0;
 2859
 2860#ifndef C_SIXTY_FOUR
 2861  /* Align on 8-byte boundary: */
 2862  if(C_aligned8(p)) ++p;
 2863#endif
 2864
 2865  p0 = p;
 2866  *ptr = p + 1 + C_bytestowords(len);
 2867  *(p++) = C_STRING_TYPE | C_8ALIGN_BIT | len;
 2868  C_memcpy(p, str, len);
 2869  return (C_word)p0;
 2870}
 2871
 2872
 2873C_regparm C_word C_fcall C_string2(C_word **ptr, C_char *str)
 2874{
 2875  C_word strblock = (C_word)(*ptr);
 2876  int len;
 2877
 2878  if(str == NULL) return C_SCHEME_FALSE;
 2879
 2880  len = C_strlen(str);
 2881  *ptr = (C_word *)((C_word)(*ptr) + sizeof(C_header) + C_align(len));
 2882  C_block_header_init(strblock, C_STRING_TYPE | len);
 2883  C_memcpy(C_data_pointer(strblock), str, len);
 2884  return strblock;
 2885}
 2886
 2887
 2888C_regparm C_word C_fcall C_string2_safe(C_word **ptr, int max, C_char *str)
 2889{
 2890  C_word strblock = (C_word)(*ptr);
 2891  int len;
 2892
 2893  if(str == NULL) return C_SCHEME_FALSE;
 2894
 2895  len = C_strlen(str);
 2896
 2897  if(len >= max) {
 2898    C_snprintf(buffer, sizeof(buffer), C_text("foreign string result exceeded maximum of %d bytes"), max);
 2899    panic(buffer);
 2900  }
 2901
 2902  *ptr = (C_word *)((C_word)(*ptr) + sizeof(C_header) + C_align(len));
 2903  C_block_header_init(strblock, C_STRING_TYPE | len);
 2904  C_memcpy(C_data_pointer(strblock), str, len);
 2905  return strblock;
 2906}
 2907
 2908
 2909C_word C_fcall C_closure(C_word **ptr, int cells, C_word proc, ...)
 2910{
 2911  va_list va;
 2912  C_word *p = *ptr,
 2913         *p0 = p;
 2914
 2915  *p = C_CLOSURE_TYPE | cells;
 2916  *(++p) = proc;
 2917
 2918  for(va_start(va, proc); --cells; *(++p) = va_arg(va, C_word));
 2919
 2920  va_end(va);
 2921  *ptr = p + 1;
 2922  return (C_word)p0;
 2923}
 2924
 2925
 2926/* obsolete: replaced by C_a_pair in chicken.h */
 2927C_regparm C_word C_fcall C_pair(C_word **ptr, C_word car, C_word cdr)
 2928{
 2929  C_word *p = *ptr,
 2930         *p0 = p;
 2931 
 2932  *(p++) = C_PAIR_TYPE | (C_SIZEOF_PAIR - 1);
 2933  *(p++) = car;
 2934  *(p++) = cdr;
 2935  *ptr = p;
 2936  return (C_word)p0;
 2937}
 2938
 2939
 2940C_regparm C_word C_fcall C_number(C_word **ptr, double n)
 2941{
 2942  C_word 
 2943    *p = *ptr,
 2944    *p0;
 2945  double m;
 2946
 2947  if(n <= (double)C_MOST_POSITIVE_FIXNUM
 2948     && n >= (double)C_MOST_NEGATIVE_FIXNUM && modf(n, &m) == 0.0) {
 2949    return C_fix(n);
 2950  }
 2951
 2952#ifndef C_SIXTY_FOUR
 2953#ifndef C_DOUBLE_IS_32_BITS
 2954  /* Align double on 8-byte boundary: */
 2955  if(C_aligned8(p)) ++p;
 2956#endif
 2957#endif
 2958
 2959  p0 = p;
 2960  *(p++) = C_FLONUM_TAG;
 2961  *((double *)p) = n;
 2962  *ptr = p + sizeof(double) / sizeof(C_word);
 2963  return (C_word)p0;
 2964}
 2965
 2966
 2967C_regparm C_word C_fcall C_mpointer(C_word **ptr, void *mp)
 2968{
 2969  C_word 
 2970    *p = *ptr,
 2971    *p0 = p;
 2972
 2973  *(p++) = C_POINTER_TYPE | 1;
 2974  *((void **)p) = mp;
 2975  *ptr = p + 1;
 2976  return (C_word)p0;
 2977}
 2978
 2979
 2980C_regparm C_word C_fcall C_mpointer_or_false(C_word **ptr, void *mp)
 2981{
 2982  C_word 
 2983    *p = *ptr,
 2984    *p0 = p;
 2985
 2986  if(mp == NULL) return C_SCHEME_FALSE;
 2987
 2988  *(p++) = C_POINTER_TYPE | 1;
 2989  *((void **)p) = mp;
 2990  *ptr = p + 1;
 2991  return (C_word)p0;
 2992}
 2993
 2994
 2995C_regparm C_word C_fcall C_taggedmpointer(C_word **ptr, C_word tag, void *mp)
 2996{
 2997  C_word 
 2998    *p = *ptr,
 2999    *p0 = p;
 3000
 3001  *(p++) = C_TAGGED_POINTER_TAG;
 3002  *((void **)p) = mp;
 3003  *(++p) = tag;
 3004  *ptr = p + 1;
 3005  return (C_word)p0;
 3006}
 3007
 3008
 3009C_regparm C_word C_fcall C_taggedmpointer_or_false(C_word **ptr, C_word tag, void *mp)
 3010{
 3011  C_word 
 3012    *p = *ptr,
 3013    *p0 = p;
 3014
 3015  if(mp == NULL) return C_SCHEME_FALSE;
 3016 
 3017  *(p++) = C_TAGGED_POINTER_TAG;
 3018  *((void **)p) = mp;
 3019  *(++p) = tag;
 3020  *ptr = p + 1;
 3021  return (C_word)p0;
 3022}
 3023
 3024
 3025C_word C_vector(C_word **ptr, int n, ...)
 3026{
 3027  va_list v;
 3028  C_word 
 3029    *p = *ptr,
 3030    *p0 = p; 
 3031
 3032  *(p++) = C_VECTOR_TYPE | n;
 3033  va_start(v, n);
 3034
 3035  while(n--)
 3036    *(p++) = va_arg(v, C_word);
 3037
 3038  *ptr = p;
 3039  va_end(v);
 3040  return (C_word)p0;
 3041}
 3042
 3043
 3044C_word C_structure(C_word **ptr, int n, ...)
 3045{
 3046  va_list v;
 3047  C_word *p = *ptr,
 3048         *p0 = p; 
 3049
 3050  *(p++) = C_STRUCTURE_TYPE | n;
 3051  va_start(v, n);
 3052
 3053  while(n--)
 3054    *(p++) = va_arg(v, C_word);
 3055
 3056  *ptr = p;
 3057  va_end(v);
 3058  return (C_word)p0;
 3059}
 3060
 3061
 3062C_regparm C_word C_fcall
 3063C_mutate_slot(C_word *slot, C_word val)
 3064{
 3065  unsigned int mssize, newmssize, bytes;
 3066
 3067  ++mutation_count;
 3068  /* Mutation stack exists to track mutations pointing from elsewhere
 3069   * into nursery.  Stuff pointing anywhere else can be skipped, as
 3070   * well as mutations on nursery objects.
 3071   */
 3072  if(!C_in_stackp(val) || C_in_stackp((C_word)slot))
 3073    return *slot = val;
 3074
 3075#ifdef C_GC_HOOKS
 3076  if(C_gc_mutation_hook != NULL && C_gc_mutation_hook(slot, val)) return val;
 3077#endif
 3078
 3079  if(mutation_stack_top >= mutation_stack_limit) {
 3080    assert(mutation_stack_top == mutation_stack_limit);
 3081    mssize = mutation_stack_top - mutation_stack_bottom;
 3082    newmssize = mssize * 2;
 3083    bytes = newmssize * sizeof(C_word *);
 3084
 3085    if(debug_mode) 
 3086      C_dbg(C_text("debug"), C_text("resizing mutation stack from %uk to %uk ...\n"),
 3087	    (mssize * sizeof(C_word *)) / 1024, bytes / 1024);
 3088
 3089    mutation_stack_bottom = (C_word **)realloc(mutation_stack_bottom, bytes);
 3090
 3091    if(mutation_stack_bottom == NULL)
 3092      panic(C_text("out of memory - cannot re-allocate mutation stack"));
 3093
 3094    mutation_stack_limit = mutation_stack_bottom + newmssize;
 3095    mutation_stack_top = mutation_stack_bottom + mssize;
 3096  }
 3097
 3098  *(mutation_stack_top++) = slot;
 3099  ++tracked_mutation_count;
 3100  return *slot = val;
 3101}
 3102
 3103/* Allocate memory in scratch space, "size" is in words, like C_alloc.
 3104 * The memory in the scratch space is laid out as follows: First,
 3105 * there's a count that indicates how big the object originally was,
 3106 * followed by a pointer to the slot in the object which points to the
 3107 * object in scratch space, finally followed by the object itself.
 3108 * The reason we store the slot pointer is so that we can figure out
 3109 * whether the object is still "live" when reallocating; that's
 3110 * because we don't have a saved continuation from where we can trace
 3111 * the live data.  The reason we store the total length of the object
 3112 * is because we may be mutating in-place the lengths of the stored
 3113 * objects, and we need to know how much to skip over while scanning.
 3114 *
 3115 * If the allocating function returns, it *must* first mark all the
 3116 * values in scratch space as reclaimable.  This is needed because
 3117 * there is no way to distinguish between a stale pointer into scratch
 3118 * space that's still somewhere on the stack in "uninitialized" memory
 3119 * versus a word that's been recycled by the next called function,
 3120 * which now holds a value that happens to have the same bit pattern
 3121 * but represents another thing entirely.
 3122 */
 3123C_regparm C_word C_fcall C_scratch_alloc(C_uword size)
 3124{
 3125  C_word result;
 3126  
 3127  if (C_scratchspace_top + size + 2 >= C_scratchspace_limit) {
 3128    C_word *new_scratch_start, *new_scratch_top, *new_scratch_limit;
 3129    C_uword needed = C_scratch_usage + size + 2,
 3130            new_size = nmax(scratchspace_size << 1, 2UL << C_ilen(needed));
 3131
 3132    /* Shrink if the needed size is much smaller, but not below minimum */
 3133    if (needed < (new_size >> 4)) new_size >>= 1;
 3134    new_size = nmax(new_size, DEFAULT_SCRATCH_SPACE_SIZE);
 3135    
 3136    /* TODO: Maybe we should work with two semispaces to reduce mallocs? */
 3137    new_scratch_start = (C_word *)C_malloc(C_wordstobytes(new_size));
 3138    if (new_scratch_start == NULL)
 3139      panic(C_text("out of memory - cannot (re-)allocate scratch space"));
 3140    new_scratch_top = new_scratch_start;
 3141    new_scratch_limit = new_scratch_start + new_size;
 3142
 3143    if(debug_mode) {
 3144      C_dbg(C_text("debug"), C_text("resizing scratchspace dynamically from "
 3145				    UWORD_COUNT_FORMAT_STRING "k to "
 3146				    UWORD_COUNT_FORMAT_STRING "k ...\n"),
 3147	    C_wordstobytes(scratchspace_size) / 1024,
 3148            C_wordstobytes(new_size) / 1024);
 3149    }
 3150
 3151    if(gc_report_flag) {
 3152      C_dbg(C_text("GC"), C_text("(old) scratchspace: \tstart=" UWORD_FORMAT_STRING 
 3153				 ", \tlimit=" UWORD_FORMAT_STRING "\n"),
 3154            (C_word)C_scratchspace_start, (C_word)C_scratchspace_limit);
 3155      C_dbg(C_text("GC"), C_text("(new) scratchspace:   \tstart=" UWORD_FORMAT_STRING
 3156                                 ", \tlimit=" UWORD_FORMAT_STRING "\n"),
 3157            (C_word)new_scratch_start, (C_word)new_scratch_limit);
 3158    }
 3159    
 3160    /* Move scratch data into new space and mutate slots pointing there.
 3161     * This is basically a much-simplified version of really_mark.
 3162     */
 3163    if (C_scratchspace_start != NULL) {
 3164      C_word val, *sscan, *slot;
 3165      C_uword n, words;
 3166      C_header h;
 3167      C_SCHEME_BLOCK *p, *p2;
 3168
 3169      sscan = C_scratchspace_start;
 3170
 3171      while (sscan < C_scratchspace_top) {
 3172        words = *sscan;
 3173        slot = (C_word *)*(sscan+1);
 3174
 3175        if (*(sscan+2) == ALIGNMENT_HOLE_MARKER) val = (C_word)(sscan+3);
 3176        else val = (C_word)(sscan+2);
 3177
 3178        sscan += words + 2;
 3179        
 3180        p = (C_SCHEME_BLOCK *)val;
 3181        h = p->header;
 3182        if (is_fptr(h)) /* TODO: Support scratch->scratch pointers? */
 3183          panic(C_text("Unexpected forwarding pointer in scratch space"));
 3184
 3185        p2 = (C_SCHEME_BLOCK *)(new_scratch_top+2);
 3186
 3187#ifndef C_SIXTY_FOUR
 3188        if ((h & C_8ALIGN_BIT) && C_aligned8(p2) &&
 3189            (C_word *)p2 < new_scratch_limit) {
 3190          *((C_word *)p2) = ALIGNMENT_HOLE_MARKER;
 3191          p2 = (C_SCHEME_BLOCK *)((C_word *)p2 + 1);
 3192        }
 3193#endif
 3194
 3195        /* If orig slot still points here, copy data and update it */
 3196        if (slot != NULL) {
 3197          assert(C_in_stackp((C_word)slot) && *slot == val);
 3198          n = C_header_size(p);
 3199          n = (h & C_BYTEBLOCK_BIT) ? C_bytestowords(n) : n;
 3200          
 3201          *slot = (C_word)p2;
 3202          /* size = header plus block size plus optional alignment hole */
 3203          *new_scratch_top = ((C_word *)p2-(C_word *)new_scratch_top-2) + n + 1;
 3204          *(new_scratch_top+1) = (C_word)slot;
 3205          
 3206          new_scratch_top = (C_word *)p2 + n + 1;
 3207          if(new_scratch_top > new_scratch_limit)
 3208            panic(C_text("out of memory - scratch space full while resizing"));
 3209
 3210          p2->header = h;
 3211          p->header = ptr_to_fptr((C_uword)p2);
 3212          C_memcpy(p2->data, p->data, C_wordstobytes(n));
 3213        }
 3214      }
 3215      free(C_scratchspace_start);
 3216    }
 3217    C_scratchspace_start = new_scratch_start;
 3218    C_scratchspace_top = new_scratch_top;
 3219    C_scratchspace_limit = new_scratch_limit;
 3220    /* Scratch space is now tightly packed */
 3221    C_scratch_usage = (new_scratch_top - new_scratch_start);
 3222    scratchspace_size = new_size;
 3223  }
 3224  assert(C_scratchspace_top + size + 2 <= C_scratchspace_limit);
 3225
 3226  *C_scratchspace_top = size;
 3227  *(C_scratchspace_top+1) = (C_word)NULL; /* Nothing points here 'til mutated */
 3228  result = (C_word)(C_scratchspace_top+2);
 3229  C_scratchspace_top += size + 2;
 3230  /* This will only be marked as "used" when it's claimed by a pointer */
 3231  /* C_scratch_usage += size + 2; */
 3232  return result;
 3233}
 3234
 3235/* Given a root object, scan its slots recursively (the objects
 3236 * themselves should be shallow and non-recursive), and migrate every
 3237 * object stored between the memory boundaries to the supplied
 3238 * pointer.  Scratch data pointed to by objects between the memory
 3239 * boundaries is updated to point to the new memory region.  If the
 3240 * supplied pointer is NULL, the scratch memory is marked reclaimable.
 3241 */
 3242C_regparm C_word C_fcall
 3243C_migrate_buffer_object(C_word **ptr, C_word *start, C_word *end, C_word obj)
 3244{
 3245  C_word size, header, *data, *p = NULL, obj_in_buffer;
 3246
 3247  if (C_immediatep(obj)) return obj;
 3248
 3249  size = C_header_size(obj);
 3250  header = C_block_header(obj);
 3251  data = C_data_pointer(obj);
 3252  obj_in_buffer = (obj >= (C_word)start && obj < (C_word)end);
 3253
 3254  /* Only copy object if we have a target pointer and it's in the buffer */
 3255  if (ptr != NULL && obj_in_buffer) {
 3256    p = *ptr;
 3257    obj = (C_word)p; /* Return the object's new location at the end */
 3258  }
 3259
 3260  if (p != NULL) *p++ = header;
 3261  
 3262  if (header & C_BYTEBLOCK_BIT) {
 3263    if (p != NULL) {
 3264      *ptr = (C_word *)((C_byte *)(*ptr) + sizeof(C_header) + C_align(size));
 3265      C_memcpy(p, data, size);
 3266    }
 3267  } else {
 3268    if (p != NULL) *ptr += size + 1;
 3269    
 3270    if(header & C_SPECIALBLOCK_BIT) {
 3271      if (p != NULL) *(p++) = *data;
 3272      size--;
 3273      data++;
 3274    }
 3275
 3276    /* TODO: See if we can somehow make this use Cheney's algorithm */
 3277    while(size--) {
 3278      C_word slot = *data;
 3279
 3280      if(!C_immediatep(slot)) {
 3281        if (C_in_scratchspacep(slot)) {
 3282          if (obj_in_buffer) { /* Otherwise, don't touch scratch backpointer */
 3283            /* TODO: Support recursing into objects in scratch space? */
 3284            C_word *sp = (C_word *)slot;
 3285
 3286            if (*(sp-1) == ALIGNMENT_HOLE_MARKER) --sp;
 3287            if (*(sp-1) != (C_word)NULL && p == NULL)
 3288              C_scratch_usage -= *(sp-2) + 2;
 3289            *(sp-1) = (C_word)p; /* This is why we traverse even if p = NULL */
 3290
 3291            *data = C_SCHEME_UNBOUND; /* Ensure old reference is killed dead */
 3292          }
 3293        } else { /* Slot is not a scratchspace object: check sub-objects */
 3294          slot = C_migrate_buffer_object(ptr, start, end, slot);
 3295        }
 3296      }
 3297      if (p != NULL) *(p++) = slot;
 3298      else *data = slot; /* Sub-object may have moved! */
 3299      data++;
 3300    }
 3301  }
 3302  return obj; /* Should be NULL if ptr was NULL */
 3303}
 3304
 3305/* Register an object's slot as holding data to scratch space.  Only
 3306 * one slot can point to a scratch space object; the object in scratch
 3307 * space is preceded by a pointer that points to this slot (or NULL).
 3308 */
 3309C_regparm C_word C_fcall C_mutate_scratch_slot(C_word *slot, C_word val)
 3310{
 3311  C_word *ptr = (C_word *)val;
 3312  assert(C_in_scratchspacep(val));
 3313  assert(slot == NULL || C_in_stackp((C_word)slot));
 3314  if (*(ptr-1) == ALIGNMENT_HOLE_MARKER) --ptr;
 3315  if (*(ptr-1) == (C_word)NULL && slot != NULL)
 3316    C_scratch_usage += *(ptr-2) + 2;
 3317  if (*(ptr-1) != (C_word)NULL && slot == NULL)
 3318    C_scratch_usage -= *(ptr-2) + 2;
 3319  *(ptr-1) = (C_word)slot; /* Remember the slot pointing here, for realloc */
 3320  if (slot != NULL) *slot = val;
 3321  return val; 
 3322}
 3323
 3324/* Initiate garbage collection: */
 3325
 3326
 3327void C_save_and_reclaim(void *trampoline, int n, C_word *av)
 3328{
 3329  C_word new_size = nmax((C_word)1 << C_ilen(n), DEFAULT_TEMPORARY_STACK_SIZE);
 3330
 3331  assert(av > C_temporary_stack_bottom || av < C_temporary_stack_limit);
 3332  assert(C_temporary_stack == C_temporary_stack_bottom);
 3333
 3334  /* Don't *immediately* slam back to default size */
 3335  if (new_size < temporary_stack_size / 4)
 3336    new_size = temporary_stack_size >> 1;
 3337
 3338  if (new_size != temporary_stack_size) {
 3339
 3340    if(fixed_temporary_stack_size)
 3341      panic(C_text("fixed temporary stack overflow (\"apply\" called with too many arguments?)"));
 3342
 3343    if(gc_report_flag) {
 3344      C_dbg(C_text("GC"), C_text("resizing temporary stack dynamically from " UWORD_COUNT_FORMAT_STRING "k to " UWORD_COUNT_FORMAT_STRING "k ...\n"),
 3345            C_wordstobytes(temporary_stack_size) / 1024,
 3346            C_wordstobytes(new_size) / 1024);
 3347    }
 3348
 3349    C_free(C_temporary_stack_limit);
 3350
 3351    if((C_temporary_stack_limit = (C_word *)C_malloc(new_size * sizeof(C_word))) == NULL)
 3352      panic(C_text("out of memory - could not resize temporary stack"));
 3353
 3354    C_temporary_stack_bottom = C_temporary_stack_limit + new_size;
 3355    C_temporary_stack = C_temporary_stack_bottom;
 3356    temporary_stack_size = new_size;
 3357  }
 3358
 3359  C_temporary_stack = C_temporary_stack_bottom - n;
 3360
 3361  assert(C_temporary_stack >= C_temporary_stack_limit);
 3362
 3363  C_memmove(C_temporary_stack, av, n * sizeof(C_word));
 3364  C_reclaim(trampoline, n);
 3365}
 3366
 3367
 3368void C_save_and_reclaim_args(void *trampoline, int n, ...)
 3369{
 3370  va_list v;
 3371  int i;
 3372  
 3373  va_start(v, n);
 3374
 3375  for(i = 0; i < n; ++i)
 3376    C_save(va_arg(v, C_word));
 3377
 3378  va_end(v);
 3379  C_reclaim(trampoline, n);
 3380}
 3381
 3382
 3383#ifdef __SUNPRO_C
 3384static void _mark(C_word *x, C_byte *s, C_byte **t, C_byte *l) {   \
 3385  C_word *_x = (x), _val = *_x;                                   \
 3386  if(!C_immediatep(_val)) really_mark(_x,s,t,l);                  \
 3387}
 3388#else
 3389# define _mark(x,s,t,l)                                  \
 3390  C_cblock						\
 3391  C_word *_x = (x), _val = *_x;				\
 3392  if(!C_immediatep(_val)) really_mark(_x,s,t,l);	\
 3393  C_cblockend
 3394#endif
 3395
 3396/* NOTE: This macro is particularly unhygienic! */
 3397#define mark(x) _mark(x, tgt_space_start, tgt_space_top, tgt_space_limit)
 3398
 3399C_regparm void C_fcall C_reclaim(void *trampoline, C_word c)
 3400{
 3401  int i, j, fcount;
 3402  C_uword count;
 3403  C_word **msp, last;
 3404  C_byte *tmp, *start;
 3405  C_GC_ROOT *gcrp;
 3406  double tgc = 0;
 3407  volatile int finalizers_checked;
 3408  FINALIZER_NODE *flist;
 3409  C_DEBUG_INFO cell;
 3410  C_byte *tgt_space_start, **tgt_space_top, *tgt_space_limit;
 3411  
 3412  /* assert(C_timer_interrupt_counter >= 0); */
 3413
 3414  if(pending_interrupts_count > 0 && C_interrupts_enabled) {
 3415    stack_check_demand = 0; /* forget demand: we're not going to gc yet */
 3416    handle_interrupt(trampoline);
 3417  }
 3418
 3419  cell.enabled = 0;
 3420  cell.event = C_DEBUG_GC;
 3421  cell.loc = "<runtime>";
 3422  cell.val = "GC_MINOR";
 3423  C_debugger(&cell, 0, NULL);
 3424
 3425  /* Note: the mode argument will always be GC_MINOR or GC_REALLOC. */
 3426  if(C_pre_gc_hook != NULL) C_pre_gc_hook(GC_MINOR);
 3427
 3428  finalizers_checked = 0;
 3429  C_restart_trampoline = trampoline;
 3430  C_restart_c = c;
 3431  gc_mode = GC_MINOR;
 3432  tgt_space_start = fromspace_start;
 3433  tgt_space_top = &C_fromspace_top;
 3434  tgt_space_limit = C_fromspace_limit;
 3435  weak_pair_chain = (C_word)NULL;
 3436  locative_chain = (C_word)NULL;
 3437
 3438  start = C_fromspace_top;
 3439
 3440  /* Entry point for second-level GC (on explicit request or because of full fromspace): */
 3441#ifdef HAVE_SIGSETJMP
 3442  if(C_sigsetjmp(gc_restart, 0) || start >= C_fromspace_limit) {
 3443#else
 3444  if(C_setjmp(gc_restart) || start >= C_fromspace_limit) {
 3445#endif
 3446    if(gc_bell) {
 3447      C_putchar(7);
 3448      C_fflush(stdout);
 3449    }
 3450
 3451    tgc = C_cpu_milliseconds();
 3452
 3453    if(gc_mode == GC_REALLOC) {
 3454      cell.val = "GC_REALLOC";
 3455      C_debugger(&cell, 0, NULL);
 3456      C_rereclaim2(percentage(heap_size, C_heap_growth), 0);
 3457      gc_mode = GC_MAJOR;
 3458
 3459      tgt_space_start = tospace_start;
 3460      tgt_space_top = &tospace_top;
 3461      tgt_space_limit= tospace_limit;
 3462
 3463      count = (C_uword)tospace_top - (C_uword)tospace_start;
 3464      goto never_mind_edsger;
 3465    }
 3466
 3467    start = (C_byte *)C_align((C_uword)tospace_top);    
 3468    gc_mode = GC_MAJOR;
 3469    tgt_space_start = tospace_start;
 3470    tgt_space_top = &tospace_top;
 3471    tgt_space_limit= tospace_limit;
 3472    weak_pair_chain = (C_word)NULL; /* only chain up weak pairs forwarded into tospace */
 3473    locative_chain = (C_word)NULL;  /* same for locatives */
 3474
 3475    cell.val = "GC_MAJOR";
 3476    C_debugger(&cell, 0, NULL);
 3477
 3478    mark_live_heap_only_objects(tgt_space_start, tgt_space_top, tgt_space_limit);
 3479
 3480    /* mark normal GC roots (see below for finalizer handling): */
 3481    for(gcrp = gc_root_list; gcrp != NULL; gcrp = gcrp->next) {
 3482      if(!gcrp->finalizable) mark(&gcrp->value);
 3483    }
 3484  }
 3485  else {
 3486    /* Mark mutated slots: */
 3487    for(msp = mutation_stack_bottom; msp < mutation_stack_top; ++msp)
 3488      mark(*msp);
 3489  }
 3490
 3491  mark_live_objects(tgt_space_start, tgt_space_top, tgt_space_limit);
 3492
 3493  mark_nested_objects(start, tgt_space_start, tgt_space_top, tgt_space_limit);
 3494  start = *tgt_space_top;
 3495
 3496  if(gc_mode == GC_MINOR) {
 3497    count = (C_uword)C_fromspace_top - (C_uword)start;
 3498    ++gc_count_1;
 3499    ++gc_count_1_total;
 3500    update_locatives(GC_MINOR, start, *tgt_space_top);
 3501    update_weak_pairs(GC_MINOR, start, *tgt_space_top);
 3502  }
 3503  else {
 3504    /* Mark finalizer list and remember pointers to non-forwarded items: */
 3505    last = C_block_item(pending_finalizers_symbol, 0);
 3506
 3507    if(!C_immediatep(last) && (j = C_unfix(C_block_item(last, 0))) != 0) { 
 3508      /* still finalizers pending: just mark table items... */
 3509      if(gc_report_flag)
 3510        C_dbg(C_text("GC"), C_text("%d finalized item(s) still pending\n"), j);
 3511
 3512      j = fcount = 0;
 3513
 3514      for(flist = finalizer_list; flist != NULL; flist = flist->next) {
 3515        mark(&flist->item);
 3516        mark(&flist->finalizer);
 3517        ++fcount;
 3518      }
 3519
 3520      /* mark finalizable GC roots: */
 3521      for(gcrp = gc_root_list; gcrp != NULL; gcrp = gcrp->next) {
 3522        if(gcrp->finalizable) mark(&gcrp->value);
 3523      }
 3524
 3525      if(gc_report_flag && fcount > 0)
 3526        C_dbg(C_text("GC"), C_text("%d finalizer value(s) marked\n"), fcount);
 3527    }
 3528    else {
 3529      j = fcount = 0;
 3530
 3531      /* move into pending */
 3532      for(flist = finalizer_list; flist != NULL; flist = flist->next) {
 3533        if(j < C_max_pending_finalizers) {
 3534          if(!is_fptr(C_block_header(flist->item))) 
 3535            pending_finalizer_indices[ j++ ] = flist;
 3536        }
 3537      }
 3538
 3539      /* mark */
 3540      for(flist = finalizer_list; flist != NULL; flist = flist->next) {
 3541        mark(&flist->item);
 3542        mark(&flist->finalizer);
 3543      }
 3544
 3545      /* mark finalizable GC roots: */
 3546      for(gcrp = gc_root_list; gcrp != NULL; gcrp = gcrp->next) {
 3547        if(gcrp->finalizable) mark(&gcrp->value);
 3548      }
 3549    }
 3550
 3551    pending_finalizer_count = j;
 3552    finalizers_checked = 1;
 3553
 3554    if(pending_finalizer_count > 0 && gc_report_flag)
 3555      C_dbg(C_text("GC"), C_text("%d finalizer(s) pending (%d live)\n"), 
 3556            pending_finalizer_count, live_finalizer_count);
 3557
 3558    /* Once more mark nested objects after (maybe) copying finalizer objects: */
 3559    mark_nested_objects(start, tgt_space_start, tgt_space_top, tgt_space_limit);
 3560
 3561    /* Copy finalized items with remembered indices into `##sys#pending-finalizers' 
 3562       (and release finalizer node): */
 3563    if(pending_finalizer_count > 0) {
 3564      if(gc_report_flag)
 3565        C_dbg(C_text("GC"), C_text("queueing %d finalizer(s)\n"), pending_finalizer_count);
 3566
 3567      last = C_block_item(pending_finalizers_symbol, 0);
 3568      assert(C_block_item(last, 0) == C_fix(0));
 3569      C_set_block_item(last, 0, C_fix(pending_finalizer_count));
 3570
 3571      for(i = 0; i < pending_finalizer_count; ++i) {
 3572        flist = pending_finalizer_indices[ i ];
 3573        C_set_block_item(last, 1 + i * 2, flist->item);
 3574        C_set_block_item(last, 2 + i * 2, flist->finalizer);
 3575	  
 3576        if(flist->previous != NULL) flist->previous->next = flist->next;
 3577        else finalizer_list = flist->next;
 3578
 3579        if(flist->next != NULL) flist->next->previous = flist->previous;
 3580
 3581        flist->next = finalizer_free_list;
 3582        flist->previous = NULL;
 3583        finalizer_free_list = flist;
 3584        --live_finalizer_count;
 3585      }
 3586    }
 3587
 3588    update_locatives(gc_mode, start, *tgt_space_top);
 3589    update_weak_pairs(gc_mode, start, *tgt_space_top);
 3590
 3591    count = (C_uword)tospace_top - (C_uword)tospace_start; // Actual used, < heap_size/2
 3592
 3593    {
 3594      C_uword min_half = count + C_heap_half_min_free;
 3595      C_uword low_half = percentage(heap_size/2, C_heap_shrinkage_used);
 3596      C_uword grown    = percentage(heap_size, C_heap_growth);
 3597      C_uword shrunk   = percentage(heap_size, C_heap_shrinkage);
 3598
 3599      if (count < low_half) {
 3600        heap_shrink_counter++;
 3601      } else {
 3602        heap_shrink_counter = 0;
 3603      }
 3604
 3605      /*** isn't gc_mode always GC_MAJOR here? */
 3606      if(gc_mode == GC_MAJOR && !C_heap_size_is_fixed &&
 3607         C_heap_shrinkage > 0 &&
 3608         // This prevents grow, shrink, grow, shrink... spam
 3609         HEAP_SHRINK_COUNTS < heap_shrink_counter &&
 3610         (min_half * 2) <= shrunk && // Min. size trumps shrinkage
 3611         heap_size > MINIMAL_HEAP_SIZE) {
 3612        if(gc_report_flag) {
 3613          C_dbg(C_text("GC"), C_text("Heap low water mark hit (%d%%), shrinking...\n"),
 3614                C_heap_shrinkage_used);
 3615        }
 3616        heap_shrink_counter = 0;
 3617        C_rereclaim2(shrunk, 0);
 3618      } else if (gc_mode == GC_MAJOR && !C_heap_size_is_fixed &&
 3619                 (heap_size / 2) < min_half) {
 3620        if(gc_report_flag) {
 3621          C_dbg(C_text("GC"), C_text("Heap high water mark hit, growing...\n"));
 3622        }
 3623        heap_shrink_counter = 0;
 3624        C_rereclaim2(grown, 0);
 3625      } else {
 3626        C_fromspace_top = tospace_top;
 3627        tmp = fromspace_start;
 3628        fromspace_start = tospace_start;
 3629        tospace_start = tospace_top = tmp;
 3630        tmp = C_fromspace_limit;
 3631        C_fromspace_limit = tospace_limit;
 3632        tospace_limit = tmp;
 3633      }
 3634    }
 3635
 3636  never_mind_edsger:
 3637    ++gc_count_2;
 3638  }
 3639
 3640  if(gc_mode == GC_MAJOR) {
 3641    tgc = C_cpu_milliseconds() - tgc;
 3642    gc_ms += tgc;
 3643    timer_accumulated_gc_ms += tgc;
 3644  }
 3645
 3646  /* Display GC report: 
 3647     Note: stubbornly writes to stderr - there is no provision for other output-ports */
 3648  if(gc_report_flag == 1 || (gc_report_flag && gc_mode == GC_MAJOR)) {
 3649    C_dbg(C_text("GC"), C_text("level  %d\tgcs(minor)  %d\tgcs(major)  %d\n"),
 3650	  gc_mode, gc_count_1, gc_count_2);
 3651    i = (C_uword)C_stack_pointer;
 3652
 3653#if C_STACK_GROWS_DOWNWARD
 3654    C_dbg("GC", C_text("stack\t" UWORD_FORMAT_STRING "\t" UWORD_FORMAT_STRING "\t" UWORD_FORMAT_STRING), 
 3655	  (C_uword)C_stack_limit, (C_uword)i, (C_uword)C_stack_limit + stack_size);
 3656#else
 3657    C_dbg("GC", C_text("stack\t" UWORD_FORMAT_STRING "\t" UWORD_FORMAT_STRING "\t" UWORD_FORMAT_STRING), 
 3658	  (C_uword)C_stack_limit - stack_size, (C_uword)i, (C_uword)C_stack_limit);
 3659#endif
 3660
 3661    if(gc_mode == GC_MINOR) 
 3662      C_fprintf(C_stderr, C_text("\t" UWORD_FORMAT_STRING), (C_uword)count);
 3663
 3664    C_fputc('\n', C_stderr);
 3665    C_dbg("GC", C_text(" from\t" UWORD_FORMAT_STRING "\t" UWORD_FORMAT_STRING "\t" UWORD_FORMAT_STRING),
 3666	  (C_uword)fromspace_start, (C_uword)C_fromspace_top, (C_uword)C_fromspace_limit);
 3667
 3668    if(gc_mode == GC_MAJOR) 
 3669      C_fprintf(C_stderr, C_text("\t" UWORD_FORMAT_STRING), (C_uword)count);
 3670
 3671    C_fputc('\n', C_stderr);
 3672    C_dbg("GC", C_text("   to\t" UWORD_FORMAT_STRING "\t" UWORD_FORMAT_STRING "\t" UWORD_FORMAT_STRING" \n"), 
 3673	  (C_uword)tospace_start, (C_uword)tospace_top, 
 3674	  (C_uword)tospace_limit);
 3675  }
 3676
 3677  /* GC will have copied any live objects out of scratch space: clear it */
 3678  if (C_scratchspace_start != C_scratchspace_top) {
 3679    /* And drop the scratchspace in case of a major or reallocating collection */
 3680    if (gc_mode != GC_MINOR) {
 3681      C_free(C_scratchspace_start);
 3682      C_scratchspace_start = NULL;
 3683      C_scratchspace_limit = NULL;
 3684      scratchspace_size = 0;
 3685    }
 3686    C_scratchspace_top = C_scratchspace_start;
 3687    C_scratch_usage = 0;
 3688  }
 3689
 3690  if(gc_mode == GC_MAJOR) {
 3691    gc_count_1 = 0;
 3692    maximum_heap_usage = count > maximum_heap_usage ? count : maximum_heap_usage;
 3693  }
 3694
 3695  if(C_post_gc_hook != NULL) C_post_gc_hook(gc_mode, (C_long)tgc);
 3696
 3697  /* Unwind stack completely */
 3698#ifdef HAVE_SIGSETJMP
 3699  C_siglongjmp(C_restart, 1);
 3700#else
 3701  C_longjmp(C_restart, 1);
 3702#endif
 3703}
 3704
 3705
 3706/* Mark live objects which can exist in the nursery and/or the heap */
 3707static C_regparm void C_fcall mark_live_objects(C_byte *tgt_space_start, C_byte **tgt_space_top, C_byte *tgt_space_limit)
 3708{
 3709  C_word *p;
 3710  TRACE_INFO *tinfo;
 3711
 3712  assert(C_temporary_stack >= C_temporary_stack_limit);
 3713
 3714  /* Mark live values from the currently running closure: */
 3715  for(p = C_temporary_stack; p < C_temporary_stack_bottom; ++p)
 3716    mark(p);
 3717
 3718  /* Clear the mutated slot stack: */
 3719  mutation_stack_top = mutation_stack_bottom;
 3720
 3721  /* Mark trace-buffer: */
 3722  for(tinfo = trace_buffer; tinfo < trace_buffer_limit; ++tinfo) {
 3723    mark(&tinfo->cooked_location);
 3724    mark(&tinfo->cooked1);
 3725    mark(&tinfo->cooked2);
 3726    mark(&tinfo->thread);
 3727  }
 3728}
 3729
 3730
 3731/*
 3732 * Mark all live *heap* objects that don't need GC mode-specific
 3733 * treatment.  Thus, no finalizers or other GC roots.
 3734 *
 3735 * Finalizers are excluded because these need special handling:
 3736 * finalizers referring to dead objects must be marked and queued.
 3737 * However, *pending* finalizers (for objects previously determined
 3738 * to be collectable) are marked so that these objects stick around
 3739 * until after the finalizer has been run.
 3740 *
 3741 * This function does not need to be called on a minor GC, since these
 3742 * objects won't ever exist in the nursery.
 3743 */
 3744static C_regparm void C_fcall mark_live_heap_only_objects(C_byte *tgt_space_start, C_byte **tgt_space_top, C_byte *tgt_space_limit)
 3745{
 3746  LF_LIST *lfn;
 3747  C_word *p, **msp, last;
 3748  unsigned int i;
 3749  C_SYMBOL_TABLE *stp;
 3750  
 3751  /* Mark items in forwarding table: */
 3752  for(p = forwarding_table; *p != 0; p += 2) {
 3753    last = p[ 1 ];
 3754    mark(&p[ 1 ]);
 3755    C_block_header(p[ 0 ]) = C_block_header(last);
 3756  }
 3757
 3758  /* Mark literal frames: */
 3759  for(lfn = lf_list; lfn != NULL; lfn = lfn->next)
 3760    for(i = 0; i < (unsigned int)lfn->count; ++i)
 3761      mark(&lfn->lf[i]);
 3762
 3763  /* Mark symbol tables: */
 3764  for(stp = symbol_table_list; stp != NULL; stp = stp->next)
 3765    for(i = 0; i < stp->size; ++i)
 3766      mark(&stp->table[i]);
 3767
 3768  /* Mark collectibles: */
 3769  for(msp = collectibles; msp < collectibles_top; ++msp)
 3770    if(*msp != NULL) mark(*msp);
 3771
 3772  /* Mark system globals */
 3773  mark(&core_provided_symbol);
 3774  mark(&interrupt_hook_symbol);
 3775  mark(&error_hook_symbol);
 3776  mark(&callback_continuation_stack_symbol);
 3777  mark(&pending_finalizers_symbol);
 3778  mark(&current_thread_symbol);
 3779
 3780  mark(&u8vector_symbol);
 3781  mark(&s8vector_symbol);
 3782  mark(&u16vector_symbol);
 3783  mark(&s16vector_symbol);
 3784  mark(&u32vector_symbol);
 3785  mark(&s32vector_symbol);
 3786  mark(&u64vector_symbol);
 3787  mark(&s64vector_symbol);
 3788  mark(&f32vector_symbol);
 3789  mark(&f64vector_symbol);
 3790}
 3791
 3792
 3793/*
 3794 * Mark nested values in already moved (i.e., marked) blocks in
 3795 * breadth-first manner (Cheney's algorithm).
 3796 */
 3797static C_regparm void C_fcall mark_nested_objects(C_byte *heap_scan_top, C_byte *tgt_space_start, C_byte **tgt_space_top, C_byte *tgt_space_limit)
 3798{
 3799  int n;
 3800  C_word bytes;
 3801  C_word *p;
 3802  C_header h;
 3803  C_SCHEME_BLOCK *bp;
 3804
 3805  while(heap_scan_top < *tgt_space_top) {
 3806    bp = (C_SCHEME_BLOCK *)heap_scan_top;
 3807
 3808    if(*((C_word *)bp) == ALIGNMENT_HOLE_MARKER) 
 3809      bp = (C_SCHEME_BLOCK *)((C_word *)bp + 1);
 3810
 3811    n = C_header_size(bp);
 3812    h = bp->header;
 3813    bytes = (h & C_BYTEBLOCK_BIT) ? n : n * sizeof(C_word);
 3814    p = bp->data;
 3815
 3816    if(n > 0 && (h & C_BYTEBLOCK_BIT) == 0) {
 3817      if(h & C_SPECIALBLOCK_BIT) {
 3818	--n;
 3819	++p;
 3820      }
 3821
 3822      while(n--) mark(p++);
 3823    }
 3824
 3825    heap_scan_top = (C_byte *)bp + C_align(bytes) + sizeof(C_word);
 3826  }
 3827}
 3828
 3829
 3830static C_regparm void C_fcall really_mark(C_word *x, C_byte *tgt_space_start, C_byte **tgt_space_top, C_byte *tgt_space_limit)
 3831{
 3832  C_word val;
 3833  C_uword n, bytes;
 3834  C_header h;
 3835  C_SCHEME_BLOCK *p, *p2;
 3836
 3837  val = *x;
 3838
 3839  if (!C_in_stackp(val) && !C_in_heapp(val) && !C_in_scratchspacep(val)) {
 3840#ifdef C_GC_HOOKS
 3841    if(C_gc_trace_hook != NULL) 
 3842      C_gc_trace_hook(x, gc_mode);
 3843#endif
 3844    return;
 3845  }
 3846
 3847  p = (C_SCHEME_BLOCK *)val;
 3848  h = p->header;
 3849
 3850  while(is_fptr(h)) { /* TODO: Pass in fptr chain limit? */
 3851    val = fptr_to_ptr(h);
 3852    p = (C_SCHEME_BLOCK *)val;
 3853    h = p->header;
 3854  }
 3855
 3856  /* Already in target space, probably as result of chasing fptrs */
 3857  if ((C_uword)val >= (C_uword)tgt_space_start && (C_uword)val < (C_uword)*tgt_space_top) {
 3858    *x = val;
 3859    return;
 3860  }
 3861
 3862  p2 = (C_SCHEME_BLOCK *)C_align((C_uword)*tgt_space_top);
 3863
 3864#ifndef C_SIXTY_FOUR
 3865  if((h & C_8ALIGN_BIT) && C_aligned8(p2) && (C_byte *)p2 < tgt_space_limit) {
 3866    *((C_word *)p2) = ALIGNMENT_HOLE_MARKER;
 3867    p2 = (C_SCHEME_BLOCK *)((C_word *)p2 + 1);
 3868  }
 3869#endif
 3870
 3871  n = C_header_size(p);
 3872  bytes = (h & C_BYTEBLOCK_BIT) ? n : n * sizeof(C_word);
 3873
 3874  if(C_unlikely(((C_byte *)p2 + bytes + sizeof(C_word)) > tgt_space_limit)) {
 3875    if (gc_mode == GC_MAJOR) {
 3876      /* Detect impossibilities before GC_REALLOC to preserve state: */
 3877      if (C_in_stackp((C_word)p) && bytes > stack_size)
 3878        panic(C_text("Detected corrupted data in stack"));
 3879      if (C_in_heapp((C_word)p) && bytes > (heap_size / 2))
 3880        panic(C_text("Detected corrupted data in heap"));
 3881      if(C_heap_size_is_fixed)
 3882        panic(C_text("out of memory - heap full"));
 3883      
 3884      gc_mode = GC_REALLOC;
 3885    } else if (gc_mode == GC_REALLOC) {
 3886      if (new_tospace_top > new_tospace_limit) {
 3887        panic(C_text("out of memory - heap full while resizing"));
 3888      }
 3889    }
 3890#ifdef HAVE_SIGSETJMP
 3891    C_siglongjmp(gc_restart, 1);
 3892#else
 3893    C_longjmp(gc_restart, 1);
 3894#endif
 3895  }
 3896
 3897  *tgt_space_top = (C_byte *)p2 + C_align(bytes) + sizeof(C_word);
 3898
 3899  *x = (C_word)p2;
 3900  p2->header = h;
 3901  p->header = ptr_to_fptr((C_uword)p2);
 3902  C_memcpy(p2->data, p->data, bytes);
 3903  if (h == C_WEAK_PAIR_TAG && !C_immediatep(p2->data[0])) {
 3904    p->data[0] = weak_pair_chain; /* "Recycle" the weak pair's CAR to point to prev head */
 3905    weak_pair_chain = (C_word)p;  /* Make this fwd ptr the new head of the weak pair chain */
 3906  } else if (h == C_LOCATIVE_TAG) {
 3907    p->data[0] = locative_chain; /* "Recycle" the locative pointer field to point to prev head */
 3908    locative_chain = (C_word)p;  /* Make this fwd ptr the new head of the locative chain */
 3909  }
 3910}
 3911
 3912
 3913/* Do a major GC into a freshly allocated heap: */
 3914
 3915#define remark(x)  _mark(x, new_tospace_start, &new_tospace_top, new_tospace_limit)
 3916
 3917C_regparm void C_fcall C_rereclaim2(C_uword size, int relative_resize)
 3918{
 3919  int i;
 3920  C_GC_ROOT *gcrp;
 3921  FINALIZER_NODE *flist;
 3922  C_byte *new_heapspace, *start;
 3923  size_t  new_heapspace_size;
 3924
 3925  if(C_pre_gc_hook != NULL) C_pre_gc_hook(GC_REALLOC);
 3926
 3927  /*
 3928   * Normally, size is "absolute": it indicates the desired size of
 3929   * the entire new heap.  With relative_resize, size is a demanded
 3930   * increase of the heap, so we'll have to add it.  This calculation
 3931   * doubles the current heap size because heap_size is already both
 3932   * halves.  We add size*2 because we'll eventually divide the size
 3933   * by 2 for both halves.  We also add stack_size*2 because all the
 3934   * nursery data is also copied to the heap on GC, and the requested
 3935   * memory "size" must be available after the GC.
 3936   */
 3937  if(relative_resize) size = (heap_size + size + stack_size) * 2;
 3938
 3939  if(size < MINIMAL_HEAP_SIZE) size = MINIMAL_HEAP_SIZE;
 3940
 3941  /*
 3942   * When heap grows, ensure it's enough to accommodate first
 3943   * generation (nursery).  Because we're calculating the total heap
 3944   * size here (fromspace *AND* tospace), we have to double the stack
 3945   * size, otherwise we'd accommodate only half the stack in the tospace.
 3946   */
 3947  if(size > heap_size && size - heap_size < stack_size * 2)
 3948    size = heap_size + stack_size * 2;
 3949
 3950  /*
 3951   * The heap has grown but we've already hit the maximal size with the current
 3952   * heap, we can't do anything else but panic.
 3953   */
 3954  if(size > heap_size && heap_size >= C_maximal_heap_size)
 3955    panic(C_text("out of memory - heap has reached its maximum size"));
 3956
 3957  if(size > C_maximal_heap_size) size = C_maximal_heap_size;
 3958
 3959  if(debug_mode) {
 3960    C_dbg(C_text("debug"), C_text("resizing heap dynamically from "
 3961                                  UWORD_COUNT_FORMAT_STRING "k to "
 3962                                  UWORD_COUNT_FORMAT_STRING "k ...\n"),
 3963	  heap_size / 1024, size / 1024);
 3964  }
 3965
 3966  if(gc_report_flag) {
 3967    C_dbg(C_text("GC"), C_text("(old) fromspace: \tstart=" UWORD_FORMAT_STRING 
 3968			       ", \tlimit=" UWORD_FORMAT_STRING "\n"),
 3969	  (C_word)fromspace_start, (C_word)C_fromspace_limit);
 3970    C_dbg(C_text("GC"), C_text("(old) tospace:   \tstart=" UWORD_FORMAT_STRING
 3971			       ", \tlimit=" UWORD_FORMAT_STRING "\n"),
 3972	  (C_word)tospace_start, (C_word)tospace_limit);
 3973  }
 3974
 3975  heap_size = size;         /* Total heap size of the two halves... */
 3976  size /= 2;                /* ...each half is this big */
 3977  
 3978  /*
 3979   * Start by allocating the new heap's fromspace.  After remarking,
 3980   * allocate the other half of the new heap (its tospace).
 3981   *
 3982   * To clarify: what we call "new_space" here is what will eventually
 3983   * be cycled over to "fromspace" when re-reclamation has finished
 3984   * (that is, after the old one has been freed).
 3985   */
 3986  if ((new_heapspace = heap_alloc (size, &new_tospace_start)) == NULL)
 3987    panic(C_text("out of memory - cannot allocate heap segment"));
 3988  new_heapspace_size = size;
 3989
 3990  new_tospace_top = new_tospace_start;
 3991  new_tospace_limit = new_tospace_start + size;
 3992  start = new_tospace_top;
 3993  weak_pair_chain = (C_word)NULL; /* only chain up weak pairs forwarded into new heap */
 3994  locative_chain = (C_word)NULL;  /* same for locatives */
 3995
 3996  /* Mark standard live objects in nursery and heap */
 3997  mark_live_objects(new_tospace_start, &new_tospace_top, new_tospace_limit);
 3998  mark_live_heap_only_objects(new_tospace_start, &new_tospace_top, new_tospace_limit);
 3999
 4000  /* Mark finalizer table: */
 4001  for(flist = finalizer_list; flist != NULL; flist = flist->next) {
 4002    remark(&flist->item);
 4003    remark(&flist->finalizer);
 4004  }
 4005
 4006  /* Mark *all* GC roots */
 4007  for(gcrp = gc_root_list; gcrp != NULL; gcrp = gcrp->next) {
 4008    remark(&gcrp->value);
 4009  }
 4010
 4011  /* Mark nested values in already moved (marked) blocks in breadth-first manner: */
 4012  mark_nested_objects(start, new_tospace_start, &new_tospace_top, new_tospace_limit);
 4013  update_locatives(GC_REALLOC, new_tospace_top, new_tospace_top);
 4014  update_weak_pairs(GC_REALLOC, new_tospace_top, new_tospace_top);
 4015
 4016  heap_free (heapspace1, heapspace1_size);
 4017  heap_free (heapspace2, heapspace2_size);
 4018  
 4019  if ((heapspace2 = heap_alloc (size, &tospace_start)) == NULL)
 4020    panic(C_text("out of memory - cannot allocate next heap segment"));
 4021  heapspace2_size = size;
 4022
 4023  heapspace1 = new_heapspace;
 4024  heapspace1_size = new_heapspace_size;
 4025  tospace_limit = tospace_start + size;
 4026  tospace_top = tospace_start;
 4027  fromspace_start = new_tospace_start;
 4028  C_fromspace_top = new_tospace_top;
 4029  C_fromspace_limit = new_tospace_limit;
 4030
 4031  if(gc_report_flag) {
 4032    C_dbg(C_text("GC"), C_text("resized heap to %d bytes\n"), heap_size);
 4033    C_dbg(C_text("GC"), C_text("(new) fromspace: \tstart=" UWORD_FORMAT_STRING 
 4034			       ", \tlimit=" UWORD_FORMAT_STRING "\n"),
 4035	  (C_word)fromspace_start, (C_word)C_fromspace_limit);
 4036    C_dbg(C_text("GC"), C_text("(new) tospace:   \tstart=" UWORD_FORMAT_STRING
 4037			       ", \tlimit=" UWORD_FORMAT_STRING "\n"),
 4038	  (C_word)tospace_start, (C_word)tospace_limit);
 4039  }
 4040
 4041  if(C_post_gc_hook != NULL) C_post_gc_hook(GC_REALLOC, 0);
 4042}
 4043
 4044
 4045/* When a weak pair is encountered by GC, it turns it into a
 4046 * forwarding reference as usual, but then it re-uses the now-defunct
 4047 * pair's CAR field.  It clobbers that field with a plain C pointer to
 4048 * the current "weak pair chain".  Then, the weak pair chain is
 4049 * updated to point to this new forwarding pointer, creating a crude
 4050 * linked list of sorts.
 4051 *
 4052 * We can get away with this because the slots of an object are
 4053 * unused/dead when it is turned into a forwarding pointer - the
 4054 * forwarding pointer itself is just a header, but those data fields
 4055 * remain allocated.  Since the weak pair chain is a linked list that
 4056 * can *only* contain weak-pairs-turned-forwarding-pointer, we may
 4057 * freely access the first slot of such forwarding pointers.
 4058 */
 4059static C_regparm void C_fcall update_weak_pairs(int mode, C_byte *undead_start, C_byte *undead_end)
 4060{
 4061  int weakn = 0;
 4062  C_word p, pair, car, h;
 4063  C_byte *car_ptr;
 4064
 4065  /* NOTE: Don't use C_block_item() because it asserts the block is
 4066   * big enough in DEBUGBUILD, but forwarding pointers have size 0.
 4067   */
 4068  for (p = weak_pair_chain; p != (C_word)NULL; p = *((C_word *)C_data_pointer(p))) {
 4069    /* NOTE: We only chain up the weak pairs' forwarding pointers into
 4070     * the new space.  This is safe because already forwarded weak
 4071     * pairs in nursery/fromspace will be forwarded *again* into
 4072     * tospace/new heap.  That forwarding pointer is chained up.
 4073     * Still-unforwarded weak pairs will be forwarded straight to the
 4074     * new space, and also chained up.
 4075     */
 4076    h = C_block_header(p);
 4077    assert(is_fptr(h));
 4078    pair = fptr_to_ptr(h);
 4079    assert(!is_fptr(C_block_header(pair)));
 4080
 4081    /* The pair itself should be live */
 4082    assert((mode == GC_MINOR && !C_in_stackp(pair)) ||
 4083           (mode == GC_MAJOR && !C_in_stackp(pair) && !C_in_fromspacep(pair)) ||
 4084           (mode == GC_REALLOC && !C_in_stackp(pair) && !C_in_heapp(pair))); /* NB: *old* heap! */
 4085
 4086    car = C_block_item(pair, 0);
 4087    assert(!C_immediatep(car)); /* should be ensured when adding it to the chain */
 4088    h = C_block_header(car);
 4089    while (is_fptr(h)) {
 4090      car = fptr_to_ptr(h);
 4091      h = C_block_header(car);
 4092    }
 4093
 4094    car_ptr = (C_byte *)(C_uword)car;
 4095    /* If the car is unreferenced by anyone else, it wasn't moved by GC.  Or, if it's in the "undead" portion of
 4096       the new heap, it was moved because it was only referenced by a revived finalizable object.  In either case, drop it: */
 4097    if((mode == GC_MINOR && C_in_stackp(car)) ||
 4098       (mode == GC_MAJOR && (C_in_stackp(car) || C_in_fromspacep(car) || (car_ptr >= undead_start && car_ptr < undead_end))) ||
 4099       (mode == GC_REALLOC && (C_in_stackp(car) || C_in_heapp(car) || (car_ptr >= undead_start && car_ptr < undead_end)))) { /* NB: *old* heap! */
 4100
 4101      C_set_block_item(pair, 0, C_SCHEME_BROKEN_WEAK_PTR);
 4102      ++weakn;
 4103    } else {
 4104      /* Might have moved, re-set the car to the target value */
 4105      C_set_block_item(pair, 0, car);
 4106    }
 4107  }
 4108  weak_pair_chain = (C_word)NULL;
 4109  if(gc_report_flag && weakn)
 4110    C_dbg("GC", C_text("%d recoverable weak pairs found\n"), weakn);
 4111}
 4112
 4113/* Same as weak pairs (see above), but for locatives.  Note that this
 4114 * also includes non-weak locatives, as these point *into* an object,
 4115 * so the updating of that pointer is not handled by the GC proper
 4116 * (which only deals with full objects).
 4117 */
 4118static C_regparm void C_fcall update_locatives(int mode, C_byte *undead_start, C_byte *undead_end)
 4119{
 4120  int weakn = 0;
 4121  C_word p, loc, ptr, obj, h, offset;
 4122  C_byte *obj_ptr;
 4123
 4124  for (p = locative_chain; p != (C_word)NULL; p = *((C_word *)C_data_pointer(p))) {
 4125    h = C_block_header(p);
 4126    assert(is_fptr(h));
 4127    loc = fptr_to_ptr(h);
 4128    assert(!is_fptr(C_block_header(loc)));
 4129
 4130    /* The locative object itself should be live */
 4131    assert((mode == GC_MINOR && !C_in_stackp(loc)) ||
 4132           (mode == GC_MAJOR && !C_in_stackp(loc) && !C_in_fromspacep(loc)) ||
 4133           (mode == GC_REALLOC && !C_in_stackp(loc) && !C_in_heapp(loc))); /* NB: *old* heap! */
 4134
 4135    ptr = C_block_item(loc, 0); /* fix up ptr */
 4136    if (ptr == 0) continue; /* Skip already dropped weak locatives */
 4137    offset = C_unfix(C_block_item(loc, 1));
 4138    obj = ptr - offset;
 4139
 4140    h = C_block_header(obj);
 4141    while (is_fptr(h)) {
 4142      obj = fptr_to_ptr(h);
 4143      h = C_block_header(obj);
 4144    }
 4145
 4146    obj_ptr = (C_byte *)(C_uword)obj;
 4147    /* If the object is unreferenced by anyone else, it wasn't moved by GC.  Or, if it's in the "undead" portion of
 4148       the new heap, it was moved because it was only referenced by a revived finalizable object.  In either case, drop it: */
 4149    if((mode == GC_MINOR && C_in_stackp(obj)) ||
 4150       (mode == GC_MAJOR && (C_in_stackp(obj) || C_in_fromspacep(obj) || (obj_ptr >= undead_start && obj_ptr < undead_end))) ||
 4151       (mode == GC_REALLOC && (C_in_stackp(obj) || C_in_heapp(obj) || (obj_ptr >= undead_start && obj_ptr < undead_end)))) { /* NB: *old* heap! */
 4152
 4153      /* NOTE: This does *not* use BROKEN_WEAK_POINTER.  This slot
 4154       * holds an unaligned raw C pointer, not a Scheme object */
 4155      C_set_block_item(loc, 0, 0);
 4156      ++weakn;
 4157    } else {
 4158      /* Might have moved, re-set the object to the target value */
 4159      C_set_block_item(loc, 0, obj + offset);
 4160    }
 4161  }
 4162  locative_chain = (C_word)NULL;
 4163  if(gc_report_flag && weakn)
 4164    C_dbg("GC", C_text("%d recoverable weak locatives found\n"), weakn);
 4165}
 4166
 4167
 4168void handle_interrupt(void *trampoline)
 4169{
 4170  C_word *p, h, reason, state, proc, n;
 4171  double c;
 4172  C_word av[ 4 ]; 
 4173
 4174  /* Build vector with context information: */
 4175  n = C_temporary_stack_bottom - C_temporary_stack;
 4176  p = C_alloc(C_SIZEOF_VECTOR(2) + C_SIZEOF_VECTOR(n));
 4177  proc = (C_word)p;
 4178  *(p++) = C_VECTOR_TYPE | C_BYTEBLOCK_BIT | sizeof(C_word);
 4179  *(p++) = (C_word)trampoline;
 4180  state = (C_word)p;
 4181  *(p++) = C_VECTOR_TYPE | (n + 1);
 4182  *(p++) = proc;
 4183  C_memcpy(p, C_temporary_stack, n * sizeof(C_word));
 4184
 4185  /* Restore state to the one at the time of the interrupt: */
 4186  C_temporary_stack = C_temporary_stack_bottom;
 4187  C_stack_limit = C_stack_hard_limit;
 4188  
 4189  /* Invoke high-level interrupt handler: */
 4190  reason = C_fix(pending_interrupts[ --pending_interrupts_count ]);
 4191  proc = C_block_item(interrupt_hook_symbol, 0);
 4192
 4193  if(C_immediatep(proc))
 4194    panic(C_text("`##sys#interrupt-hook' is not defined"));
 4195
 4196  c = C_cpu_milliseconds() - interrupt_time;
 4197  last_interrupt_latency = c;
 4198  C_timer_interrupt_counter = C_initial_timer_interrupt_period;
 4199  /* <- no continuation is passed: "##sys#interrupt-hook" may not return! */
 4200  av[ 0 ] = proc;
 4201  av[ 1 ] = C_SCHEME_UNDEFINED;
 4202  av[ 2 ] = reason;
 4203  av[ 3 ] = state;
 4204  C_do_apply(4, av);
 4205}
 4206
 4207
 4208void 
 4209C_unbound_variable(C_word sym)
 4210{
 4211  barf(C_UNBOUND_VARIABLE_ERROR, NULL, sym);
 4212}
 4213
 4214
 4215/* XXX: This needs to be given a better name.
 4216   C_retrieve used to exist but it just called C_fast_retrieve */
 4217C_regparm C_word C_fcall C_retrieve2(C_word val, char *name)
 4218{
 4219  C_word *p;
 4220  int len;
 4221
 4222  if(val == C_SCHEME_UNBOUND) {
 4223    len = C_strlen(name);
 4224    /* this is ok: we won't return from `C_retrieve2'
 4225     * (or the value isn't needed). */
 4226    p = C_alloc(C_SIZEOF_STRING(len));
 4227    C_unbound_variable(C_string2(&p, name));
 4228  }
 4229
 4230  return val;
 4231}
 4232
 4233
 4234void C_ccall C_invalid_procedure(C_word c, C_word *av)
 4235{
 4236  C_word self = av[0];
 4237  barf(C_NOT_A_CLOSURE_ERROR, NULL, self);  
 4238}
 4239
 4240
 4241C_regparm void *C_fcall C_retrieve2_symbol_proc(C_word val, char *name)
 4242{
 4243  C_word *p;
 4244  int len;
 4245
 4246  if(val == C_SCHEME_UNBOUND) {
 4247    len = C_strlen(name);
 4248    /* this is ok: we won't return from `C_retrieve2' (or the value isn't needed). */
 4249    p = C_alloc(C_SIZEOF_STRING(len));
 4250    barf(C_UNBOUND_VARIABLE_ERROR, NULL, C_string2(&p, name));
 4251  }
 4252
 4253  return C_fast_retrieve_proc(val);
 4254}
 4255
 4256#ifdef C_NONUNIX
 4257VOID CALLBACK win_timer(PVOID data_ignored, BOOLEAN wait_or_fired)
 4258{
 4259  if (profiling) take_profile_sample();
 4260}
 4261#endif
 4262
 4263static void set_profile_timer(C_uword freq)
 4264{
 4265#ifdef C_NONUNIX
 4266  static HANDLE timer = NULL;
 4267
 4268  if (freq == 0) {
 4269    assert(timer != NULL);
 4270    if (!DeleteTimerQueueTimer(NULL, timer, NULL)) goto error;
 4271    timer = NULL;
 4272  } else if (freq < 1000) {
 4273    panic(C_text("On Windows, sampling can only be done in milliseconds"));
 4274  } else {
 4275    if (!CreateTimerQueueTimer(&timer, NULL, win_timer, NULL, 0, freq/1000, 0))
 4276      goto error;
 4277  }
 4278#else
 4279  struct itimerval itv;
 4280
 4281  itv.it_value.tv_sec = freq / 1000000;
 4282  itv.it_value.tv_usec = freq % 1000000;
 4283  itv.it_interval.tv_sec = itv.it_value.tv_sec;
 4284  itv.it_interval.tv_usec = itv.it_value.tv_usec;
 4285
 4286  if (setitimer(C_PROFILE_TIMER, &itv, NULL) == -1) goto error;
 4287#endif
 4288
 4289  return;
 4290
 4291error:
 4292  if (freq == 0) panic(C_text("error clearing timer for profiling"));
 4293  else panic(C_text("error setting timer for profiling"));
 4294}
 4295
 4296/* Bump profile count for current top of trace buffer */
 4297static void take_profile_sample()
 4298{
 4299  PROFILE_BUCKET **bp, *b;
 4300  C_char *key;
 4301  TRACE_INFO *tb;
 4302  /* To count distinct calls of a procedure, remember last call */
 4303  static C_char *prev_key = NULL;
 4304  static TRACE_INFO *prev_tb = NULL;
 4305
 4306  /* trace_buffer_top points *beyond* the topmost entry: Go back one */
 4307  if (trace_buffer_top == trace_buffer) {
 4308    if (!trace_buffer_full) return; /* No data yet */
 4309    tb = trace_buffer_limit - 1;
 4310  } else {
 4311    tb = trace_buffer_top - 1;
 4312  }
 4313
 4314  if (tb->raw_location != NULL) {
 4315    key = tb->raw_location;
 4316  } else {
 4317    key = "<eval>"; /* Location string is GCable, can't use it */
 4318  }
 4319
 4320  /* We could also just hash the pointer but that's a bit trickier */
 4321  bp = profile_table + hash_string(C_strlen(key), key, PROFILE_TABLE_SIZE, 0, 0);
 4322  b = *bp;
 4323
 4324  /* First try to find pre-existing item in hash table */
 4325  while(b != NULL) {
 4326    if(b->key == key) {
 4327      b->sample_count++;
 4328      if (prev_key != key && prev_tb != tb)
 4329        b->call_count++;
 4330      goto done;
 4331    }
 4332    else b = b->next;
 4333  }
 4334
 4335  /* Not found, allocate a new item and use it as bucket's new head */
 4336  b = next_profile_bucket;
 4337  next_profile_bucket = NULL;
 4338
 4339  assert(b != NULL);
 4340
 4341  b->next = *bp;
 4342  b->key = key;
 4343  *bp = b;
 4344  b->sample_count = 1;
 4345  b->call_count = 1;
 4346
 4347done:
 4348  prev_tb = tb;
 4349  prev_key = key;
 4350}
 4351
 4352
 4353C_regparm void C_fcall C_trace(C_char *name)
 4354{
 4355  C_word thread;
 4356
 4357  if(show_trace) {
 4358    C_fputs(name, C_stderr);
 4359    C_fputc('\n', C_stderr);
 4360  }
 4361
 4362  /*
 4363   * When profiling, pre-allocate profile bucket if necessary.  This
 4364   * is used in the signal handler, because it may not malloc.
 4365   */
 4366  if(profiling && next_profile_bucket == NULL) {
 4367    next_profile_bucket = (PROFILE_BUCKET *)C_malloc(sizeof(PROFILE_BUCKET));
 4368    if (next_profile_bucket == NULL) {
 4369      panic(C_text("out of memory - cannot allocate profile table-bucket"));
 4370    }
 4371  }
 4372
 4373  if(trace_buffer_top >= trace_buffer_limit) {
 4374    trace_buffer_top = trace_buffer;
 4375    trace_buffer_full = 1;
 4376  }
 4377
 4378  trace_buffer_top->raw_location = name;
 4379  trace_buffer_top->cooked_location = C_SCHEME_FALSE;
 4380  trace_buffer_top->cooked1 = C_SCHEME_FALSE;
 4381  trace_buffer_top->cooked2 = C_SCHEME_FALSE;
 4382  thread = C_block_item(current_thread_symbol, 0);
 4383  trace_buffer_top->thread = C_and(C_blockp(thread), C_thread_id(thread));
 4384  ++trace_buffer_top;
 4385}
 4386
 4387
 4388C_regparm C_word C_fcall C_emit_trace_info2(char *raw, C_word l, C_word x, C_word y, C_word t)
 4389{
 4390  /* See above */
 4391  if(profiling && next_profile_bucket == NULL) {
 4392    next_profile_bucket = (PROFILE_BUCKET *)C_malloc(sizeof(PROFILE_BUCKET));
 4393    if (next_profile_bucket == NULL) {
 4394      panic(C_text("out of memory - cannot allocate profile table-bucket"));
 4395    }
 4396  }
 4397
 4398  if(trace_buffer_top >= trace_buffer_limit) {
 4399    trace_buffer_top = trace_buffer;
 4400    trace_buffer_full = 1;
 4401  }
 4402
 4403  trace_buffer_top->raw_location = raw;
 4404  trace_buffer_top->cooked_location = l;
 4405  trace_buffer_top->cooked1 = x;
 4406  trace_buffer_top->cooked2 = y;
 4407  trace_buffer_top->thread = t;
 4408  ++trace_buffer_top;
 4409  return x;
 4410}
 4411
 4412
 4413C_char *C_dump_trace(int start)
 4414{
 4415  TRACE_INFO *ptr;
 4416  C_char *result;
 4417  int i, result_len;
 4418
 4419  result_len = STRING_BUFFER_SIZE;
 4420  if((result = (char *)C_malloc(result_len)) == NULL)
 4421    horror(C_text("out of memory - cannot allocate trace-dump buffer"));
 4422
 4423  *result = '\0';
 4424
 4425  if(trace_buffer_top > trace_buffer || trace_buffer_full) {
 4426    if(trace_buffer_full) {
 4427      i = C_trace_buffer_size;
 4428      C_strlcat(result, C_text("...more...\n"), result_len);
 4429    }
 4430    else i = trace_buffer_top - trace_buffer;
 4431
 4432    ptr = trace_buffer_full ? trace_buffer_top : trace_buffer;
 4433    ptr += start;
 4434    i -= start;
 4435
 4436    for(;i--; ++ptr) {
 4437      if(ptr >= trace_buffer_limit) ptr = trace_buffer;
 4438
 4439      if(C_strlen(result) > STRING_BUFFER_SIZE - 32) {
 4440        result_len = C_strlen(result) * 2;
 4441        result = C_realloc(result, result_len);
 4442	if(result == NULL)
 4443	  horror(C_text("out of memory - cannot reallocate trace-dump buffer"));
 4444      }
 4445
 4446      if (ptr->raw_location != NULL) {
 4447        C_strlcat(result, ptr->raw_location, result_len);
 4448      } else if (ptr->cooked_location != C_SCHEME_FALSE) {
 4449        C_strlcat(result, C_c_string(ptr->cooked_location), nmin(C_header_size(ptr->cooked_location), result_len));
 4450      } else {
 4451        C_strlcat(result, "<unknown>", result_len);
 4452      }
 4453
 4454      if(i > 0) C_strlcat(result, "\n", result_len);
 4455      else C_strlcat(result, " \t<--\n", result_len);
 4456    }
 4457  }
 4458
 4459  return result;
 4460}
 4461
 4462
 4463C_regparm void C_fcall C_clear_trace_buffer(void)
 4464{
 4465  int i, old_profiling = profiling;
 4466
 4467  profiling = 0;
 4468
 4469  if(trace_buffer == NULL) {
 4470    if(C_trace_buffer_size < MIN_TRACE_BUFFER_SIZE)
 4471      C_trace_buffer_size = MIN_TRACE_BUFFER_SIZE;
 4472
 4473    trace_buffer = (TRACE_INFO *)C_malloc(sizeof(TRACE_INFO) * C_trace_buffer_size);
 4474
 4475    if(trace_buffer == NULL)
 4476      panic(C_text("out of memory - cannot allocate trace-buffer"));
 4477  }
 4478
 4479  trace_buffer_top = trace_buffer;
 4480  trace_buffer_limit = trace_buffer + C_trace_buffer_size;
 4481  trace_buffer_full = 0;
 4482
 4483  for(i = 0; i < C_trace_buffer_size; ++i) {
 4484    trace_buffer[ i ].raw_location = NULL;
 4485    trace_buffer[ i ].cooked_location = C_SCHEME_FALSE;
 4486    trace_buffer[ i ].cooked1 = C_SCHEME_FALSE;
 4487    trace_buffer[ i ].cooked2 = C_SCHEME_FALSE;
 4488    trace_buffer[ i ].thread = C_SCHEME_FALSE;
 4489  }
 4490
 4491  profiling = old_profiling;
 4492}
 4493
 4494C_word C_resize_trace_buffer(C_word size) {
 4495  int old_size = C_trace_buffer_size, old_profiling = profiling;
 4496  assert(trace_buffer);
 4497  profiling = 0;
 4498  free(trace_buffer);
 4499  trace_buffer = NULL;
 4500  C_trace_buffer_size = C_unfix(size);
 4501  C_clear_trace_buffer();
 4502  profiling = old_profiling;
 4503  return(C_fix(old_size));
 4504}
 4505
 4506C_word C_fetch_trace(C_word starti, C_word buffer)
 4507{
 4508  TRACE_INFO *ptr;
 4509  int i, p = 0, start = C_unfix(starti);
 4510
 4511  if(trace_buffer_top > trace_buffer || trace_buffer_full) {
 4512    if(trace_buffer_full) i = C_trace_buffer_size;
 4513    else i = trace_buffer_top - trace_buffer;
 4514
 4515    ptr = trace_buffer_full ? trace_buffer_top : trace_buffer;
 4516    ptr += start;
 4517    i -= start;
 4518
 4519    if(C_header_size(buffer) < i * 5)
 4520      panic(C_text("destination buffer too small for call-chain"));
 4521
 4522    for(;i--; ++ptr) {
 4523      if(ptr >= trace_buffer_limit) ptr = trace_buffer;
 4524
 4525      /* outside-pointer, will be ignored by GC */
 4526      C_mutate(&C_block_item(buffer, p++), (C_word)ptr->raw_location);
 4527
 4528      /* subject to GC */
 4529      C_mutate(&C_block_item(buffer, p++), ptr->cooked_location);
 4530      C_mutate(&C_block_item(buffer, p++), ptr->cooked1);
 4531      C_mutate(&C_block_item(buffer, p++), ptr->cooked2);
 4532      C_mutate(&C_block_item(buffer, p++), ptr->thread);
 4533    }
 4534  }
 4535
 4536  return C_fix(p);
 4537}
 4538
 4539C_regparm C_word C_fcall C_u_i_string_hash(C_word str, C_word rnd)
 4540{
 4541  int len = C_header_size(str);
 4542  C_char *ptr = C_data_pointer(str);
 4543  return C_fix(hash_string(len, ptr, C_MOST_POSITIVE_FIXNUM, C_unfix(rnd), 0));
 4544}
 4545
 4546C_regparm C_word C_fcall C_u_i_string_ci_hash(C_word str, C_word rnd)
 4547{
 4548  int len = C_header_size(str);
 4549  C_char *ptr = C_data_pointer(str);
 4550  return C_fix(hash_string(len, ptr, C_MOST_POSITIVE_FIXNUM, C_unfix(rnd), 1));
 4551}
 4552
 4553C_regparm void C_fcall C_toplevel_entry(C_char *name)
 4554{
 4555  if(debug_mode)
 4556    C_dbg(C_text("debug"), C_text("entering %s...\n"), name);
 4557}
 4558
 4559C_regparm C_word C_fcall C_a_i_provide(C_word **a, int c, C_word id)
 4560{
 4561  if (debug_mode == 2) {
 4562    C_word str = C_block_item(id, 1);
 4563    C_snprintf(buffer, C_header_size(str) + 1, C_text("%s"), (C_char *) C_data_pointer(str));
 4564    C_dbg(C_text("debug"), C_text("providing %s...\n"), buffer);
 4565  }
 4566  return C_a_i_putprop(a, 3, core_provided_symbol, id, C_SCHEME_TRUE);
 4567}
 4568
 4569C_regparm C_word C_fcall C_i_providedp(C_word id)
 4570{
 4571  return C_i_getprop(core_provided_symbol, id, C_SCHEME_FALSE);
 4572}
 4573
 4574C_word C_halt(C_word msg)
 4575{
 4576  C_char *dmp = msg != C_SCHEME_FALSE ? C_dump_trace(0) : NULL;
 4577
 4578  if(C_gui_mode) {
 4579    if(msg != C_SCHEME_FALSE) {
 4580      int n = C_header_size(msg);
 4581
 4582      if (n >= sizeof(buffer))
 4583	n = sizeof(buffer) - 1;
 4584      C_strlcpy(buffer, (C_char *)C_data_pointer(msg), n);
 4585      /* XXX msg isn't checked for NUL bytes, but we can't barf here either! */
 4586    }
 4587    else C_strlcpy(buffer, C_text("(aborted)"), sizeof(buffer));
 4588
 4589    C_strlcat(buffer, C_text("\n\n"), sizeof(buffer));
 4590
 4591    if(dmp != NULL) C_strlcat(buffer, dmp, sizeof(buffer));
 4592
 4593#if defined(_WIN32) && !defined(__CYGWIN__) 
 4594    MessageBox(NULL, buffer, C_text("CHICKEN runtime"), MB_OK | MB_ICONERROR);
 4595    ExitProcess(1);
 4596#endif
 4597  } /* otherwise fall through */
 4598
 4599  if(msg != C_SCHEME_FALSE) {
 4600    C_fwrite(C_data_pointer(msg), C_header_size(msg), sizeof(C_char), C_stderr);
 4601    C_fputc('\n', C_stderr);
 4602  }
 4603
 4604  if(dmp != NULL) 
 4605    C_dbg("", C_text("\n%s"), dmp);
 4606  
 4607  C_exit_runtime(C_fix(EX_SOFTWARE));
 4608  return 0;
 4609}
 4610
 4611
 4612C_word C_message(C_word msg)
 4613{
 4614  unsigned int n = C_header_size(msg);
 4615  /*
 4616   * Strictly speaking this isn't necessary for the non-gui-mode,
 4617   * but let's try and keep this consistent across modes.
 4618   */
 4619  if (C_memchr(C_c_string(msg), '\0', n) != NULL)
 4620    barf(C_ASCIIZ_REPRESENTATION_ERROR, "##sys#message", msg);
 4621
 4622  if(C_gui_mode) {
 4623    if (n >= sizeof(buffer))
 4624      n = sizeof(buffer) - 1;
 4625    C_strncpy(buffer, C_c_string(msg), n);
 4626    buffer[ n ] = '\0';
 4627#if defined(_WIN32) && !defined(__CYGWIN__)
 4628    MessageBox(NULL, buffer, C_text("CHICKEN runtime"), MB_OK | MB_ICONEXCLAMATION);
 4629    return C_SCHEME_UNDEFINED;
 4630#endif
 4631  } /* fall through */
 4632
 4633  C_fwrite(C_c_string(msg), n, sizeof(C_char), stdout);
 4634  C_putchar('\n');
 4635  return C_SCHEME_UNDEFINED;
 4636}
 4637
 4638
 4639C_regparm C_word C_fcall C_equalp(C_word x, C_word y)
 4640{
 4641  C_header header;
 4642  C_word bits, n, i;
 4643
 4644  C_stack_check1(barf(C_CIRCULAR_DATA_ERROR, "equal?"));
 4645
 4646 loop:
 4647  if(x == y) return 1;
 4648
 4649  if(C_immediatep(x) || C_immediatep(y)) return 0;
 4650
 4651  /* NOTE: Extra check at the end is special consideration for pairs being equal to weak pairs */
 4652  if((header = C_block_header(x)) != C_block_header(y) && !(C_header_type(x) == C_PAIR_TYPE && C_header_type(y) == C_PAIR_TYPE)) return 0;
 4653  else if((bits = header & C_HEADER_BITS_MASK) & C_BYTEBLOCK_BIT) {
 4654    if(header == C_FLONUM_TAG && C_block_header(y) == C_FLONUM_TAG)
 4655      return C_ub_i_flonum_eqvp(C_flonum_magnitude(x),
 4656                                C_flonum_magnitude(y));
 4657    else return !C_memcmp(C_data_pointer(x), C_data_pointer(y), header & C_HEADER_SIZE_MASK);
 4658  }
 4659  else if(header == C_SYMBOL_TAG) return 0;
 4660  else {
 4661    i = 0;
 4662    n = header & C_HEADER_SIZE_MASK;
 4663
 4664    if(bits & C_SPECIALBLOCK_BIT) {
 4665      /* do not recurse into closures */
 4666      if(C_header_bits(x) == C_CLOSURE_TYPE)
 4667	return !C_memcmp(C_data_pointer(x), C_data_pointer(y), n * sizeof(C_word));
 4668      else if(C_block_item(x, 0) != C_block_item(y, 0)) return 0;
 4669      else ++i;
 4670
 4671      if(n == 1) return 1;
 4672    }
 4673
 4674    if(--n < 0) return 1;
 4675
 4676    while(i < n)
 4677      if(!C_equalp(C_block_item(x, i), C_block_item(y, i))) return 0;
 4678      else ++i;
 4679
 4680    x = C_block_item(x, i);
 4681    y = C_block_item(y, i);
 4682    goto loop;
 4683  }
 4684}
 4685
 4686
 4687C_regparm C_word C_fcall C_set_gc_report(C_word flag)
 4688{
 4689  if(flag == C_SCHEME_FALSE) gc_report_flag = 0;
 4690  else if(flag == C_SCHEME_TRUE) gc_report_flag = 2;
 4691  else gc_report_flag = 1;
 4692
 4693  return C_SCHEME_UNDEFINED;
 4694}
 4695
 4696C_regparm C_word C_fcall C_i_accumulated_gc_time(void)
 4697{
 4698  double tgc;
 4699
 4700  tgc = timer_accumulated_gc_ms;
 4701  timer_accumulated_gc_ms = 0;
 4702  return C_fix(tgc);
 4703}
 4704
 4705C_regparm C_word C_fcall C_start_timer(void)
 4706{
 4707  tracked_mutation_count = 0;
 4708  mutation_count = 0;
 4709  gc_count_1_total = 0;
 4710  gc_count_2 = 0;
 4711  timer_start_ms = C_cpu_milliseconds();
 4712  gc_ms = 0;
 4713  maximum_heap_usage = 0;
 4714  return C_SCHEME_UNDEFINED;
 4715}
 4716
 4717
 4718void C_ccall C_stop_timer(C_word c, C_word *av)
 4719{
 4720  C_word 
 4721    closure = av[ 0 ],
 4722    k = av[ 1 ];
 4723  double t0 = C_cpu_milliseconds() - timer_start_ms;
 4724  C_word 
 4725    ab[ WORDS_PER_FLONUM * 2 + C_SIZEOF_BIGNUM(1) + C_SIZEOF_VECTOR(7) ],
 4726    *a = ab,
 4727    elapsed = C_flonum(&a, t0 / 1000.0),
 4728    gc_time = C_flonum(&a, gc_ms / 1000.0),
 4729    heap_usage = C_unsigned_int_to_num(&a, maximum_heap_usage),
 4730    info;
 4731  
 4732  info = C_vector(&a, 7, elapsed, gc_time, C_fix(mutation_count),
 4733                  C_fix(tracked_mutation_count), C_fix(gc_count_1_total),
 4734		  C_fix(gc_count_2), heap_usage);
 4735  C_kontinue(k, info);
 4736}
 4737
 4738
 4739C_word C_exit_runtime(C_word code)
 4740{
 4741  C_fflush(NULL);
 4742  C__exit(C_unfix(code));
 4743}
 4744
 4745
 4746C_regparm C_word C_fcall C_set_print_precision(C_word n)
 4747{
 4748  flonum_print_precision = C_unfix(n);
 4749  return C_SCHEME_UNDEFINED;
 4750}
 4751
 4752
 4753C_regparm C_word C_fcall C_get_print_precision(void)
 4754{
 4755  return C_fix(flonum_print_precision);
 4756}
 4757
 4758
 4759C_regparm C_word C_fcall C_read_char(C_word port)
 4760{
 4761  C_FILEPTR fp = C_port_file(port);
 4762  int c = C_getc(fp);
 4763
 4764  if(c == EOF) {
 4765    if(ferror(fp)) {
 4766      clearerr(fp);
 4767      return C_fix(-1);
 4768    }
 4769    /* Found here:
 4770       http://mail.python.org/pipermail/python-bugs-list/2002-July/012579.html */
 4771#if defined(_WIN32) && !defined(__CYGWIN__)
 4772    else if(GetLastError() == ERROR_OPERATION_ABORTED) return C_fix(-1);
 4773#endif
 4774    else return C_SCHEME_END_OF_FILE;
 4775  }
 4776
 4777  return C_make_character(c);
 4778}
 4779
 4780
 4781C_regparm C_word C_fcall C_peek_char(C_word port)
 4782{
 4783  C_FILEPTR fp = C_port_file(port);
 4784  int c = C_getc(fp);
 4785
 4786  if(c == EOF) {
 4787    if(ferror(fp)) {
 4788      clearerr(fp);
 4789      return C_fix(-1);
 4790    }
 4791    /* see above */
 4792#if defined(_WIN32) && !defined(__CYGWIN__)
 4793    else if(GetLastError() == ERROR_OPERATION_ABORTED) return C_fix(-1);
 4794#endif
 4795    else return C_SCHEME_END_OF_FILE;
 4796  }
 4797
 4798  C_ungetc(c, fp);
 4799  return C_make_character(c);
 4800}
 4801
 4802
 4803C_regparm C_word C_fcall C_execute_shell_command(C_word string)
 4804{
 4805  int n = C_header_size(string);
 4806  char *buf = buffer;
 4807
 4808  /* Windows doc says to flush all output streams before calling system.
 4809     Probably a good idea for all platforms. */
 4810  (void)fflush(NULL);
 4811
 4812  if(n >= STRING_BUFFER_SIZE) {
 4813    if((buf = (char *)C_malloc(n + 1)) == NULL)
 4814      barf(C_OUT_OF_MEMORY_ERROR, "system");
 4815  }
 4816
 4817  C_memcpy(buf, C_data_pointer(string), n);
 4818  buf[ n ] = '\0';
 4819  if (n != strlen(buf))
 4820    barf(C_ASCIIZ_REPRESENTATION_ERROR, "system", string);
 4821
 4822  n = C_system(buf);
 4823
 4824  if(buf != buffer) C_free(buf);
 4825
 4826  return C_fix(n);
 4827}
 4828
 4829/*
 4830 * TODO: Implement something for Windows that supports selecting on
 4831 * arbitrary fds (there, select() only works on network sockets and
 4832 * poll() is not available at all).
 4833 */
 4834C_regparm int C_fcall C_check_fd_ready(int fd)
 4835{
 4836#ifdef NO_POSIX_POLL
 4837  fd_set in;
 4838  struct timeval tm;
 4839  int rv;
 4840  FD_ZERO(&in);
 4841  FD_SET(fd, &in);
 4842  tm.tv_sec = tm.tv_usec = 0;
 4843  rv = select(fd + 1, &in, NULL, NULL, &tm);
 4844  if(rv > 0) { rv = FD_ISSET(fd, &in) ? 1 : 0; }
 4845  return rv;
 4846#else
 4847  struct pollfd ps;
 4848  ps.fd = fd;
 4849  ps.events = POLLIN;
 4850  return poll(&ps, 1, 0);
 4851#endif
 4852}
 4853
 4854C_regparm C_word C_fcall C_char_ready_p(C_word port)
 4855{
 4856#if defined(C_NONUNIX)
 4857  /* The best we can currently do on Windows... */
 4858  return C_SCHEME_TRUE;
 4859#else
 4860  int fd = C_fileno(C_port_file(port));
 4861  return C_mk_bool(C_check_fd_ready(fd) == 1);
 4862#endif
 4863}
 4864
 4865C_regparm C_word C_fcall C_i_tty_forcedp(void)
 4866{
 4867  return C_mk_bool(fake_tty_flag);
 4868}
 4869
 4870C_regparm C_word C_fcall C_i_debug_modep(void)
 4871{
 4872  return C_mk_bool(debug_mode);
 4873}
 4874
 4875C_regparm C_word C_fcall C_i_dump_heap_on_exitp(void)
 4876{
 4877  return C_mk_bool(dump_heap_on_exit);
 4878}
 4879
 4880C_regparm C_word C_fcall C_i_profilingp(void)
 4881{
 4882  return C_mk_bool(profiling);
 4883}
 4884
 4885C_regparm C_word C_fcall C_i_live_finalizer_count(void)
 4886{
 4887  return C_fix(live_finalizer_count);
 4888}
 4889
 4890C_regparm C_word C_fcall C_i_allocated_finalizer_count(void)
 4891{
 4892  return C_fix(allocated_finalizer_count);
 4893}
 4894
 4895
 4896C_regparm void C_fcall C_raise_interrupt(int reason)
 4897{
 4898  if(C_interrupts_enabled) {
 4899    if(pending_interrupts_count == 0 && !handling_interrupts) {
 4900      pending_interrupts[ pending_interrupts_count++ ] = reason;
 4901      /*
 4902       * Force the next "soft" stack check to fail by faking a "full"
 4903       * stack.  This causes save_and_reclaim() to be called, which
 4904       * invokes handle_interrupt(), which restores the stack limit.
 4905       */
 4906      C_stack_limit = stack_bottom;
 4907      interrupt_time = C_cpu_milliseconds();
 4908    } else if(pending_interrupts_count < MAX_PENDING_INTERRUPTS) {
 4909      int i;
 4910      /*
 4911       * Drop signals if too many, but don't queue up multiple entries
 4912       * for the same signal.
 4913       */
 4914      for (i = 0; i < pending_interrupts_count; ++i) {
 4915        if (pending_interrupts[i] == reason)
 4916          return;
 4917      }
 4918      pending_interrupts[ pending_interrupts_count++ ] = reason;
 4919    }
 4920  }
 4921}
 4922
 4923
 4924C_regparm C_word C_fcall C_enable_interrupts(void)
 4925{
 4926  C_timer_interrupt_counter = C_initial_timer_interrupt_period;
 4927  /* assert(C_timer_interrupt_counter > 0); */
 4928  C_interrupts_enabled = 1;
 4929  return C_SCHEME_UNDEFINED;
 4930}
 4931
 4932
 4933C_regparm C_word C_fcall C_disable_interrupts(void)
 4934{
 4935  C_interrupts_enabled = 0;
 4936  return C_SCHEME_UNDEFINED;
 4937}
 4938
 4939
 4940C_regparm C_word C_fcall C_establish_signal_handler(C_word signum, C_word reason)
 4941{
 4942  int sig = C_unfix(signum);
 4943#if defined(HAVE_SIGACTION)
 4944  struct sigaction newsig;
 4945#endif
 4946
 4947  if(reason == C_SCHEME_FALSE) C_signal(sig, SIG_IGN);
 4948  else if(reason == C_SCHEME_TRUE) C_signal(sig, SIG_DFL);
 4949  else {
 4950    signal_mapping_table[ sig ] = C_unfix(reason);
 4951#if defined(HAVE_SIGACTION)
 4952    newsig.sa_flags = 0;
 4953    /* The global signal handler is used for all signals, and
 4954       manipulates a single queue.  Don't allow other signals to
 4955       concurrently arrive while it's doing this, to avoid races. */
 4956    sigfillset(&newsig.sa_mask);
 4957    newsig.sa_handler = global_signal_handler;
 4958    C_sigaction(sig, &newsig, NULL);
 4959#else
 4960    C_signal(sig, global_signal_handler);
 4961#endif
 4962  }
 4963
 4964  return C_SCHEME_UNDEFINED;
 4965}
 4966
 4967
 4968/* Copy blocks into collected or static memory: */
 4969
 4970C_regparm C_word C_fcall C_copy_block(C_word from, C_word to)
 4971{
 4972  int n = C_header_size(from);
 4973  C_long bytes;
 4974
 4975  if(C_header_bits(from) & C_BYTEBLOCK_BIT) {
 4976    bytes = n;
 4977    C_memcpy((C_SCHEME_BLOCK *)to, (C_SCHEME_BLOCK *)from, bytes + sizeof(C_header));
 4978  }
 4979  else {
 4980    bytes = C_wordstobytes(n);
 4981    C_memcpy((C_SCHEME_BLOCK *)to, (C_SCHEME_BLOCK *)from, bytes + sizeof(C_header));
 4982  }
 4983
 4984  return to;
 4985}
 4986
 4987
 4988C_regparm C_word C_fcall C_evict_block(C_word from, C_word ptr)
 4989{
 4990  int n = C_header_size(from);
 4991  C_long bytes;
 4992  C_word *p = (C_word *)C_pointer_address(ptr);
 4993
 4994  if(C_header_bits(from) & C_BYTEBLOCK_BIT) bytes = n;
 4995  else bytes = C_wordstobytes(n);
 4996
 4997  C_memcpy(p, (C_SCHEME_BLOCK *)from, bytes + sizeof(C_header));
 4998  return (C_word)p;
 4999}
 5000
 5001
 5002/* Inline versions of some standard procedures: */
 5003
 5004C_regparm C_word C_fcall C_i_listp(C_word x)
 5005{
 5006  C_word fast = x, slow = x;
 5007
 5008  while(fast != C_SCHEME_END_OF_LIST)
 5009    if(!C_immediatep(fast) && C_header_type(fast) == C_PAIR_TYPE) {
 5010      fast = C_u_i_cdr(fast);
 5011      
 5012      if(fast == C_SCHEME_END_OF_LIST) return C_SCHEME_TRUE;
 5013      else if(!C_immediatep(fast) && C_header_type(fast) == C_PAIR_TYPE) {
 5014	fast = C_u_i_cdr(fast);
 5015	slow = C_u_i_cdr(slow);
 5016
 5017	if(fast == slow) return C_SCHEME_FALSE;
 5018      }
 5019      else return C_SCHEME_FALSE;
 5020    }
 5021    else return C_SCHEME_FALSE;
 5022
 5023  return C_SCHEME_TRUE;
 5024}
 5025
 5026C_regparm C_word C_fcall C_i_u8vectorp(C_word x)
 5027{
 5028  return C_i_structurep(x, u8vector_symbol);
 5029}
 5030
 5031C_regparm C_word C_fcall C_i_s8vectorp(C_word x)
 5032{
 5033  return C_i_structurep(x, s8vector_symbol);
 5034}
 5035
 5036C_regparm C_word C_fcall C_i_u16vectorp(C_word x)
 5037{
 5038  return C_i_structurep(x, u16vector_symbol);
 5039}
 5040
 5041C_regparm C_word C_fcall C_i_s16vectorp(C_word x)
 5042{
 5043  return C_i_structurep(x, s16vector_symbol);
 5044}
 5045
 5046C_regparm C_word C_fcall C_i_u32vectorp(C_word x)
 5047{
 5048  return C_i_structurep(x, u32vector_symbol);
 5049}
 5050
 5051C_regparm C_word C_fcall C_i_s32vectorp(C_word x)
 5052{
 5053  return C_i_structurep(x, s32vector_symbol);
 5054}
 5055
 5056C_regparm C_word C_fcall C_i_u64vectorp(C_word x)
 5057{
 5058  return C_i_structurep(x, u64vector_symbol);
 5059}
 5060
 5061C_regparm C_word C_fcall C_i_s64vectorp(C_word x)
 5062{
 5063  return C_i_structurep(x, s64vector_symbol);
 5064}
 5065
 5066C_regparm C_word C_fcall C_i_f32vectorp(C_word x)
 5067{
 5068  return C_i_structurep(x, f32vector_symbol);
 5069}
 5070
 5071C_regparm C_word C_fcall C_i_f64vectorp(C_word x)
 5072{
 5073  return C_i_structurep(x, f64vector_symbol);
 5074}
 5075
 5076
 5077C_regparm C_word C_fcall C_i_string_equal_p(C_word x, C_word y)
 5078{
 5079  C_word n;
 5080
 5081  if(C_immediatep(x) || C_header_bits(x) != C_STRING_TYPE)
 5082    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string=?", x);
 5083
 5084  if(C_immediatep(y) || C_header_bits(y) != C_STRING_TYPE)
 5085    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string=?", y);
 5086
 5087  n = C_header_size(x);
 5088
 5089  return C_mk_bool(n == C_header_size(y)
 5090                   && !C_memcmp((char *)C_data_pointer(x), (char *)C_data_pointer(y), n));
 5091}
 5092
 5093
 5094C_regparm C_word C_fcall C_i_string_ci_equal_p(C_word x, C_word y)
 5095{
 5096  C_word n;
 5097  char *p1, *p2;
 5098
 5099  if(C_immediatep(x) || C_header_bits(x) != C_STRING_TYPE)
 5100    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string-ci=?", x);
 5101
 5102  if(C_immediatep(y) || C_header_bits(y) != C_STRING_TYPE)
 5103    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string-ci=?", y);
 5104
 5105  n = C_header_size(x);
 5106
 5107  if(n != C_header_size(y)) return C_SCHEME_FALSE;
 5108
 5109  p1 = (char *)C_data_pointer(x);
 5110  p2 = (char *)C_data_pointer(y);
 5111
 5112  while(n--) {
 5113    if(C_tolower((int)(*(p1++))) != C_tolower((int)(*(p2++))))
 5114      return C_SCHEME_FALSE;
 5115  }
 5116
 5117  return C_SCHEME_TRUE;
 5118}
 5119
 5120
 5121C_word C_a_i_list(C_word **a, int c, ...)
 5122{
 5123  va_list v;
 5124  C_word x, last, current,
 5125         first = C_SCHEME_END_OF_LIST;
 5126
 5127  va_start(v, c);
 5128
 5129  for(last = C_SCHEME_UNDEFINED; c--; last = current) {
 5130    x = va_arg(v, C_word);
 5131    current = C_a_pair(a, x, C_SCHEME_END_OF_LIST);
 5132
 5133    if(last != C_SCHEME_UNDEFINED)
 5134      C_set_block_item(last, 1, current);
 5135    else first = current;
 5136  }
 5137
 5138  va_end(v);
 5139  return first;
 5140}
 5141
 5142
 5143C_word C_a_i_string(C_word **a, int c, ...)
 5144{
 5145  va_list v;
 5146  C_word x, s = (C_word)(*a);
 5147  char *p;
 5148
 5149  *a = (C_word *)((C_word)(*a) + sizeof(C_header) + C_align(c));
 5150  C_block_header_init(s, C_STRING_TYPE | c);
 5151  p = (char *)C_data_pointer(s);
 5152  va_start(v, c);
 5153
 5154  for(; c; c--) {
 5155    x = va_arg(v, C_word);
 5156
 5157    if((x & C_IMMEDIATE_TYPE_BITS) == C_CHARACTER_BITS)
 5158      *(p++) = C_character_code(x);
 5159    else break;
 5160  }
 5161
 5162  va_end(v);
 5163  if (c) barf(C_BAD_ARGUMENT_TYPE_ERROR, "string", x);
 5164  return s;
 5165}
 5166
 5167
 5168C_word C_a_i_record(C_word **ptr, int n, ...)
 5169{
 5170  va_list v;
 5171  C_word *p = *ptr,
 5172         *p0 = p; 
 5173
 5174  *(p++) = C_STRUCTURE_TYPE | n;
 5175  va_start(v, n);
 5176
 5177  while(n--)
 5178    *(p++) = va_arg(v, C_word);
 5179
 5180  *ptr = p;
 5181  va_end(v);
 5182  return (C_word)p0;
 5183}
 5184
 5185
 5186C_word C_a_i_port(C_word **ptr, int n)
 5187{
 5188  C_word 
 5189    *p = *ptr,
 5190    *p0 = p; 
 5191  int i;
 5192
 5193  *(p++) = C_PORT_TYPE | (C_SIZEOF_PORT - 1);
 5194  *(p++) = (C_word)NULL;
 5195  
 5196  for(i = 0; i < C_SIZEOF_PORT - 2; ++i)
 5197    *(p++) = C_SCHEME_FALSE;
 5198
 5199  *ptr = p;
 5200  return (C_word)p0;
 5201}
 5202
 5203
 5204C_regparm C_word C_fcall C_a_i_bytevector(C_word **ptr, int c, C_word num)
 5205{
 5206  C_word *p = *ptr,
 5207         *p0;
 5208  int n = C_unfix(num);
 5209
 5210#ifndef C_SIXTY_FOUR
 5211  /* Align on 8-byte boundary: */
 5212  if(C_aligned8(p)) ++p;
 5213#endif
 5214
 5215  p0 = p;
 5216  *(p++) = C_BYTEVECTOR_TYPE | C_wordstobytes(n);
 5217  *ptr = p + n;
 5218  return (C_word)p0;
 5219}
 5220
 5221
 5222C_word C_fcall C_a_i_smart_mpointer(C_word **ptr, int c, C_word x)
 5223{
 5224  C_word 
 5225    *p = *ptr,
 5226    *p0 = p;
 5227  void *mp;
 5228
 5229  if(C_immediatep(x)) mp = NULL;
 5230  else if((C_header_bits(x) & C_SPECIALBLOCK_BIT) != 0) mp = C_pointer_address(x);
 5231  else mp = C_data_pointer(x);
 5232
 5233  *(p++) = C_POINTER_TYPE | 1;
 5234  *((void **)p) = mp;
 5235  *ptr = p + 1;
 5236  return (C_word)p0;
 5237}
 5238
 5239C_regparm C_word C_fcall C_i_nanp(C_word x)
 5240{
 5241  if (x & C_FIXNUM_BIT) {
 5242    return C_SCHEME_FALSE;
 5243  } else if (C_immediatep(x)) {
 5244    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "nan?", x);
 5245  } else if (C_block_header(x) == C_FLONUM_TAG) {
 5246    return C_u_i_flonum_nanp(x);
 5247  } else if (C_truep(C_bignump(x))) {
 5248    return C_SCHEME_FALSE;
 5249  } else if (C_block_header(x) == C_RATNUM_TAG) {
 5250    return C_SCHEME_FALSE;
 5251  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 5252    return C_mk_bool(C_truep(C_i_nanp(C_u_i_cplxnum_real(x))) ||
 5253		     C_truep(C_i_nanp(C_u_i_cplxnum_imag(x))));
 5254  } else {
 5255    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "nan?", x);
 5256  }
 5257}
 5258
 5259C_regparm C_word C_fcall C_i_finitep(C_word x)
 5260{
 5261  if (x & C_FIXNUM_BIT) {
 5262    return C_SCHEME_TRUE;
 5263  } else if (C_immediatep(x)) {
 5264    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "finite?", x);
 5265  } else if (C_block_header(x) == C_FLONUM_TAG) {
 5266    return C_u_i_flonum_finitep(x);
 5267  } else if (C_truep(C_bignump(x))) {
 5268    return C_SCHEME_TRUE;
 5269  } else if (C_block_header(x) == C_RATNUM_TAG) {
 5270    return C_SCHEME_TRUE;
 5271  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 5272    return C_and(C_i_finitep(C_u_i_cplxnum_real(x)),
 5273		 C_i_finitep(C_u_i_cplxnum_imag(x)));
 5274  } else {
 5275    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "finite?", x);
 5276  }
 5277}
 5278
 5279C_regparm C_word C_fcall C_i_infinitep(C_word x)
 5280{
 5281  if (x & C_FIXNUM_BIT) {
 5282    return C_SCHEME_FALSE;
 5283  } else if (C_immediatep(x)) {
 5284    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "infinite?", x);
 5285  } else if (C_block_header(x) == C_FLONUM_TAG) {
 5286    return C_u_i_flonum_infinitep(x);
 5287  } else if (C_truep(C_bignump(x))) {
 5288    return C_SCHEME_FALSE;
 5289  } else if (C_block_header(x) == C_RATNUM_TAG) {
 5290    return C_SCHEME_FALSE;
 5291  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 5292    return C_mk_bool(C_truep(C_i_infinitep(C_u_i_cplxnum_real(x))) ||
 5293                     C_truep(C_i_infinitep(C_u_i_cplxnum_imag(x))));
 5294  } else {
 5295    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "infinite?", x);
 5296  }
 5297}
 5298
 5299C_regparm C_word C_fcall C_i_exactp(C_word x)
 5300{
 5301  if (x & C_FIXNUM_BIT) {
 5302    return C_SCHEME_TRUE;
 5303  } else if (C_immediatep(x)) {
 5304    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "exact?", x);
 5305  } else if (C_block_header(x) == C_FLONUM_TAG) {
 5306    return C_SCHEME_FALSE;
 5307  } else if (C_truep(C_bignump(x))) {
 5308    return C_SCHEME_TRUE;
 5309  } else if (C_block_header(x) == C_RATNUM_TAG) {
 5310    return C_SCHEME_TRUE;
 5311  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 5312    return C_i_exactp(C_u_i_cplxnum_real(x)); /* Exactness of i and r matches */
 5313  } else {
 5314    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "exact?", x);
 5315  }
 5316}
 5317
 5318
 5319C_regparm C_word C_fcall C_i_inexactp(C_word x)
 5320{
 5321  if (x & C_FIXNUM_BIT) {
 5322    return C_SCHEME_FALSE;
 5323  } else if (C_immediatep(x)) {
 5324    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "inexact?", x);
 5325  } else if (C_block_header(x) == C_FLONUM_TAG) {
 5326    return C_SCHEME_TRUE;
 5327  } else if (C_truep(C_bignump(x))) {
 5328    return C_SCHEME_FALSE;
 5329  } else if (C_block_header(x) == C_RATNUM_TAG) {
 5330    return C_SCHEME_FALSE;
 5331  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 5332    return C_i_inexactp(C_u_i_cplxnum_real(x)); /* Exactness of i and r matches */
 5333  } else {
 5334    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "inexact?", x);
 5335  }
 5336}
 5337
 5338
 5339C_regparm C_word C_fcall C_i_zerop(C_word x)
 5340{
 5341  if (x & C_FIXNUM_BIT) {
 5342    return C_mk_bool(x == C_fix(0));
 5343  } else if (C_immediatep(x)) {
 5344    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "zero?", x);
 5345  } else if (C_block_header(x) == C_FLONUM_TAG) {
 5346    return C_mk_bool(C_flonum_magnitude(x) == 0.0);
 5347  } else if (C_block_header(x) == C_BIGNUM_TAG ||
 5348             C_block_header(x) == C_RATNUM_TAG ||
 5349             C_block_header(x) == C_CPLXNUM_TAG) {
 5350    return C_SCHEME_FALSE;
 5351  } else {
 5352    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "zero?", x);
 5353  }
 5354}
 5355
 5356/* DEPRECATED */
 5357C_regparm C_word C_fcall C_u_i_zerop(C_word x)
 5358{
 5359  return C_mk_bool(x == C_fix(0) ||
 5360                   (!C_immediatep(x) &&
 5361                    C_block_header(x) == C_FLONUM_TAG &&
 5362                    C_flonum_magnitude(x) == 0.0));
 5363}
 5364
 5365
 5366C_regparm C_word C_fcall C_i_positivep(C_word x)
 5367{
 5368  if (x & C_FIXNUM_BIT)
 5369    return C_i_fixnum_positivep(x);
 5370  else if (C_immediatep(x))
 5371    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "positive?", x);
 5372  else if (C_block_header(x) == C_FLONUM_TAG)
 5373    return C_mk_bool(C_flonum_magnitude(x) > 0.0);
 5374  else if (C_truep(C_bignump(x)))
 5375    return C_mk_nbool(C_bignum_negativep(x));
 5376  else if (C_block_header(x) == C_RATNUM_TAG)
 5377    return C_i_integer_positivep(C_u_i_ratnum_num(x));
 5378  else if (C_block_header(x) == C_CPLXNUM_TAG)
 5379    barf(C_BAD_ARGUMENT_TYPE_NO_REAL_ERROR, "positive?", x);
 5380  else
 5381    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "positive?", x);
 5382}
 5383
 5384C_regparm C_word C_fcall C_i_integer_positivep(C_word x)
 5385{
 5386  if (x & C_FIXNUM_BIT) return C_i_fixnum_positivep(x);
 5387  else return C_mk_nbool(C_bignum_negativep(x));
 5388}
 5389
 5390C_regparm C_word C_fcall C_i_negativep(C_word x)
 5391{
 5392  if (x & C_FIXNUM_BIT)
 5393    return C_i_fixnum_negativep(x);
 5394  else if (C_immediatep(x))
 5395    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "negative?", x);
 5396  else if (C_block_header(x) == C_FLONUM_TAG)
 5397    return C_mk_bool(C_flonum_magnitude(x) < 0.0);
 5398  else if (C_truep(C_bignump(x)))
 5399    return C_mk_bool(C_bignum_negativep(x));
 5400  else if (C_block_header(x) == C_RATNUM_TAG)
 5401    return C_i_integer_negativep(C_u_i_ratnum_num(x));
 5402  else if (C_block_header(x) == C_CPLXNUM_TAG)
 5403    barf(C_BAD_ARGUMENT_TYPE_NO_REAL_ERROR, "negative?", x);
 5404  else
 5405    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "negative?", x);
 5406}
 5407
 5408
 5409C_regparm C_word C_fcall C_i_integer_negativep(C_word x)
 5410{
 5411  if (x & C_FIXNUM_BIT) return C_i_fixnum_negativep(x);
 5412  else return C_mk_bool(C_bignum_negativep(x));
 5413}
 5414
 5415
 5416C_regparm C_word C_fcall C_i_evenp(C_word x)
 5417{
 5418  if(x & C_FIXNUM_BIT) {
 5419    return C_i_fixnumevenp(x);
 5420  } else if(C_immediatep(x)) {
 5421    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "even?", x);
 5422  } else if (C_block_header(x) == C_FLONUM_TAG) {
 5423    double val, dummy;
 5424    val = C_flonum_magnitude(x);
 5425    if(C_isnan(val) || C_isinf(val) || C_modf(val, &dummy) != 0.0)
 5426      barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "even?", x);
 5427    else
 5428      return C_mk_bool(fmod(val, 2.0) == 0.0);
 5429  } else if (C_truep(C_bignump(x))) {
 5430    return C_mk_nbool(C_bignum_digits(x)[0] & 1);
 5431  } else { /* No need to try extended number */
 5432    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "even?", x);
 5433  }
 5434}
 5435
 5436C_regparm C_word C_fcall C_i_integer_evenp(C_word x)
 5437{
 5438  if (x & C_FIXNUM_BIT) return C_i_fixnumevenp(x);
 5439  return C_mk_nbool(C_bignum_digits(x)[0] & 1);
 5440}
 5441
 5442
 5443C_regparm C_word C_fcall C_i_oddp(C_word x)
 5444{
 5445  if(x & C_FIXNUM_BIT) {
 5446    return C_i_fixnumoddp(x);
 5447  } else if(C_immediatep(x)) {
 5448    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "odd?", x);
 5449  } else if(C_block_header(x) == C_FLONUM_TAG) {
 5450    double val, dummy;
 5451    val = C_flonum_magnitude(x);
 5452    if(C_isnan(val) || C_isinf(val) || C_modf(val, &dummy) != 0.0)
 5453      barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "odd?", x);
 5454    else
 5455      return C_mk_bool(fmod(val, 2.0) != 0.0);
 5456  } else if (C_truep(C_bignump(x))) {
 5457    return C_mk_bool(C_bignum_digits(x)[0] & 1);
 5458  } else {
 5459    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "odd?", x);
 5460  }
 5461}
 5462
 5463
 5464C_regparm C_word C_fcall C_i_integer_oddp(C_word x)
 5465{
 5466  if (x & C_FIXNUM_BIT) return C_i_fixnumoddp(x);
 5467  return C_mk_bool(C_bignum_digits(x)[0] & 1);
 5468}
 5469
 5470
 5471C_regparm C_word C_fcall C_i_car(C_word x)
 5472{
 5473  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE)
 5474    barf(C_BAD_ARGUMENT_TYPE_ERROR, "car", x);
 5475
 5476  return C_u_i_car(x);
 5477}
 5478
 5479
 5480C_regparm C_word C_fcall C_i_cdr(C_word x)
 5481{
 5482  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE)
 5483    barf(C_BAD_ARGUMENT_TYPE_ERROR, "cdr", x);
 5484
 5485  return C_u_i_cdr(x);
 5486}
 5487
 5488
 5489C_regparm C_word C_fcall C_i_caar(C_word x)
 5490{
 5491  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 5492  bad:
 5493    barf(C_BAD_ARGUMENT_TYPE_ERROR, "caar", x);
 5494  }
 5495
 5496  x = C_u_i_car(x);
 5497
 5498  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5499
 5500  return C_u_i_car(x);
 5501}
 5502
 5503
 5504C_regparm C_word C_fcall C_i_cadr(C_word x)
 5505{
 5506  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 5507  bad:
 5508    barf(C_BAD_ARGUMENT_TYPE_ERROR, "cadr", x);
 5509  }
 5510
 5511  x = C_u_i_cdr(x);
 5512
 5513  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5514
 5515  return C_u_i_car(x);
 5516}
 5517
 5518
 5519C_regparm C_word C_fcall C_i_cdar(C_word x)
 5520{
 5521  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 5522  bad:
 5523    barf(C_BAD_ARGUMENT_TYPE_ERROR, "cdar", x);
 5524  }
 5525
 5526  x = C_u_i_car(x);
 5527
 5528  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5529
 5530  return C_u_i_cdr(x);
 5531}
 5532
 5533
 5534C_regparm C_word C_fcall C_i_cddr(C_word x)
 5535{
 5536  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 5537  bad:
 5538    barf(C_BAD_ARGUMENT_TYPE_ERROR, "cddr", x);
 5539  }
 5540
 5541  x = C_u_i_cdr(x);
 5542  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5543
 5544  return C_u_i_cdr(x);
 5545}
 5546
 5547
 5548C_regparm C_word C_fcall C_i_caddr(C_word x)
 5549{
 5550  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 5551  bad:
 5552    barf(C_BAD_ARGUMENT_TYPE_ERROR, "caddr", x);
 5553  }
 5554
 5555  x = C_u_i_cdr(x);
 5556  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5557  x = C_u_i_cdr(x);
 5558  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5559
 5560  return C_u_i_car(x);
 5561}
 5562
 5563
 5564C_regparm C_word C_fcall C_i_cdddr(C_word x)
 5565{
 5566  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 5567  bad:
 5568    barf(C_BAD_ARGUMENT_TYPE_ERROR, "cdddr", x);
 5569  }
 5570
 5571  x = C_u_i_cdr(x);
 5572  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5573  x = C_u_i_cdr(x);
 5574  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5575
 5576  return C_u_i_cdr(x);
 5577}
 5578
 5579
 5580C_regparm C_word C_fcall C_i_cadddr(C_word x)
 5581{
 5582  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 5583  bad:
 5584    barf(C_BAD_ARGUMENT_TYPE_ERROR, "cadddr", x);
 5585  }
 5586
 5587  x = C_u_i_cdr(x);
 5588  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5589  x = C_u_i_cdr(x);
 5590  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5591  x = C_u_i_cdr(x);
 5592  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5593
 5594  return C_u_i_car(x);
 5595}
 5596
 5597
 5598C_regparm C_word C_fcall C_i_cddddr(C_word x)
 5599{
 5600  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 5601  bad:
 5602    barf(C_BAD_ARGUMENT_TYPE_ERROR, "cddddr", x);
 5603  }
 5604
 5605  x = C_u_i_cdr(x);
 5606  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5607  x = C_u_i_cdr(x);
 5608  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5609  x = C_u_i_cdr(x);
 5610  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5611
 5612  return C_u_i_cdr(x);
 5613}
 5614
 5615
 5616C_regparm C_word C_fcall C_i_list_tail(C_word lst, C_word i)
 5617{
 5618  C_word lst0 = lst;
 5619  int n;
 5620
 5621  if(lst != C_SCHEME_END_OF_LIST && 
 5622     (C_immediatep(lst) || C_header_type(lst) != C_PAIR_TYPE))
 5623    barf(C_BAD_ARGUMENT_TYPE_ERROR, "list-tail", lst);
 5624
 5625  if(i & C_FIXNUM_BIT) n = C_unfix(i);
 5626  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "list-tail", i);
 5627
 5628  while(n--) {
 5629    if(C_immediatep(lst) || C_header_type(lst) != C_PAIR_TYPE)
 5630      barf(C_OUT_OF_RANGE_ERROR, "list-tail", lst0, i);
 5631    
 5632    lst = C_u_i_cdr(lst);
 5633  }
 5634
 5635  return lst;
 5636}
 5637
 5638
 5639C_regparm C_word C_fcall C_i_vector_ref(C_word v, C_word i)
 5640{
 5641  int j;
 5642
 5643  if(C_immediatep(v) || C_header_bits(v) != C_VECTOR_TYPE)
 5644    barf(C_BAD_ARGUMENT_TYPE_ERROR, "vector-ref", v);
 5645
 5646  if(i & C_FIXNUM_BIT) {
 5647    j = C_unfix(i);
 5648
 5649    if(j < 0 || j >= C_header_size(v)) barf(C_OUT_OF_RANGE_ERROR, "vector-ref", v, i);
 5650
 5651    return C_block_item(v, j);
 5652  }
 5653  
 5654  barf(C_BAD_ARGUMENT_TYPE_ERROR, "vector-ref", i);
 5655  return C_SCHEME_UNDEFINED;
 5656}
 5657
 5658
 5659C_regparm C_word C_fcall C_i_u8vector_ref(C_word v, C_word i)
 5660{
 5661  int j;
 5662
 5663  if(!C_truep(C_i_u8vectorp(v)))
 5664    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u8vector-ref", v);
 5665
 5666  if(i & C_FIXNUM_BIT) {
 5667    j = C_unfix(i);
 5668
 5669    if(j < 0 || j >= C_header_size(C_block_item(v, 1))) barf(C_OUT_OF_RANGE_ERROR, "u8vector-ref", v, i);
 5670
 5671    return C_fix(((unsigned char *)C_data_pointer(C_block_item(v, 1)))[j]);
 5672  }
 5673  
 5674  barf(C_BAD_ARGUMENT_TYPE_ERROR, "u8vector-ref", i);
 5675  return C_SCHEME_UNDEFINED;
 5676}
 5677
 5678C_regparm C_word C_fcall C_i_s8vector_ref(C_word v, C_word i)
 5679{
 5680  int j;
 5681
 5682  if(!C_truep(C_i_s8vectorp(v)))
 5683    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s8vector-ref", v);
 5684
 5685  if(i & C_FIXNUM_BIT) {
 5686    j = C_unfix(i);
 5687
 5688    if(j < 0 || j >= C_header_size(C_block_item(v, 1))) barf(C_OUT_OF_RANGE_ERROR, "s8vector-ref", v, i);
 5689
 5690    return C_fix(((signed char *)C_data_pointer(C_block_item(v, 1)))[j]);
 5691  }
 5692  
 5693  barf(C_BAD_ARGUMENT_TYPE_ERROR, "s8vector-ref", i);
 5694  return C_SCHEME_UNDEFINED;
 5695}
 5696
 5697C_regparm C_word C_fcall C_i_u16vector_ref(C_word v, C_word i)
 5698{
 5699  int j;
 5700
 5701  if(!C_truep(C_i_u16vectorp(v)))
 5702    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u16vector-ref", v);
 5703
 5704  if(i & C_FIXNUM_BIT) {
 5705    j = C_unfix(i);
 5706
 5707    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 1)) barf(C_OUT_OF_RANGE_ERROR, "u16vector-ref", v, i);
 5708
 5709    return C_fix(((unsigned short *)C_data_pointer(C_block_item(v, 1)))[j]);
 5710  }
 5711  
 5712  barf(C_BAD_ARGUMENT_TYPE_ERROR, "u16vector-ref", i);
 5713  return C_SCHEME_UNDEFINED;
 5714}
 5715
 5716C_regparm C_word C_fcall C_i_s16vector_ref(C_word v, C_word i)
 5717{
 5718  C_word size;
 5719  int j;
 5720
 5721  if(C_immediatep(v) || C_header_bits(v) != C_STRUCTURE_TYPE ||
 5722     C_header_size(v) != 2 || C_block_item(v, 0) != s16vector_symbol)
 5723    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s16vector-ref", v);
 5724
 5725  if(i & C_FIXNUM_BIT) {
 5726    j = C_unfix(i);
 5727
 5728    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 1)) barf(C_OUT_OF_RANGE_ERROR, "u16vector-ref", v, i);
 5729
 5730    return C_fix(((signed short *)C_data_pointer(C_block_item(v, 1)))[j]);
 5731  }
 5732  
 5733  barf(C_BAD_ARGUMENT_TYPE_ERROR, "s16vector-ref", i);
 5734  return C_SCHEME_UNDEFINED;
 5735}
 5736
 5737C_regparm C_word C_fcall C_a_i_u32vector_ref(C_word **ptr, C_word c, C_word v, C_word i)
 5738{
 5739  int j;
 5740
 5741  if(!C_truep(C_i_u32vectorp(v)))
 5742    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u32vector-ref", v);
 5743
 5744  if(i & C_FIXNUM_BIT) {
 5745    j = C_unfix(i);
 5746
 5747    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 2)) barf(C_OUT_OF_RANGE_ERROR, "u32vector-ref", v, i);
 5748
 5749    return C_unsigned_int_to_num(ptr, ((C_u32 *)C_data_pointer(C_block_item(v, 1)))[j]);
 5750  }
 5751  
 5752  barf(C_BAD_ARGUMENT_TYPE_ERROR, "u32vector-ref", i);
 5753  return C_SCHEME_UNDEFINED;
 5754}
 5755
 5756C_regparm C_word C_fcall C_a_i_s32vector_ref(C_word **ptr, C_word c, C_word v, C_word i)
 5757{
 5758  int j;
 5759
 5760  if(!C_truep(C_i_s32vectorp(v)))
 5761    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s32vector-ref", v);
 5762
 5763  if(i & C_FIXNUM_BIT) {
 5764    j = C_unfix(i);
 5765
 5766    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 2)) barf(C_OUT_OF_RANGE_ERROR, "s32vector-ref", v, i);
 5767
 5768    return C_int_to_num(ptr, ((C_s32 *)C_data_pointer(C_block_item(v, 1)))[j]);
 5769  }
 5770  
 5771  barf(C_BAD_ARGUMENT_TYPE_ERROR, "s32vector-ref", i);
 5772  return C_SCHEME_UNDEFINED;
 5773}
 5774
 5775C_regparm C_word C_fcall C_a_i_u64vector_ref(C_word **ptr, C_word c, C_word v, C_word i)
 5776{
 5777  int j;
 5778
 5779  if(!C_truep(C_i_u64vectorp(v)))
 5780    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u64vector-ref", v);
 5781
 5782  if(i & C_FIXNUM_BIT) {
 5783    j = C_unfix(i);
 5784
 5785    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 3)) barf(C_OUT_OF_RANGE_ERROR, "u64vector-ref", v, i);
 5786
 5787    return C_uint64_to_num(ptr, ((C_u64 *)C_data_pointer(C_block_item(v, 1)))[j]);
 5788  }
 5789  
 5790  barf(C_BAD_ARGUMENT_TYPE_ERROR, "u64vector-ref", i);
 5791  return C_SCHEME_UNDEFINED;
 5792}
 5793
 5794C_regparm C_word C_fcall C_a_i_s64vector_ref(C_word **ptr, C_word c, C_word v, C_word i)
 5795{
 5796  int j;
 5797
 5798  if(!C_truep(C_i_s64vectorp(v)))
 5799    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s64vector-ref", v);
 5800
 5801  if(i & C_FIXNUM_BIT) {
 5802    j = C_unfix(i);
 5803
 5804    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 3)) barf(C_OUT_OF_RANGE_ERROR, "s64vector-ref", v, i);
 5805
 5806    return C_int64_to_num(ptr, ((C_s64 *)C_data_pointer(C_block_item(v, 1)))[j]);
 5807  }
 5808  
 5809  barf(C_BAD_ARGUMENT_TYPE_ERROR, "s64vector-ref", i);
 5810  return C_SCHEME_UNDEFINED;
 5811}
 5812
 5813C_regparm C_word C_fcall C_a_i_f32vector_ref(C_word **ptr, C_word c, C_word v, C_word i)
 5814{
 5815  int j;
 5816
 5817  if(!C_truep(C_i_f32vectorp(v)))
 5818    barf(C_BAD_ARGUMENT_TYPE_ERROR, "f32vector-ref", v);
 5819
 5820  if(i & C_FIXNUM_BIT) {
 5821    j = C_unfix(i);
 5822
 5823    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 2)) barf(C_OUT_OF_RANGE_ERROR, "f32vector-ref", v, i);
 5824
 5825    return C_flonum(ptr, ((float *)C_data_pointer(C_block_item(v, 1)))[j]);
 5826  }
 5827  
 5828  barf(C_BAD_ARGUMENT_TYPE_ERROR, "f32vector-ref", i);
 5829  return C_SCHEME_UNDEFINED;
 5830}
 5831
 5832C_regparm C_word C_fcall C_a_i_f64vector_ref(C_word **ptr, C_word c, C_word v, C_word i)
 5833{
 5834  C_word size;
 5835  int j;
 5836
 5837  if(!C_truep(C_i_f64vectorp(v)))
 5838    barf(C_BAD_ARGUMENT_TYPE_ERROR, "f64vector-ref", v);
 5839
 5840  if(i & C_FIXNUM_BIT) {
 5841    j = C_unfix(i);
 5842
 5843    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 3)) barf(C_OUT_OF_RANGE_ERROR, "f64vector-ref", v, i);
 5844
 5845    return C_flonum(ptr, ((double *)C_data_pointer(C_block_item(v, 1)))[j]);
 5846  }
 5847  
 5848  barf(C_BAD_ARGUMENT_TYPE_ERROR, "f64vector-ref", i);
 5849  return C_SCHEME_UNDEFINED;
 5850}
 5851
 5852
 5853C_regparm C_word C_fcall C_i_block_ref(C_word x, C_word i)
 5854{
 5855  int j;
 5856
 5857  if(C_immediatep(x) || (C_header_bits(x) & C_BYTEBLOCK_BIT) != 0)
 5858    barf(C_BAD_ARGUMENT_TYPE_NO_BLOCK_ERROR, "##sys#block-ref", x);
 5859
 5860  if(i & C_FIXNUM_BIT) {
 5861    j = C_unfix(i);
 5862
 5863    if(j < 0 || j >= C_header_size(x)) barf(C_OUT_OF_RANGE_ERROR, "##sys#block-ref", x, i);
 5864
 5865    return C_block_item(x, j);
 5866  }
 5867  
 5868  barf(C_BAD_ARGUMENT_TYPE_ERROR, "##sys#block-ref", i);
 5869  return C_SCHEME_UNDEFINED;
 5870}
 5871
 5872
 5873C_regparm C_word C_fcall C_i_string_set(C_word s, C_word i, C_word c)
 5874{
 5875  int j;
 5876
 5877  if(C_immediatep(s) || C_header_bits(s) != C_STRING_TYPE)
 5878    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string-set!", s);
 5879
 5880  if(!C_immediatep(c) || (c & C_IMMEDIATE_TYPE_BITS) != C_CHARACTER_BITS)
 5881    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string-set!", c);
 5882
 5883  if(i & C_FIXNUM_BIT) {
 5884    j = C_unfix(i);
 5885
 5886    if(j < 0 || j >= C_header_size(s)) barf(C_OUT_OF_RANGE_ERROR, "string-set!", s, i);
 5887
 5888    return C_setsubchar(s, i, c);
 5889  }
 5890
 5891  barf(C_BAD_ARGUMENT_TYPE_ERROR, "string-set!", i);
 5892  return C_SCHEME_UNDEFINED;
 5893}
 5894
 5895
 5896C_regparm C_word C_fcall C_i_string_ref(C_word s, C_word i)
 5897{
 5898  int j;
 5899
 5900  if(C_immediatep(s) || C_header_bits(s) != C_STRING_TYPE)
 5901    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string-ref", s);
 5902
 5903  if(i & C_FIXNUM_BIT) {
 5904    j = C_unfix(i);
 5905
 5906    if(j < 0 || j >= C_header_size(s)) barf(C_OUT_OF_RANGE_ERROR, "string-ref", s, i);
 5907
 5908    return C_subchar(s, i);
 5909  }
 5910  
 5911  barf(C_BAD_ARGUMENT_TYPE_ERROR, "string-ref", i);
 5912  return C_SCHEME_UNDEFINED;
 5913}
 5914
 5915
 5916C_regparm C_word C_fcall C_i_vector_length(C_word v)
 5917{
 5918  if(C_immediatep(v) || C_header_bits(v) != C_VECTOR_TYPE)
 5919    barf(C_BAD_ARGUMENT_TYPE_ERROR, "vector-length", v);
 5920
 5921  return C_fix(C_header_size(v));
 5922}
 5923
 5924C_regparm C_word C_fcall C_i_u8vector_length(C_word v)
 5925{
 5926  if(!C_truep(C_i_u8vectorp(v)))
 5927    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u8vector-length", v);
 5928
 5929  return C_fix(C_header_size(C_block_item(v, 1)));
 5930}
 5931
 5932C_regparm C_word C_fcall C_i_s8vector_length(C_word v)
 5933{
 5934  if(!C_truep(C_i_s8vectorp(v)))
 5935    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s8vector-length", v);
 5936
 5937  return C_fix(C_header_size(C_block_item(v, 1)));
 5938}
 5939
 5940C_regparm C_word C_fcall C_i_u16vector_length(C_word v)
 5941{
 5942  if(!C_truep(C_i_u16vectorp(v)))
 5943    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u16vector-length", v);
 5944
 5945  return C_fix(C_header_size(C_block_item(v, 1)) >> 1);
 5946}
 5947
 5948C_regparm C_word C_fcall C_i_s16vector_length(C_word v)
 5949{
 5950  if(!C_truep(C_i_s16vectorp(v)))
 5951    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s16vector-length", v);
 5952
 5953  return C_fix(C_header_size(C_block_item(v, 1)) >> 1);
 5954}
 5955
 5956C_regparm C_word C_fcall C_i_u32vector_length(C_word v)
 5957{
 5958  if(!C_truep(C_i_u32vectorp(v)))
 5959    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u32vector-length", v);
 5960
 5961  return C_fix(C_header_size(C_block_item(v, 1)) >> 2);
 5962}
 5963
 5964C_regparm C_word C_fcall C_i_s32vector_length(C_word v)
 5965{
 5966  if(!C_truep(C_i_s32vectorp(v)))
 5967    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s32vector-length", v);
 5968
 5969  return C_fix(C_header_size(C_block_item(v, 1)) >> 2);
 5970}
 5971
 5972C_regparm C_word C_fcall C_i_u64vector_length(C_word v)
 5973{
 5974  if(!C_truep(C_i_u64vectorp(v)))
 5975    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u64vector-length", v);
 5976
 5977  return C_fix(C_header_size(C_block_item(v, 1)) >> 3);
 5978}
 5979
 5980C_regparm C_word C_fcall C_i_s64vector_length(C_word v)
 5981{
 5982  if(!C_truep(C_i_s64vectorp(v)))
 5983    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s64vector-length", v);
 5984
 5985  return C_fix(C_header_size(C_block_item(v, 1)) >> 3);
 5986}
 5987
 5988
 5989C_regparm C_word C_fcall C_i_f32vector_length(C_word v)
 5990{
 5991  if(!C_truep(C_i_f32vectorp(v)))
 5992    barf(C_BAD_ARGUMENT_TYPE_ERROR, "f32vector-length", v);
 5993
 5994  return C_fix(C_header_size(C_block_item(v, 1)) >> 2);
 5995}
 5996
 5997C_regparm C_word C_fcall C_i_f64vector_length(C_word v)
 5998{
 5999  if(!C_truep(C_i_f64vectorp(v)))
 6000    barf(C_BAD_ARGUMENT_TYPE_ERROR, "f64vector-length", v);
 6001
 6002  return C_fix(C_header_size(C_block_item(v, 1)) >> 3);
 6003}
 6004
 6005
 6006C_regparm C_word C_fcall C_i_string_length(C_word s)
 6007{
 6008  if(C_immediatep(s) || C_header_bits(s) != C_STRING_TYPE)
 6009    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string-length", s);
 6010
 6011  return C_fix(C_header_size(s));
 6012}
 6013
 6014
 6015C_regparm C_word C_fcall C_i_length(C_word lst)
 6016{
 6017  C_word fast = lst, slow = lst;
 6018  int n = 0;
 6019
 6020  while(slow != C_SCHEME_END_OF_LIST) {
 6021    if(fast != C_SCHEME_END_OF_LIST) {
 6022      if(!C_immediatep(fast) && C_header_type(fast) == C_PAIR_TYPE) {
 6023	fast = C_u_i_cdr(fast);
 6024      
 6025	if(fast != C_SCHEME_END_OF_LIST) {
 6026	  if(!C_immediatep(fast) && C_header_type(fast) == C_PAIR_TYPE) {
 6027	    fast = C_u_i_cdr(fast);
 6028	  }
 6029	  else barf(C_NOT_A_PROPER_LIST_ERROR, "length", lst);
 6030	}
 6031
 6032	if(fast == slow) 
 6033	  barf(C_BAD_ARGUMENT_TYPE_CYCLIC_LIST_ERROR, "length", lst);
 6034      }
 6035    }
 6036
 6037    if(C_immediatep(slow) || C_header_type(slow) != C_PAIR_TYPE)
 6038      barf(C_NOT_A_PROPER_LIST_ERROR, "length", lst);
 6039
 6040    slow = C_u_i_cdr(slow);
 6041    ++n;
 6042  }
 6043
 6044  return C_fix(n);
 6045}
 6046
 6047
 6048C_regparm C_word C_fcall C_u_i_length(C_word lst)
 6049{
 6050  int n = 0;
 6051
 6052  while(!C_immediatep(lst) && C_header_type(lst) == C_PAIR_TYPE) {
 6053    lst = C_u_i_cdr(lst);
 6054    ++n;
 6055  }
 6056
 6057  return C_fix(n);
 6058}
 6059
 6060C_regparm C_word C_fcall C_i_set_car(C_word x, C_word val)
 6061{
 6062  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE)
 6063    barf(C_BAD_ARGUMENT_TYPE_ERROR, "set-car!", x);
 6064
 6065  C_mutate(&C_u_i_car(x), val);
 6066  return C_SCHEME_UNDEFINED;
 6067}
 6068
 6069
 6070C_regparm C_word C_fcall C_i_set_cdr(C_word x, C_word val)
 6071{
 6072  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE)
 6073    barf(C_BAD_ARGUMENT_TYPE_ERROR, "set-cdr!", x);
 6074
 6075  C_mutate(&C_u_i_cdr(x), val);
 6076  return C_SCHEME_UNDEFINED;
 6077}
 6078
 6079
 6080C_regparm C_word C_fcall C_i_vector_set(C_word v, C_word i, C_word x)
 6081{
 6082  int j;
 6083
 6084  if(C_immediatep(v) || C_header_bits(v) != C_VECTOR_TYPE)
 6085    barf(C_BAD_ARGUMENT_TYPE_ERROR, "vector-set!", v);
 6086
 6087  if(i & C_FIXNUM_BIT) {
 6088    j = C_unfix(i);
 6089
 6090    if(j < 0 || j >= C_header_size(v)) barf(C_OUT_OF_RANGE_ERROR, "vector-set!", v, i);
 6091
 6092    C_mutate(&C_block_item(v, j), x);
 6093  }
 6094  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "vector-set!", i);
 6095
 6096  return C_SCHEME_UNDEFINED;
 6097}
 6098
 6099
 6100C_regparm C_word C_fcall C_i_u8vector_set(C_word v, C_word i, C_word x)
 6101{
 6102  int j;
 6103  C_word n;
 6104
 6105  if(!C_truep(C_i_u8vectorp(v)))
 6106    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u8vector-set!", v);
 6107
 6108  if(i & C_FIXNUM_BIT) {
 6109    j = C_unfix(i);
 6110
 6111    if(j < 0 || j >= C_header_size(C_block_item(v, 1))) barf(C_OUT_OF_RANGE_ERROR, "u8vector-set!", v, i);
 6112
 6113    if(x & C_FIXNUM_BIT) {
 6114      if (!(x & C_INT_SIGN_BIT) && C_ilen(C_unfix(x)) <= 8) n = C_unfix(x);
 6115      else barf(C_OUT_OF_RANGE_ERROR, "u8vector-set!", x);
 6116    }
 6117    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "u8vector-set!", x);
 6118  }
 6119  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "u8vector-set!", i);
 6120
 6121  ((unsigned char *)C_data_pointer(C_block_item(v, 1)))[j] = n;
 6122  return C_SCHEME_UNDEFINED;
 6123}
 6124
 6125C_regparm C_word C_fcall C_i_s8vector_set(C_word v, C_word i, C_word x)
 6126{
 6127  int j;
 6128  C_word n;
 6129
 6130  if(!C_truep(C_i_s8vectorp(v)))
 6131    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s8vector-set!", v);
 6132
 6133  if(i & C_FIXNUM_BIT) {
 6134    j = C_unfix(i);
 6135
 6136    if(j < 0 || j >= C_header_size(C_block_item(v, 1))) barf(C_OUT_OF_RANGE_ERROR, "s8vector-set!", v, i);
 6137
 6138    if(x & C_FIXNUM_BIT) {
 6139      if (C_unfix(C_i_fixnum_length(x)) <= 8) n = C_unfix(x);
 6140      else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s8vector-set!", x);
 6141    }
 6142    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s8vector-set!", x);
 6143  }
 6144  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s8vector-set!", i);
 6145
 6146  ((signed char *)C_data_pointer(C_block_item(v, 1)))[j] = n;
 6147  return C_SCHEME_UNDEFINED;
 6148}
 6149
 6150C_regparm C_word C_fcall C_i_u16vector_set(C_word v, C_word i, C_word x)
 6151{
 6152  int j;
 6153  C_word n;
 6154
 6155  if(!C_truep(C_i_u16vectorp(v)))
 6156    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u16vector-set!", v);
 6157
 6158  if(i & C_FIXNUM_BIT) {
 6159    j = C_unfix(i);
 6160
 6161    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 1)) barf(C_OUT_OF_RANGE_ERROR, "u16vector-set!", v, i);
 6162
 6163    if(x & C_FIXNUM_BIT) {
 6164      if (!(x & C_INT_SIGN_BIT) && C_ilen(C_unfix(x)) <= 16) n = C_unfix(x);
 6165      else barf(C_OUT_OF_RANGE_ERROR, "u16vector-set!", x);
 6166    }
 6167    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "u16vector-set!", x);
 6168  }
 6169  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "u16vector-set!", i);
 6170
 6171  ((unsigned short *)C_data_pointer(C_block_item(v, 1)))[j] = n;
 6172  return C_SCHEME_UNDEFINED;
 6173}
 6174
 6175C_regparm C_word C_fcall C_i_s16vector_set(C_word v, C_word i, C_word x)
 6176{
 6177  int j;
 6178  C_word n;
 6179
 6180  if(!C_truep(C_i_s16vectorp(v)))
 6181    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s16vector-set!", v);
 6182
 6183  if(i & C_FIXNUM_BIT) {
 6184    j = C_unfix(i);
 6185
 6186    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 1)) barf(C_OUT_OF_RANGE_ERROR, "u16vector-set!", v, i);
 6187
 6188    if(x & C_FIXNUM_BIT) {
 6189      if (C_unfix(C_i_fixnum_length(x)) <= 16) n = C_unfix(x);
 6190      else barf(C_OUT_OF_RANGE_ERROR, "s16vector-set!", x);
 6191    }
 6192    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s16vector-set!", x);
 6193  }
 6194  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s16vector-set!", i);
 6195
 6196  ((short *)C_data_pointer(C_block_item(v, 1)))[j] = n;
 6197  return C_SCHEME_UNDEFINED;
 6198}
 6199
 6200C_regparm C_word C_fcall C_i_u32vector_set(C_word v, C_word i, C_word x)
 6201{
 6202  int j;
 6203  C_u32 n;
 6204
 6205  if(!C_truep(C_i_u32vectorp(v)))
 6206    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u32vector-set!", v);
 6207
 6208  if(i & C_FIXNUM_BIT) {
 6209    j = C_unfix(i);
 6210
 6211    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 2)) barf(C_OUT_OF_RANGE_ERROR, "u32vector-set!", v, i);
 6212
 6213    if(C_truep(C_i_exact_integerp(x))) {
 6214      if (C_unfix(C_i_integer_length(x)) <= 32) n = C_num_to_unsigned_int(x);
 6215      else barf(C_OUT_OF_RANGE_ERROR, "u32vector-set!", x);
 6216    }
 6217    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "u32vector-set!", x);
 6218  }
 6219  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "u32vector-set!", i);
 6220
 6221  ((C_u32 *)C_data_pointer(C_block_item(v, 1)))[j] = n;
 6222  return C_SCHEME_UNDEFINED;
 6223}
 6224
 6225C_regparm C_word C_fcall C_i_s32vector_set(C_word v, C_word i, C_word x)
 6226{
 6227  int j;
 6228  C_s32 n;
 6229
 6230  if(!C_truep(C_i_s32vectorp(v)))
 6231    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s32vector-set!", v);
 6232
 6233  if(i & C_FIXNUM_BIT) {
 6234    j = C_unfix(i);
 6235
 6236    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 2)) barf(C_OUT_OF_RANGE_ERROR, "s32vector-set!", v, i);
 6237
 6238    if(C_truep(C_i_exact_integerp(x))) {
 6239      if (C_unfix(C_i_integer_length(x)) <= 32) n = C_num_to_int(x);
 6240      else barf(C_OUT_OF_RANGE_ERROR, "s32vector-set!", x);
 6241    }
 6242    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s32vector-set!", x);
 6243  }
 6244  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s32vector-set!", i);
 6245
 6246  ((C_s32 *)C_data_pointer(C_block_item(v, 1)))[j] = n;
 6247  return C_SCHEME_UNDEFINED;
 6248}
 6249
 6250C_regparm C_word C_fcall C_i_u64vector_set(C_word v, C_word i, C_word x)
 6251{
 6252  int j;
 6253  C_u64 n;
 6254
 6255  if(!C_truep(C_i_u64vectorp(v)))
 6256    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u64vector-set!", v);
 6257
 6258  if(i & C_FIXNUM_BIT) {
 6259    j = C_unfix(i);
 6260
 6261    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 3)) barf(C_OUT_OF_RANGE_ERROR, "u64vector-set!", v, i);
 6262
 6263    if(C_truep(C_i_exact_integerp(x))) {
 6264      if (C_unfix(C_i_integer_length(x)) <= 64) n = C_num_to_uint64(x);
 6265      else barf(C_OUT_OF_RANGE_ERROR, "u64vector-set!", x);
 6266    }
 6267    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "u64vector-set!", x);
 6268  }
 6269  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "u64vector-set!", i);
 6270
 6271  ((C_u64 *)C_data_pointer(C_block_item(v, 1)))[j] = n;
 6272  return C_SCHEME_UNDEFINED;
 6273}
 6274
 6275C_regparm C_word C_fcall C_i_s64vector_set(C_word v, C_word i, C_word x)
 6276{
 6277  int j;
 6278  C_s64 n;
 6279
 6280  if(!C_truep(C_i_s64vectorp(v)))
 6281    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s64vector-set!", v);
 6282
 6283  if(i & C_FIXNUM_BIT) {
 6284    j = C_unfix(i);
 6285
 6286    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 3)) barf(C_OUT_OF_RANGE_ERROR, "s64vector-set!", v, i);
 6287
 6288    if(C_truep(C_i_exact_integerp(x))) {
 6289      if (C_unfix(C_i_integer_length(x)) <= 64) n = C_num_to_int64(x);
 6290      else barf(C_OUT_OF_RANGE_ERROR, "s64vector-set!", x);
 6291    }
 6292    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s64vector-set!", x);
 6293  }
 6294  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s64vector-set!", i);
 6295
 6296  ((C_s64 *)C_data_pointer(C_block_item(v, 1)))[j] = n;
 6297  return C_SCHEME_UNDEFINED;
 6298}
 6299
 6300C_regparm C_word C_fcall C_i_f32vector_set(C_word v, C_word i, C_word x)
 6301{
 6302  int j;
 6303  double f;
 6304
 6305  if(!C_truep(C_i_f32vectorp(v)))
 6306    barf(C_BAD_ARGUMENT_TYPE_ERROR, "f32vector-set!", v);
 6307
 6308  if(i & C_FIXNUM_BIT) {
 6309    j = C_unfix(i);
 6310
 6311    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 2)) barf(C_OUT_OF_RANGE_ERROR, "f32vector-set!", v, i);
 6312
 6313    if(C_truep(C_i_flonump(x))) f = C_flonum_magnitude(x);
 6314    else if(x & C_FIXNUM_BIT) f = C_unfix(x);
 6315    else if (C_truep(C_i_bignump(x))) f = C_bignum_to_double(x);
 6316    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "f32vector-set!", x);
 6317  }
 6318  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "f32vector-set!", i);
 6319
 6320  ((float *)C_data_pointer(C_block_item(v, 1)))[j] = (float)f;
 6321  return C_SCHEME_UNDEFINED;
 6322}
 6323
 6324C_regparm C_word C_fcall C_i_f64vector_set(C_word v, C_word i, C_word x)
 6325{
 6326  int j;
 6327  double f;
 6328
 6329  if(!C_truep(C_i_f64vectorp(v)))
 6330    barf(C_BAD_ARGUMENT_TYPE_ERROR, "f64vector-set!", v);
 6331
 6332  if(i & C_FIXNUM_BIT) {
 6333    j = C_unfix(i);
 6334
 6335    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 3)) barf(C_OUT_OF_RANGE_ERROR, "f64vector-set!", v, i);
 6336
 6337    if(C_truep(C_i_flonump(x))) f = C_flonum_magnitude(x);
 6338    else if(x & C_FIXNUM_BIT) f = C_unfix(x);
 6339    else if (C_truep(C_i_bignump(x))) f = C_bignum_to_double(x);
 6340    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "f64vector-set!", x);
 6341
 6342  }
 6343  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "f64vector-set!", i);
 6344
 6345  ((double *)C_data_pointer(C_block_item(v, 1)))[j] = f;
 6346  return C_SCHEME_UNDEFINED;
 6347}
 6348
 6349
 6350/* This needs at most C_SIZEOF_FIX_BIGNUM + max(C_SIZEOF_RATNUM, C_SIZEOF_CPLXNUM) so 7 words */
 6351C_regparm C_word C_fcall
 6352C_s_a_i_abs(C_word **ptr, C_word n, C_word x)
 6353{
 6354  if (x & C_FIXNUM_BIT) {
 6355    return C_a_i_fixnum_abs(ptr, 1, x);
 6356  } else if (C_immediatep(x)) {
 6357    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "abs", x);
 6358  } else if (C_block_header(x) == C_FLONUM_TAG) {
 6359    return C_a_i_flonum_abs(ptr, 1, x);
 6360  } else if (C_truep(C_bignump(x))) {
 6361    return C_s_a_u_i_integer_abs(ptr, 1, x);
 6362  } else if (C_block_header(x) == C_RATNUM_TAG) {
 6363    return C_ratnum(ptr, C_s_a_u_i_integer_abs(ptr, 1, C_u_i_ratnum_num(x)),
 6364                    C_u_i_ratnum_denom(x));
 6365  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 6366    barf(C_BAD_ARGUMENT_TYPE_COMPLEX_ABS, "abs", x);
 6367  } else {
 6368    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "abs", x);
 6369  }
 6370}
 6371
 6372void C_ccall C_signum(C_word c, C_word *av)
 6373{
 6374  C_word k = av[ 1 ], x, y;
 6375
 6376  if (c != 3) C_bad_argc_2(c, 3, av[ 0 ]);
 6377
 6378  x = av[ 2 ];
 6379  y = av[ 3 ];
 6380
 6381  if (x & C_FIXNUM_BIT) {
 6382    C_kontinue(k, C_i_fixnum_signum(x));
 6383  } else if (C_immediatep(x)) {
 6384    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "signum", x);
 6385  } else if (C_block_header(x) == C_FLONUM_TAG) {
 6386    C_word *a = C_alloc(C_SIZEOF_FLONUM);
 6387    C_kontinue(k, C_a_u_i_flonum_signum(&a, 1, x));
 6388  } else if (C_truep(C_bignump(x))) {
 6389    C_kontinue(k, C_bignum_negativep(x) ? C_fix(-1) : C_fix(1));
 6390  } else {
 6391    try_extended_number("##sys#extended-signum", 2, k, x);
 6392  }
 6393}
 6394
 6395
 6396/* The maximum this can allocate is a cplxnum which consists of two
 6397 * ratnums that consist of 2 fix bignums each.  So that's
 6398 * C_SIZEOF_CPLXNUM + C_SIZEOF_RATNUM * 2 + C_SIZEOF_FIX_BIGNUM * 4 = 29 words!
 6399 */
 6400C_regparm C_word C_fcall
 6401C_s_a_i_negate(C_word **ptr, C_word n, C_word x)
 6402{
 6403  if (x & C_FIXNUM_BIT) {
 6404    return C_a_i_fixnum_negate(ptr, 1, x);
 6405  } else if (C_immediatep(x)) {
 6406    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", x);
 6407  } else if (C_block_header(x) == C_FLONUM_TAG) {
 6408    return C_a_i_flonum_negate(ptr, 1, x);
 6409  } else if (C_truep(C_bignump(x))) {
 6410    return C_s_a_u_i_integer_negate(ptr, 1, x);
 6411  } else if (C_block_header(x) == C_RATNUM_TAG) {
 6412    return C_ratnum(ptr, C_s_a_u_i_integer_negate(ptr, 1, C_u_i_ratnum_num(x)),
 6413                    C_u_i_ratnum_denom(x));
 6414  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 6415    return C_cplxnum(ptr, C_s_a_i_negate(ptr, 1, C_u_i_cplxnum_real(x)),
 6416                     C_s_a_i_negate(ptr, 1, C_u_i_cplxnum_imag(x)));
 6417  } else {
 6418    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", x);
 6419  }
 6420}
 6421
 6422/* Copy all the digits from source to target, obliterating what was
 6423 * there.  If target is larger than source, the most significant
 6424 * digits will remain untouched.
 6425 */
 6426inline static void bignum_digits_destructive_copy(C_word target, C_word source)
 6427{
 6428  C_memcpy(C_bignum_digits(target), C_bignum_digits(source),
 6429           C_wordstobytes(C_bignum_size(source)));
 6430}
 6431
 6432C_regparm C_word C_fcall
 6433C_s_a_u_i_integer_negate(C_word **ptr, C_word n, C_word x)
 6434{
 6435  if (x & C_FIXNUM_BIT) {
 6436    return C_a_i_fixnum_negate(ptr, 1, x);
 6437  } else {
 6438    if (C_bignum_negated_fitsinfixnump(x)) {
 6439      return C_fix(C_MOST_NEGATIVE_FIXNUM);
 6440    } else {
 6441      C_word res, negp = C_mk_nbool(C_bignum_negativep(x)),
 6442             size = C_fix(C_bignum_size(x));
 6443      res = C_allocate_scratch_bignum(ptr, size, negp, C_SCHEME_FALSE);
 6444      bignum_digits_destructive_copy(res, x);
 6445      return C_bignum_simplify(res);
 6446    }
 6447  }
 6448}
 6449
 6450
 6451/* Faster version that ignores sign */
 6452inline static int integer_length_abs(C_word x)
 6453{
 6454  if (x & C_FIXNUM_BIT) {
 6455    return C_ilen(C_wabs(C_unfix(x)));
 6456  } else {
 6457    C_uword result = (C_bignum_size(x) - 1) * C_BIGNUM_DIGIT_LENGTH,
 6458            *last_digit = C_bignum_digits(x) + C_bignum_size(x) - 1,
 6459            last_digit_length = C_ilen(*last_digit);
 6460    return result + last_digit_length;
 6461  }
 6462}
 6463
 6464C_regparm C_word C_fcall C_i_integer_length(C_word x)
 6465{
 6466  if (x & C_FIXNUM_BIT) {
 6467    return C_i_fixnum_length(x);
 6468  } else if (C_truep(C_i_bignump(x))) {
 6469    C_uword result = (C_bignum_size(x) - 1) * C_BIGNUM_DIGIT_LENGTH,
 6470            *last_digit = C_bignum_digits(x) + C_bignum_size(x) - 1,
 6471            last_digit_length = C_ilen(*last_digit);
 6472
 6473    /* If *only* the highest bit is set, negating will give one less bit */
 6474    if (C_bignum_negativep(x) &&
 6475        *last_digit == ((C_uword)1 << (last_digit_length-1))) {
 6476      C_uword *startx = C_bignum_digits(x);
 6477      while (startx < last_digit && *startx == 0) ++startx;
 6478      if (startx == last_digit) result--;
 6479    }
 6480    return C_fix(result + last_digit_length);
 6481  } else {
 6482    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "integer-length", x);
 6483  }
 6484}
 6485
 6486/* This is currently only used by Karatsuba multiplication and
 6487 * Burnikel-Ziegler division. */
 6488static C_regparm C_word
 6489bignum_extract_digits(C_word **ptr, C_word n, C_word x, C_word start, C_word end)
 6490{
 6491  if (x & C_FIXNUM_BIT) { /* Needed? */
 6492    if (C_unfix(start) == 0 && (end == C_SCHEME_FALSE || C_unfix(end) > 0))
 6493      return x;
 6494    else
 6495      return C_fix(0);
 6496  } else {
 6497    C_word negp, size;
 6498
 6499    negp = C_mk_bool(C_bignum_negativep(x)); /* Always false */
 6500
 6501    start = C_unfix(start);
 6502    /* We might get passed larger values than actually fits; pad w/ zeroes */
 6503    if (end == C_SCHEME_FALSE) end = C_bignum_size(x);
 6504    else end = nmin(C_unfix(end), C_bignum_size(x));
 6505    assert(start >= 0);
 6506
 6507    size = end - start;
 6508
 6509    if (size == 0 || start >= C_bignum_size(x)) {
 6510      return C_fix(0);
 6511    } else {
 6512      C_uword res, *res_digits, *x_digits;
 6513      res = C_allocate_scratch_bignum(ptr, C_fix(size), negp, C_SCHEME_FALSE);
 6514      res_digits = C_bignum_digits(res);
 6515      x_digits = C_bignum_digits(x);
 6516      /* Can't use bignum_digits_destructive_copy because that assumes
 6517       * target is at least as big as source.
 6518       */
 6519      C_memcpy(res_digits, x_digits + start, C_wordstobytes(end - start));
 6520      return C_bignum_simplify(res);
 6521    }
 6522  }
 6523}
 6524
 6525/* This returns a tmp bignum negated copy of X (must be freed!) when
 6526 * the number is negative, or #f if it doesn't need to be negated.
 6527 * The size can be larger or smaller than X (it may be 1-padded).
 6528 */
 6529inline static C_word maybe_negate_bignum_for_bitwise_op(C_word x, C_word size)
 6530{
 6531  C_word nx = C_SCHEME_FALSE, xsize;
 6532  if (C_bignum_negativep(x)) {
 6533    nx = allocate_tmp_bignum(C_fix(size), C_SCHEME_FALSE, C_SCHEME_FALSE);
 6534    xsize = C_bignum_size(x);
 6535    /* Copy up until requested size, and init any remaining upper digits */
 6536    C_memcpy(C_bignum_digits(nx), C_bignum_digits(x),
 6537             C_wordstobytes(nmin(size, xsize)));
 6538    if (size > xsize)
 6539      C_memset(C_bignum_digits(nx)+xsize, 0, C_wordstobytes(size-xsize));
 6540    bignum_digits_destructive_negate(nx);
 6541  }
 6542  return nx;
 6543}
 6544
 6545/* DEPRECATED */
 6546C_regparm C_word C_fcall C_i_bit_to_bool(C_word n, C_word i)
 6547{
 6548  if (!C_truep(C_i_exact_integerp(n))) {
 6549    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bit->boolean", n);
 6550  } else if (!(i & C_FIXNUM_BIT)) {
 6551    if (!C_immediatep(i) && C_truep(C_bignump(i)) && !C_bignum_negativep(i)) {
 6552      return C_i_integer_negativep(n); /* A bit silly, but strictly correct */
 6553    } else {
 6554      barf(C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR, "bit->boolean", i);
 6555    }
 6556  } else if (i & C_INT_SIGN_BIT) {
 6557    barf(C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR, "bit->boolean", i);
 6558  } else {
 6559    i = C_unfix(i);
 6560    if (n & C_FIXNUM_BIT) {
 6561      if (i >= C_WORD_SIZE) return C_mk_bool(n & C_INT_SIGN_BIT);
 6562      else return C_mk_bool((C_unfix(n) & ((C_word)1 << i)) != 0);
 6563    } else {
 6564      C_word nn, d;
 6565      d = i / C_BIGNUM_DIGIT_LENGTH;
 6566      if (d >= C_bignum_size(n)) return C_mk_bool(C_bignum_negativep(n));
 6567
 6568      /* TODO: this isn't necessary, is it? */
 6569      if (C_truep(nn = maybe_negate_bignum_for_bitwise_op(n, d))) n = nn;
 6570
 6571      i %= C_BIGNUM_DIGIT_LENGTH;
 6572      d = C_mk_bool((C_bignum_digits(n)[d] & (C_uword)1 << i) != 0);
 6573      if (C_truep(nn)) free_tmp_bignum(nn);
 6574      return d;
 6575    }
 6576  }
 6577}
 6578
 6579C_regparm C_word C_fcall
 6580C_s_a_i_bitwise_and(C_word **ptr, C_word n, C_word x, C_word y)
 6581{
 6582  if ((x & y) & C_FIXNUM_BIT) {
 6583    return C_u_fixnum_and(x, y);
 6584  } else if (!C_truep(C_i_exact_integerp(x))) {
 6585    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-and", x);
 6586  } else if (!C_truep(C_i_exact_integerp(y))) {
 6587    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-and", y);
 6588  } else {
 6589    C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, negp, size, res, nx, ny;
 6590    C_uword *scanr, *endr, *scans1, *ends1, *scans2;
 6591
 6592    if (x & C_FIXNUM_BIT) x = C_a_u_i_fix_to_big(&a, x);
 6593    if (y & C_FIXNUM_BIT) y = C_a_u_i_fix_to_big(&a, y);
 6594
 6595    negp = C_mk_bool(C_bignum_negativep(x) && C_bignum_negativep(y));
 6596    /* Allow negative 1-bits to propagate */
 6597    if (C_bignum_negativep(x) || C_bignum_negativep(y))
 6598      size = nmax(C_bignum_size(x), C_bignum_size(y)) + 1;
 6599    else
 6600      size = nmin(C_bignum_size(x), C_bignum_size(y));
 6601
 6602    res = C_allocate_scratch_bignum(ptr, C_fix(size), negp, C_SCHEME_FALSE);
 6603    scanr = C_bignum_digits(res);
 6604    endr = scanr + C_bignum_size(res);
 6605    
 6606    if (C_truep(nx = maybe_negate_bignum_for_bitwise_op(x, size))) x = nx;
 6607    if (C_truep(ny = maybe_negate_bignum_for_bitwise_op(y, size))) y = ny;
 6608
 6609    if (C_bignum_size(x) < C_bignum_size(y)) {
 6610      scans1 = C_bignum_digits(x); ends1 = scans1 + C_bignum_size(x);
 6611      scans2 = C_bignum_digits(y);
 6612    } else {
 6613      scans1 = C_bignum_digits(y); ends1 = scans1 + C_bignum_size(y);
 6614      scans2 = C_bignum_digits(x);
 6615    }
 6616
 6617    while (scans1 < ends1) *scanr++ = *scans1++ & *scans2++;
 6618    C_memset(scanr, 0, C_wordstobytes(endr - scanr));
 6619
 6620    if (C_truep(nx)) free_tmp_bignum(nx);
 6621    if (C_truep(ny)) free_tmp_bignum(ny);
 6622    if (C_bignum_negativep(res)) bignum_digits_destructive_negate(res);
 6623    
 6624    return C_bignum_simplify(res);
 6625  }
 6626}
 6627
 6628void C_ccall C_bitwise_and(C_word c, C_word *av)
 6629{
 6630  /* C_word closure = av[ 0 ]; */
 6631  C_word k = av[ 1 ];
 6632  C_word next_val, result, prev_result;
 6633  C_word ab[2][C_SIZEOF_BIGNUM_WRAPPER], *a;
 6634
 6635  c -= 2; 
 6636  av += 2;
 6637
 6638  if (c == 0) C_kontinue(k, C_fix(-1));
 6639
 6640  prev_result = result = *(av++);
 6641
 6642  if (c-- == 1 && !C_truep(C_i_exact_integerp(result)))
 6643    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-and", result);
 6644
 6645  while (c--) {
 6646    next_val = *(av++);
 6647    a = ab[c&1]; /* One may hold last iteration result, the other is unused */
 6648    result = C_s_a_i_bitwise_and(&a, 2, result, next_val);
 6649    result = move_buffer_object(&a, ab[(c+1)&1], result);
 6650    clear_buffer_object(ab[(c+1)&1], prev_result);
 6651    prev_result = result;
 6652  }
 6653
 6654  C_kontinue(k, result);
 6655}
 6656
 6657C_regparm C_word C_fcall
 6658C_s_a_i_bitwise_ior(C_word **ptr, C_word n, C_word x, C_word y)
 6659{
 6660  if ((x & y) & C_FIXNUM_BIT) {
 6661    return C_u_fixnum_or(x, y);
 6662  } else if (!C_truep(C_i_exact_integerp(x))) {
 6663    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-ior", x);
 6664  } else if (!C_truep(C_i_exact_integerp(y))) {
 6665    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-ior", y);
 6666  } else {
 6667    C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, negp, size, res, nx, ny;
 6668    C_uword *scanr, *endr, *scans1, *ends1, *scans2, *ends2;
 6669
 6670    if (x & C_FIXNUM_BIT) x = C_a_u_i_fix_to_big(&a, x);
 6671    if (y & C_FIXNUM_BIT) y = C_a_u_i_fix_to_big(&a, y);
 6672
 6673    negp = C_mk_bool(C_bignum_negativep(x) || C_bignum_negativep(y));
 6674    size = nmax(C_bignum_size(x), C_bignum_size(y)) + 1;
 6675    res = C_allocate_scratch_bignum(ptr, C_fix(size), negp, C_SCHEME_FALSE);
 6676    scanr = C_bignum_digits(res);
 6677    endr = scanr + C_bignum_size(res);
 6678    
 6679    if (C_truep(nx = maybe_negate_bignum_for_bitwise_op(x, size))) x = nx;
 6680    if (C_truep(ny = maybe_negate_bignum_for_bitwise_op(y, size))) y = ny;
 6681
 6682    if (C_bignum_size(x) < C_bignum_size(y)) {
 6683      scans1 = C_bignum_digits(x); ends1 = scans1 + C_bignum_size(x);
 6684      scans2 = C_bignum_digits(y); ends2 = scans2 + C_bignum_size(y);
 6685    } else {
 6686      scans1 = C_bignum_digits(y); ends1 = scans1 + C_bignum_size(y);
 6687      scans2 = C_bignum_digits(x); ends2 = scans2 + C_bignum_size(x);
 6688    }
 6689
 6690    while (scans1 < ends1) *scanr++ = *scans1++ | *scans2++;
 6691    while (scans2 < ends2) *scanr++ = *scans2++;
 6692    if (scanr < endr) *scanr++ = 0; /* Only done when result is positive */
 6693    assert(scanr == endr);
 6694
 6695    if (C_truep(nx)) free_tmp_bignum(nx);
 6696    if (C_truep(ny)) free_tmp_bignum(ny);
 6697    if (C_bignum_negativep(res)) bignum_digits_destructive_negate(res);
 6698
 6699    return C_bignum_simplify(res);
 6700  }
 6701}
 6702
 6703void C_ccall C_bitwise_ior(C_word c, C_word *av)
 6704{
 6705  /* C_word closure = av[ 0 ]; */
 6706  C_word k = av[ 1 ];
 6707  C_word next_val, result, prev_result;
 6708  C_word ab[2][C_SIZEOF_BIGNUM_WRAPPER], *a;
 6709
 6710  c -= 2; 
 6711  av += 2;
 6712
 6713  if (c == 0) C_kontinue(k, C_fix(0));
 6714
 6715  prev_result = result = *(av++);
 6716
 6717  if (c-- == 1 && !C_truep(C_i_exact_integerp(result)))
 6718    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-ior", result);
 6719
 6720  while (c--) {
 6721    next_val = *(av++);
 6722    a = ab[c&1]; /* One may hold prev iteration result, the other is unused */
 6723    result = C_s_a_i_bitwise_ior(&a, 2, result, next_val);
 6724    result = move_buffer_object(&a, ab[(c+1)&1], result);
 6725    clear_buffer_object(ab[(c+1)&1], prev_result);
 6726    prev_result = result;
 6727  }
 6728
 6729  C_kontinue(k, result);
 6730}
 6731
 6732C_regparm C_word C_fcall
 6733C_s_a_i_bitwise_xor(C_word **ptr, C_word n, C_word x, C_word y)
 6734{
 6735  if ((x & y) & C_FIXNUM_BIT) {
 6736    return C_fixnum_xor(x, y);
 6737  } else if (!C_truep(C_i_exact_integerp(x))) {
 6738    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-xor", x);
 6739  } else if (!C_truep(C_i_exact_integerp(y))) {
 6740    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-xor", y);
 6741  } else {
 6742    C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, negp, size, res, nx, ny;
 6743    C_uword *scanr, *endr, *scans1, *ends1, *scans2, *ends2;
 6744
 6745    if (x & C_FIXNUM_BIT) x = C_a_u_i_fix_to_big(&a, x);
 6746    if (y & C_FIXNUM_BIT) y = C_a_u_i_fix_to_big(&a, y);
 6747
 6748    size = nmax(C_bignum_size(x), C_bignum_size(y)) + 1;
 6749    negp = C_mk_bool(C_bignum_negativep(x) != C_bignum_negativep(y));
 6750    res = C_allocate_scratch_bignum(ptr, C_fix(size), negp, C_SCHEME_FALSE);
 6751    scanr = C_bignum_digits(res);
 6752    endr = scanr + C_bignum_size(res);
 6753
 6754    if (C_truep(nx = maybe_negate_bignum_for_bitwise_op(x, size))) x = nx;
 6755    if (C_truep(ny = maybe_negate_bignum_for_bitwise_op(y, size))) y = ny;
 6756
 6757    if (C_bignum_size(x) < C_bignum_size(y)) {
 6758      scans1 = C_bignum_digits(x); ends1 = scans1 + C_bignum_size(x);
 6759      scans2 = C_bignum_digits(y); ends2 = scans2 + C_bignum_size(y);
 6760    } else {
 6761      scans1 = C_bignum_digits(y); ends1 = scans1 + C_bignum_size(y);
 6762      scans2 = C_bignum_digits(x); ends2 = scans2 + C_bignum_size(x);
 6763    }
 6764
 6765    while (scans1 < ends1) *scanr++ = *scans1++ ^ *scans2++;
 6766    while (scans2 < ends2) *scanr++ = *scans2++;
 6767    if (scanr < endr) *scanr++ = 0; /* Only done when result is positive */
 6768    assert(scanr == endr);
 6769
 6770    if (C_truep(nx)) free_tmp_bignum(nx);
 6771    if (C_truep(ny)) free_tmp_bignum(ny);
 6772    if (C_bignum_negativep(res)) bignum_digits_destructive_negate(res);
 6773
 6774    return C_bignum_simplify(res);
 6775  }
 6776}
 6777
 6778void C_ccall C_bitwise_xor(C_word c, C_word *av)
 6779{
 6780  /* C_word closure = av[ 0 ]; */
 6781  C_word k = av[ 1 ];
 6782  C_word next_val, result, prev_result;
 6783  C_word ab[2][C_SIZEOF_BIGNUM_WRAPPER], *a;
 6784
 6785  c -= 2; 
 6786  av += 2;
 6787
 6788  if (c == 0) C_kontinue(k, C_fix(0));
 6789
 6790  prev_result = result = *(av++);
 6791
 6792  if (c-- == 1 && !C_truep(C_i_exact_integerp(result)))
 6793    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-xor", result);
 6794
 6795  while (c--) {
 6796    next_val = *(av++);
 6797    a = ab[c&1]; /* One may hold prev iteration result, the other is unused */
 6798    result = C_s_a_i_bitwise_xor(&a, 2, result, next_val);
 6799    result = move_buffer_object(&a, ab[(c+1)&1], result);
 6800    clear_buffer_object(ab[(c+1)&1], prev_result);
 6801    prev_result = result;
 6802  }
 6803
 6804  C_kontinue(k, result);
 6805}
 6806
 6807C_regparm C_word C_fcall
 6808C_s_a_i_bitwise_not(C_word **ptr, C_word n, C_word x)
 6809{
 6810  if (!C_truep(C_i_exact_integerp(x))) {
 6811    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-not", x);
 6812  } else {
 6813    return C_s_a_u_i_integer_minus(ptr, 2, C_fix(-1), x);
 6814  }
 6815}
 6816
 6817C_regparm C_word C_fcall
 6818C_s_a_i_arithmetic_shift(C_word **ptr, C_word n, C_word x, C_word y)
 6819{
 6820  C_word ab[C_SIZEOF_FIX_BIGNUM], *a = ab, size, negp, res,
 6821         digit_offset, bit_offset;
 6822
 6823  if (!(y & C_FIXNUM_BIT))
 6824    barf(C_BAD_ARGUMENT_TYPE_NO_FIXNUM_ERROR, "arithmetic-shift", y);
 6825
 6826  y = C_unfix(y);
 6827  if (y == 0 || x == C_fix(0)) { /* Done (no shift) */
 6828    return x;
 6829  } else if (x & C_FIXNUM_BIT) {
 6830    if (y < 0) {
 6831      /* Don't shift more than a word's length (that's undefined in C!) */
 6832      if (-y < C_WORD_SIZE) {
 6833        return C_fix(C_unfix(x) >> -y);
 6834      } else {
 6835        return (x < 0) ? C_fix(-1) : C_fix(0);
 6836      }
 6837    } else if (y > 0 && y < C_WORD_SIZE-2 &&
 6838               /* After shifting, the length still fits a fixnum */
 6839               (C_ilen(C_unfix(x)) + y) < C_WORD_SIZE-2) {
 6840      return C_fix((C_uword)C_unfix(x) << y);
 6841    } else {
 6842      x = C_a_u_i_fix_to_big(&a, x);
 6843    }
 6844  } else if (!C_truep(C_i_bignump(x))) {
 6845    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "arithmetic-shift", x);
 6846  }
 6847
 6848  negp = C_mk_bool(C_bignum_negativep(x));
 6849  
 6850  if (y > 0) {                  /* Shift left */
 6851    C_uword *startr, *startx, *endx, *endr;
 6852
 6853    digit_offset = y / C_BIGNUM_DIGIT_LENGTH;
 6854    bit_offset =   y % C_BIGNUM_DIGIT_LENGTH;
 6855
 6856    size = C_fix(C_bignum_size(x) + digit_offset + 1);
 6857    res = C_allocate_scratch_bignum(ptr, size, negp, C_SCHEME_FALSE);
 6858
 6859    startr = C_bignum_digits(res);
 6860    endr = startr + C_bignum_size(res);
 6861
 6862    startx = C_bignum_digits(x);
 6863    endx = startx + C_bignum_size(x);
 6864
 6865    /* Initialize only the lower digits we're skipping and the MSD */
 6866    C_memset(startr, 0, C_wordstobytes(digit_offset));
 6867    *(endr-1) = 0;
 6868    startr += digit_offset;
 6869    /* Can't use bignum_digits_destructive_copy because it assumes
 6870     * we want to copy from the start.
 6871     */
 6872    C_memcpy(startr, startx, C_wordstobytes(endx-startx));
 6873    if(bit_offset > 0)
 6874      bignum_digits_destructive_shift_left(startr, endr, bit_offset);
 6875
 6876    return C_bignum_simplify(res);
 6877  } else if (-y >= C_bignum_size(x) * (C_word)C_BIGNUM_DIGIT_LENGTH) {
 6878    /* All bits are shifted out, just return 0 or -1 */
 6879    return C_truep(negp) ? C_fix(-1) : C_fix(0);
 6880  } else {                      /* Shift right */
 6881    C_uword *startr, *startx, *endr;
 6882    C_word nx;
 6883
 6884    digit_offset = -y / C_BIGNUM_DIGIT_LENGTH;
 6885    bit_offset =   -y % C_BIGNUM_DIGIT_LENGTH;
 6886
 6887    size = C_fix(C_bignum_size(x) - digit_offset);
 6888    res = C_allocate_scratch_bignum(ptr, size, negp, C_SCHEME_FALSE);
 6889
 6890    startr = C_bignum_digits(res);
 6891    endr = startr + C_bignum_size(res);
 6892
 6893    size = C_bignum_size(x) + 1;
 6894    if (C_truep(nx = maybe_negate_bignum_for_bitwise_op(x, size))) {
 6895      startx = C_bignum_digits(nx) + digit_offset;
 6896    } else {
 6897      startx = C_bignum_digits(x) + digit_offset;
 6898    }
 6899    /* Can't use bignum_digits_destructive_copy because that assumes
 6900     * target is at least as big as source.
 6901     */
 6902    C_memcpy(startr, startx, C_wordstobytes(endr-startr));
 6903    if(bit_offset > 0)
 6904      bignum_digits_destructive_shift_right(startr,endr,bit_offset,C_truep(nx));
 6905
 6906    if (C_truep(nx)) {
 6907      free_tmp_bignum(nx);
 6908      bignum_digits_destructive_negate(res);
 6909    }
 6910    return C_bignum_simplify(res);
 6911  }
 6912}
 6913
 6914
 6915C_regparm C_word C_fcall C_a_i_exp(C_word **a, int c, C_word n)
 6916{
 6917  double f;
 6918
 6919  C_check_real(n, "exp", f);
 6920  return C_flonum(a, C_exp(f));
 6921}
 6922
 6923
 6924C_regparm C_word C_fcall C_a_i_log(C_word **a, int c, C_word n)
 6925{
 6926  double f;
 6927
 6928  C_check_real(n, "log", f);
 6929  return C_flonum(a, C_log(f));
 6930}
 6931
 6932
 6933C_regparm C_word C_fcall C_a_i_sin(C_word **a, int c, C_word n)
 6934{
 6935  double f;
 6936
 6937  C_check_real(n, "sin", f);
 6938  return C_flonum(a, C_sin(f));
 6939}
 6940
 6941
 6942C_regparm C_word C_fcall C_a_i_cos(C_word **a, int c, C_word n)
 6943{
 6944  double f;
 6945
 6946  C_check_real(n, "cos", f);
 6947  return C_flonum(a, C_cos(f));
 6948}
 6949
 6950
 6951C_regparm C_word C_fcall C_a_i_tan(C_word **a, int c, C_word n)
 6952{
 6953  double f;
 6954
 6955  C_check_real(n, "tan", f);
 6956  return C_flonum(a, C_tan(f));
 6957}
 6958
 6959
 6960C_regparm C_word C_fcall C_a_i_asin(C_word **a, int c, C_word n)
 6961{
 6962  double f;
 6963
 6964  C_check_real(n, "asin", f);
 6965  return C_flonum(a, C_asin(f));
 6966}
 6967
 6968
 6969C_regparm C_word C_fcall C_a_i_acos(C_word **a, int c, C_word n)
 6970{
 6971  double f;
 6972
 6973  C_check_real(n, "acos", f);
 6974  return C_flonum(a, C_acos(f));
 6975}
 6976
 6977
 6978C_regparm C_word C_fcall C_a_i_atan(C_word **a, int c, C_word n)
 6979{
 6980  double f;
 6981
 6982  C_check_real(n, "atan", f);
 6983  return C_flonum(a, C_atan(f));
 6984}
 6985
 6986
 6987C_regparm C_word C_fcall C_a_i_atan2(C_word **a, int c, C_word n1, C_word n2)
 6988{
 6989  double f1, f2;
 6990
 6991  C_check_real(n1, "atan", f1);
 6992  C_check_real(n2, "atan", f2);
 6993  return C_flonum(a, C_atan2(f1, f2));
 6994}
 6995
 6996
 6997C_regparm C_word C_fcall C_a_i_sinh(C_word **a, int c, C_word n)
 6998{
 6999  double f;
 7000
 7001  C_check_real(n, "sinh", f);
 7002  return C_flonum(a, C_sinh(f));
 7003}
 7004
 7005
 7006C_regparm C_word C_fcall C_a_i_cosh(C_word **a, int c, C_word n)
 7007{
 7008  double f;
 7009
 7010  C_check_real(n, "cosh", f);
 7011  return C_flonum(a, C_cosh(f));
 7012}
 7013
 7014
 7015C_regparm C_word C_fcall C_a_i_tanh(C_word **a, int c, C_word n)
 7016{
 7017  double f;
 7018
 7019  C_check_real(n, "tanh", f);
 7020  return C_flonum(a, C_tanh(f));
 7021}
 7022
 7023
 7024C_regparm C_word C_fcall C_a_i_asinh(C_word **a, int c, C_word n)
 7025{
 7026  double f;
 7027
 7028  C_check_real(n, "asinh", f);
 7029  return C_flonum(a, C_asinh(f));
 7030}
 7031
 7032
 7033C_regparm C_word C_fcall C_a_i_acosh(C_word **a, int c, C_word n)
 7034{
 7035  double f;
 7036
 7037  C_check_real(n, "acosh", f);
 7038  return C_flonum(a, C_acosh(f));
 7039}
 7040
 7041
 7042C_regparm C_word C_fcall C_a_i_atanh(C_word **a, int c, C_word n)
 7043{
 7044  double f;
 7045
 7046  C_check_real(n, "atanh", f);
 7047  return C_flonum(a, C_atanh(f));
 7048}
 7049
 7050
 7051C_regparm C_word C_fcall C_a_i_sqrt(C_word **a, int c, C_word n)
 7052{
 7053  double f;
 7054
 7055  C_check_real(n, "sqrt", f);
 7056  return C_flonum(a, C_sqrt(f));
 7057}
 7058
 7059
 7060C_regparm C_word C_fcall C_i_assq(C_word x, C_word lst)
 7061{
 7062  C_word a;
 7063
 7064  while(!C_immediatep(lst) && C_header_type(lst) == C_PAIR_TYPE) {
 7065    a = C_u_i_car(lst);
 7066
 7067    if(!C_immediatep(a) && C_header_type(a) == C_PAIR_TYPE) {
 7068      if(C_u_i_car(a) == x) return a;
 7069    }
 7070    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "assq", a);
 7071  
 7072    lst = C_u_i_cdr(lst);
 7073  }
 7074
 7075  if(lst!=C_SCHEME_END_OF_LIST)
 7076    barf(C_BAD_ARGUMENT_TYPE_ERROR, "assq", lst);
 7077
 7078  return C_SCHEME_FALSE;
 7079}
 7080
 7081
 7082C_regparm C_word C_fcall C_i_assv(C_word x, C_word lst)
 7083{
 7084  C_word a;
 7085
 7086  while(!C_immediatep(lst) && C_header_type(lst) == C_PAIR_TYPE) {
 7087    a = C_u_i_car(lst);
 7088
 7089    if(!C_immediatep(a) && C_header_type(a) == C_PAIR_TYPE) {
 7090      if(C_truep(C_i_eqvp(C_u_i_car(a), x))) return a;
 7091    }
 7092    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "assv", a);
 7093  
 7094    lst = C_u_i_cdr(lst);
 7095  }
 7096
 7097  if(lst!=C_SCHEME_END_OF_LIST)
 7098    barf(C_BAD_ARGUMENT_TYPE_ERROR, "assv", lst);
 7099
 7100  return C_SCHEME_FALSE;
 7101}
 7102
 7103
 7104C_regparm C_word C_fcall C_i_assoc(C_word x, C_word lst)
 7105{
 7106  C_word a;
 7107
 7108  while(!C_immediatep(lst) && C_header_type(lst) == C_PAIR_TYPE) {
 7109    a = C_u_i_car(lst);
 7110
 7111    if(!C_immediatep(a) && C_header_type(a) == C_PAIR_TYPE) {
 7112      if(C_equalp(C_u_i_car(a), x)) return a;
 7113    }
 7114    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "assoc", a);
 7115  
 7116    lst = C_u_i_cdr(lst);
 7117  }
 7118
 7119  if(lst!=C_SCHEME_END_OF_LIST)
 7120    barf(C_BAD_ARGUMENT_TYPE_ERROR, "assoc", lst);
 7121
 7122  return C_SCHEME_FALSE;
 7123}
 7124
 7125
 7126C_regparm C_word C_fcall C_i_memq(C_word x, C_word lst)
 7127{
 7128  while(!C_immediatep(lst) && C_header_type(lst) == C_PAIR_TYPE) {
 7129    if(C_u_i_car(lst) == x) return lst;
 7130    else lst = C_u_i_cdr(lst);
 7131  }
 7132
 7133  if(lst!=C_SCHEME_END_OF_LIST)
 7134    barf(C_BAD_ARGUMENT_TYPE_ERROR, "memq", lst);
 7135
 7136  return C_SCHEME_FALSE;
 7137}
 7138
 7139
 7140C_regparm C_word C_fcall C_u_i_memq(C_word x, C_word lst)
 7141{
 7142  while(!C_immediatep(lst)) {
 7143    if(C_u_i_car(lst) == x) return lst;
 7144    else lst = C_u_i_cdr(lst);
 7145  }
 7146
 7147  return C_SCHEME_FALSE;
 7148}
 7149
 7150
 7151C_regparm C_word C_fcall C_i_memv(C_word x, C_word lst)
 7152{
 7153  while(!C_immediatep(lst) && C_header_type(lst) == C_PAIR_TYPE) {
 7154    if(C_truep(C_i_eqvp(C_u_i_car(lst), x))) return lst;
 7155    else lst = C_u_i_cdr(lst);
 7156  }
 7157
 7158  if(lst!=C_SCHEME_END_OF_LIST)
 7159    barf(C_BAD_ARGUMENT_TYPE_ERROR, "memv", lst);
 7160  
 7161  return C_SCHEME_FALSE;
 7162}
 7163
 7164
 7165C_regparm C_word C_fcall C_i_member(C_word x, C_word lst)
 7166{
 7167  while(!C_immediatep(lst) && C_header_type(lst) == C_PAIR_TYPE) {
 7168    if(C_equalp(C_u_i_car(lst), x)) return lst;
 7169    else lst = C_u_i_cdr(lst);
 7170  }
 7171
 7172  if(lst!=C_SCHEME_END_OF_LIST)
 7173    barf(C_BAD_ARGUMENT_TYPE_ERROR, "member", lst);
 7174  
 7175  return C_SCHEME_FALSE;
 7176}
 7177
 7178
 7179/* Inline routines for extended bindings: */
 7180
 7181C_regparm C_word C_fcall C_i_check_closure_2(C_word x, C_word loc)
 7182{
 7183  if(C_immediatep(x) || (C_header_bits(x) != C_CLOSURE_TYPE)) {
 7184    error_location = loc;
 7185    barf(C_BAD_ARGUMENT_TYPE_NO_CLOSURE_ERROR, NULL, x);
 7186  }
 7187
 7188  return C_SCHEME_UNDEFINED;
 7189}
 7190
 7191C_regparm C_word C_fcall C_i_check_fixnum_2(C_word x, C_word loc)
 7192{
 7193  if(!(x & C_FIXNUM_BIT)) {
 7194    error_location = loc;
 7195    barf(C_BAD_ARGUMENT_TYPE_NO_FIXNUM_ERROR, NULL, x);
 7196  }
 7197
 7198  return C_SCHEME_UNDEFINED;
 7199}
 7200
 7201/* DEPRECATED */
 7202C_regparm C_word C_fcall C_i_check_exact_2(C_word x, C_word loc)
 7203{
 7204  if(C_u_i_exactp(x) == C_SCHEME_FALSE) {
 7205    error_location = loc;
 7206    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_ERROR, NULL, x);
 7207  }
 7208
 7209  return C_SCHEME_UNDEFINED;
 7210}
 7211
 7212
 7213C_regparm C_word C_fcall C_i_check_inexact_2(C_word x, C_word loc)
 7214{
 7215  if(C_immediatep(x) || C_block_header(x) != C_FLONUM_TAG) {
 7216    error_location = loc;
 7217    barf(C_BAD_ARGUMENT_TYPE_NO_INEXACT_ERROR, NULL, x);
 7218  }
 7219
 7220  return C_SCHEME_UNDEFINED;
 7221}
 7222
 7223
 7224C_regparm C_word C_fcall C_i_check_char_2(C_word x, C_word loc)
 7225{
 7226  if((x & C_IMMEDIATE_TYPE_BITS) != C_CHARACTER_BITS) {
 7227    error_location = loc;
 7228    barf(C_BAD_ARGUMENT_TYPE_NO_CHAR_ERROR, NULL, x);
 7229  }
 7230
 7231  return C_SCHEME_UNDEFINED;
 7232}
 7233
 7234
 7235C_regparm C_word C_fcall C_i_check_number_2(C_word x, C_word loc)
 7236{
 7237  if (C_i_numberp(x) == C_SCHEME_FALSE) {
 7238    error_location = loc;
 7239    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, NULL, x);
 7240  }
 7241
 7242  return C_SCHEME_UNDEFINED;
 7243}
 7244
 7245
 7246C_regparm C_word C_fcall C_i_check_string_2(C_word x, C_word loc)
 7247{
 7248  if(C_immediatep(x) || C_header_bits(x) != C_STRING_TYPE) {
 7249    error_location = loc;
 7250    barf(C_BAD_ARGUMENT_TYPE_NO_STRING_ERROR, NULL, x);
 7251  }
 7252
 7253  return C_SCHEME_UNDEFINED;
 7254}
 7255
 7256
 7257C_regparm C_word C_fcall C_i_check_bytevector_2(C_word x, C_word loc)
 7258{
 7259  if(C_immediatep(x) || C_header_bits(x) != C_BYTEVECTOR_TYPE) {
 7260    error_location = loc;
 7261    barf(C_BAD_ARGUMENT_TYPE_NO_BYTEVECTOR_ERROR, NULL, x);
 7262  }
 7263
 7264  return C_SCHEME_UNDEFINED;
 7265}
 7266
 7267
 7268C_regparm C_word C_fcall C_i_check_vector_2(C_word x, C_word loc)
 7269{
 7270  if(C_immediatep(x) || C_header_bits(x) != C_VECTOR_TYPE) {
 7271    error_location = loc;
 7272    barf(C_BAD_ARGUMENT_TYPE_NO_VECTOR_ERROR, NULL, x);
 7273  }
 7274
 7275  return C_SCHEME_UNDEFINED;
 7276}
 7277
 7278
 7279C_regparm C_word C_fcall C_i_check_structure_2(C_word x, C_word st, C_word loc)
 7280{
 7281  if(C_immediatep(x) || C_header_bits(x) != C_STRUCTURE_TYPE || C_block_item(x,0) != st) {
 7282    error_location = loc;
 7283    barf(C_BAD_ARGUMENT_TYPE_BAD_STRUCT_ERROR, NULL, x, st);
 7284  }
 7285
 7286  return C_SCHEME_UNDEFINED;
 7287}
 7288
 7289
 7290C_regparm C_word C_fcall C_i_check_pair_2(C_word x, C_word loc)
 7291{
 7292  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 7293    error_location = loc;
 7294    barf(C_BAD_ARGUMENT_TYPE_NO_PAIR_ERROR, NULL, x);
 7295  }
 7296
 7297  return C_SCHEME_UNDEFINED;
 7298}
 7299
 7300
 7301C_regparm C_word C_fcall C_i_check_boolean_2(C_word x, C_word loc)
 7302{
 7303  if((x & C_IMMEDIATE_TYPE_BITS) != C_BOOLEAN_BITS) {
 7304    error_location = loc;
 7305    barf(C_BAD_ARGUMENT_TYPE_NO_BOOLEAN_ERROR, NULL, x);
 7306  }
 7307
 7308  return C_SCHEME_UNDEFINED;
 7309}
 7310
 7311
 7312C_regparm C_word C_fcall C_i_check_locative_2(C_word x, C_word loc)
 7313{
 7314  if(C_immediatep(x) || C_block_header(x) != C_LOCATIVE_TAG) {
 7315    error_location = loc;
 7316    barf(C_BAD_ARGUMENT_TYPE_NO_LOCATIVE_ERROR, NULL, x);
 7317  }
 7318
 7319  return C_SCHEME_UNDEFINED;
 7320}
 7321
 7322
 7323C_regparm C_word C_fcall C_i_check_symbol_2(C_word x, C_word loc)
 7324{
 7325  if(!C_truep(C_i_symbolp(x))) {
 7326    error_location = loc;
 7327    barf(C_BAD_ARGUMENT_TYPE_NO_SYMBOL_ERROR, NULL, x);
 7328  }
 7329
 7330  return C_SCHEME_UNDEFINED;
 7331}
 7332
 7333
 7334C_regparm C_word C_fcall C_i_check_keyword_2(C_word x, C_word loc)
 7335{
 7336  if(!C_truep(C_i_keywordp(x))) {
 7337    error_location = loc;
 7338    barf(C_BAD_ARGUMENT_TYPE_NO_KEYWORD_ERROR, NULL, x);
 7339  }
 7340
 7341  return C_SCHEME_UNDEFINED;
 7342}
 7343
 7344C_regparm C_word C_fcall C_i_check_list_2(C_word x, C_word loc)
 7345{
 7346  if(x != C_SCHEME_END_OF_LIST && (C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE)) {
 7347    error_location = loc;
 7348    barf(C_BAD_ARGUMENT_TYPE_NO_LIST_ERROR, NULL, x);
 7349  }
 7350
 7351  return C_SCHEME_UNDEFINED;
 7352}
 7353
 7354
 7355C_regparm C_word C_fcall C_i_check_port_2(C_word x, C_word dir, C_word open, C_word loc)
 7356{
 7357
 7358  if(C_immediatep(x) || C_header_bits(x) != C_PORT_TYPE) {
 7359    error_location = loc;
 7360    barf(C_BAD_ARGUMENT_TYPE_NO_PORT_ERROR, NULL, x);
 7361  }
 7362
 7363  if((C_block_item(x, 1) & dir) != dir) {	/* slot #1: I/O direction mask */
 7364    error_location = loc;
 7365    switch (dir) {
 7366    case C_fix(1):
 7367      barf(C_BAD_ARGUMENT_TYPE_PORT_NO_INPUT_ERROR, NULL, x);
 7368    case C_fix(2):
 7369      barf(C_BAD_ARGUMENT_TYPE_PORT_NO_OUTPUT_ERROR, NULL, x);
 7370    default:
 7371      barf(C_BAD_ARGUMENT_TYPE_PORT_DIRECTION_ERROR, NULL, x);
 7372    }
 7373  }
 7374
 7375  if(open == C_SCHEME_TRUE) {
 7376    if(C_block_item(x, 8) == C_FIXNUM_BIT) {	/* slot #8: closed mask */
 7377      error_location = loc;
 7378      barf(C_PORT_CLOSED_ERROR, NULL, x);
 7379    }
 7380  }
 7381
 7382  return C_SCHEME_UNDEFINED;
 7383}
 7384
 7385
 7386/*XXX these are not correctly named */
 7387C_regparm C_word C_fcall C_i_foreign_char_argumentp(C_word x)
 7388{
 7389  if((x & C_IMMEDIATE_TYPE_BITS) != C_CHARACTER_BITS)
 7390    barf(C_BAD_ARGUMENT_TYPE_NO_CHAR_ERROR, NULL, x);
 7391
 7392  return x;
 7393}
 7394
 7395
 7396C_regparm C_word C_fcall C_i_foreign_fixnum_argumentp(C_word x)
 7397{
 7398  if((x & C_FIXNUM_BIT) == 0)
 7399    barf(C_BAD_ARGUMENT_TYPE_NO_FIXNUM_ERROR, NULL, x);
 7400
 7401  return x;
 7402}
 7403
 7404
 7405C_regparm C_word C_fcall C_i_foreign_flonum_argumentp(C_word x)
 7406{
 7407  if((x & C_FIXNUM_BIT) != 0) return x;
 7408
 7409  if(C_immediatep(x) || C_block_header(x) != C_FLONUM_TAG)
 7410    barf(C_BAD_ARGUMENT_TYPE_NO_FLONUM_ERROR, NULL, x);
 7411
 7412  return x;
 7413}
 7414
 7415
 7416C_regparm C_word C_fcall C_i_foreign_block_argumentp(C_word x)
 7417{
 7418  if(C_immediatep(x))
 7419    barf(C_BAD_ARGUMENT_TYPE_NO_BLOCK_ERROR, NULL, x);
 7420
 7421  return x;
 7422}
 7423
 7424
 7425C_regparm C_word C_fcall C_i_foreign_struct_wrapper_argumentp(C_word t, C_word x)
 7426{
 7427  if(C_immediatep(x) || C_header_bits(x) != C_STRUCTURE_TYPE || C_block_item(x, 0) != t)
 7428    barf(C_BAD_ARGUMENT_TYPE_BAD_STRUCT_ERROR, NULL, t, x);
 7429
 7430  return x;
 7431}
 7432
 7433
 7434C_regparm C_word C_fcall C_i_foreign_string_argumentp(C_word x)
 7435{
 7436  if(C_immediatep(x) || C_header_bits(x) != C_STRING_TYPE)
 7437    barf(C_BAD_ARGUMENT_TYPE_NO_STRING_ERROR, NULL, x);
 7438
 7439  return x;
 7440}
 7441
 7442
 7443C_regparm C_word C_fcall C_i_foreign_symbol_argumentp(C_word x)
 7444{
 7445  if(C_immediatep(x) || C_header_bits(x) != C_SYMBOL_TYPE)
 7446    barf(C_BAD_ARGUMENT_TYPE_NO_SYMBOL_ERROR, NULL, x);
 7447
 7448  return x;
 7449}
 7450
 7451
 7452C_regparm C_word C_fcall C_i_foreign_pointer_argumentp(C_word x)
 7453{
 7454  if(C_immediatep(x) || (C_header_bits(x) & C_SPECIALBLOCK_BIT) == 0)
 7455    barf(C_BAD_ARGUMENT_TYPE_NO_POINTER_ERROR, NULL, x);
 7456
 7457  return x;
 7458}
 7459
 7460
 7461/* TODO: Is this used? */
 7462C_regparm C_word C_fcall C_i_foreign_scheme_or_c_pointer_argumentp(C_word x)
 7463{
 7464  if(C_immediatep(x) || (C_header_bits(x) & C_SPECIALBLOCK_BIT) == 0)
 7465    barf(C_BAD_ARGUMENT_TYPE_NO_POINTER_ERROR, NULL, x);
 7466
 7467  return x;
 7468}
 7469
 7470
 7471C_regparm C_word C_fcall C_i_foreign_tagged_pointer_argumentp(C_word x, C_word t)
 7472{
 7473  if(C_immediatep(x) || (C_header_bits(x) & C_SPECIALBLOCK_BIT) == 0
 7474     || (t != C_SCHEME_FALSE && !C_equalp(C_block_item(x, 1), t)))
 7475    barf(C_BAD_ARGUMENT_TYPE_NO_TAGGED_POINTER_ERROR, NULL, x, t);
 7476
 7477  return x;
 7478}
 7479
 7480C_regparm C_word C_fcall C_i_foreign_ranged_integer_argumentp(C_word x, C_word bits)
 7481{
 7482  if((x & C_FIXNUM_BIT) != 0) {
 7483    if (C_truep(C_fixnum_lessp(C_i_fixnum_length(x), bits))) return x;
 7484    else barf(C_BAD_ARGUMENT_TYPE_FOREIGN_LIMITATION, NULL, x);
 7485  } else if (C_truep(C_i_bignump(x))) {
 7486    if (C_truep(C_fixnum_lessp(C_i_integer_length(x), bits))) return x;
 7487    else barf(C_BAD_ARGUMENT_TYPE_FOREIGN_LIMITATION, NULL, x);
 7488  } else {
 7489    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, NULL, x);
 7490  }
 7491}
 7492
 7493C_regparm C_word C_fcall C_i_foreign_unsigned_ranged_integer_argumentp(C_word x, C_word bits)
 7494{
 7495  if((x & C_FIXNUM_BIT) != 0) {
 7496    if(x & C_INT_SIGN_BIT) barf(C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR, NULL, x);
 7497    else if(C_ilen(C_unfix(x)) <= C_unfix(bits)) return x;
 7498    else barf(C_BAD_ARGUMENT_TYPE_FOREIGN_LIMITATION, NULL, x);
 7499  } else if(C_truep(C_i_bignump(x))) {
 7500    if(C_bignum_negativep(x)) barf(C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR, NULL, x);
 7501    else if(integer_length_abs(x) <= C_unfix(bits)) return x;
 7502    else barf(C_BAD_ARGUMENT_TYPE_FOREIGN_LIMITATION, NULL, x);
 7503  } else {
 7504    barf(C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR, NULL, x);
 7505  }
 7506}
 7507
 7508/* I */
 7509C_regparm C_word C_fcall C_i_not_pair_p_2(C_word x)
 7510{
 7511  return C_mk_bool(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE);
 7512}
 7513
 7514
 7515C_regparm C_word C_fcall C_i_null_list_p(C_word x)
 7516{
 7517  if(x == C_SCHEME_END_OF_LIST) return C_SCHEME_TRUE;
 7518  else if(!C_immediatep(x) && C_header_type(x) == C_PAIR_TYPE) return C_SCHEME_FALSE;
 7519  else {
 7520    barf(C_BAD_ARGUMENT_TYPE_NO_LIST_ERROR, "null-list?", x);
 7521    return C_SCHEME_FALSE;
 7522  }
 7523}
 7524
 7525
 7526C_regparm C_word C_fcall C_i_string_null_p(C_word x)
 7527{
 7528  if(!C_immediatep(x) && C_header_bits(x) == C_STRING_TYPE)
 7529    return C_zero_length_p(x);
 7530  else {
 7531    barf(C_BAD_ARGUMENT_TYPE_NO_STRING_ERROR, "string-null?", x);
 7532    return C_SCHEME_FALSE;
 7533  }
 7534}
 7535
 7536
 7537C_regparm C_word C_fcall C_i_null_pointerp(C_word x)
 7538{
 7539  if(!C_immediatep(x) && (C_header_bits(x) & C_SPECIALBLOCK_BIT) != 0)
 7540    return C_null_pointerp(x);
 7541
 7542  barf(C_BAD_ARGUMENT_TYPE_ERROR, "null-pointer?", x);
 7543  return C_SCHEME_FALSE;
 7544}
 7545
 7546/* only used here for char comparators below: */
 7547static C_word C_fcall check_char_internal(C_word x, C_char *loc)
 7548{
 7549  if((x & C_IMMEDIATE_TYPE_BITS) != C_CHARACTER_BITS) {
 7550    error_location = intern0(loc);
 7551    barf(C_BAD_ARGUMENT_TYPE_NO_CHAR_ERROR, NULL, x);
 7552  }
 7553
 7554  return C_SCHEME_UNDEFINED;
 7555}
 7556
 7557C_regparm C_word C_i_char_equalp(C_word x, C_word y)
 7558{
 7559  check_char_internal(x, "char=?");
 7560  check_char_internal(y, "char=?");
 7561  return C_u_i_char_equalp(x, y);
 7562}
 7563
 7564C_regparm C_word C_i_char_greaterp(C_word x, C_word y)
 7565{
 7566  check_char_internal(x, "char>?");
 7567  check_char_internal(y, "char>?");
 7568  return C_u_i_char_greaterp(x, y);
 7569}
 7570
 7571C_regparm C_word C_i_char_lessp(C_word x, C_word y)
 7572{
 7573  check_char_internal(x, "char<?");
 7574  check_char_internal(y, "char<?");
 7575  return C_u_i_char_lessp(x, y);
 7576}
 7577
 7578C_regparm C_word C_i_char_greater_or_equal_p(C_word x, C_word y)
 7579{
 7580  check_char_internal(x, "char>=?");
 7581  check_char_internal(y, "char>=?");
 7582  return C_u_i_char_greater_or_equal_p(x, y);
 7583}
 7584
 7585C_regparm C_word C_i_char_less_or_equal_p(C_word x, C_word y)
 7586{
 7587  check_char_internal(x, "char<=?");
 7588  check_char_internal(y, "char<=?");
 7589  return C_u_i_char_less_or_equal_p(x, y);
 7590}
 7591
 7592
 7593/* Primitives: */
 7594
 7595void C_ccall C_apply(C_word c, C_word *av)
 7596{
 7597  C_word
 7598    /* closure = av[ 0 ] */
 7599    k = av[ 1 ],
 7600    fn = av[ 2 ];
 7601  int av2_size, i, n = c - 3;
 7602  int non_list_args = n - 1;
 7603  C_word lst, len, *ptr, *av2;
 7604
 7605  if(c < 4) C_bad_min_argc(c, 4);
 7606
 7607  if(C_immediatep(fn) || C_header_bits(fn) != C_CLOSURE_TYPE)
 7608    barf(C_NOT_A_CLOSURE_ERROR, "apply", fn);
 7609
 7610  lst = av[ c - 1 ];
 7611  if(lst != C_SCHEME_END_OF_LIST && (C_immediatep(lst) || C_header_type(lst) != C_PAIR_TYPE))
 7612    barf(C_BAD_ARGUMENT_TYPE_ERROR, "apply", lst);
 7613
 7614  len = C_unfix(C_u_i_length(lst));
 7615  av2_size = 2 + non_list_args + len;
 7616
 7617  if(C_demand(av2_size))
 7618    stack_check_demand = 0;
 7619  else if(stack_check_demand)
 7620    C_stack_overflow("apply");
 7621  else {
 7622    stack_check_demand = av2_size;
 7623    C_save_and_reclaim((void *)C_apply, c, av);
 7624  }
 7625
 7626  av2 = ptr = C_alloc(av2_size);
 7627  *(ptr++) = fn;
 7628  *(ptr++) = k;
 7629
 7630  if(non_list_args > 0) {
 7631    C_memcpy(ptr, av + 3, non_list_args * sizeof(C_word));
 7632    ptr += non_list_args;
 7633  }
 7634
 7635  while(len--) {
 7636    *(ptr++) = C_u_i_car(lst);
 7637    lst = C_u_i_cdr(lst);
 7638  }
 7639
 7640  assert((ptr - av2) == av2_size);
 7641
 7642  ((C_proc)(void *)C_block_item(fn, 0))(av2_size, av2);
 7643}
 7644
 7645
 7646void C_ccall C_call_cc(C_word c, C_word *av)
 7647{
 7648  C_word
 7649    /* closure = av[ 0 ] */
 7650    k = av[ 1 ],
 7651    cont = av[ 2 ],
 7652    *a = C_alloc(C_SIZEOF_CLOSURE(2)),
 7653    wrapper;
 7654  void *pr = (void *)C_block_item(cont,0);
 7655  C_word av2[ 3 ];
 7656  
 7657  if(C_immediatep(cont) || C_header_bits(cont) != C_CLOSURE_TYPE)
 7658    barf(C_BAD_ARGUMENT_TYPE_ERROR, "call-with-current-continuation", cont);
 7659  
 7660  /* Check for values-continuation: */
 7661  if(C_block_item(k, 0) == (C_word)values_continuation)
 7662    wrapper = C_closure(&a, 2, (C_word)call_cc_values_wrapper, k);
 7663  else wrapper = C_closure(&a, 2, (C_word)call_cc_wrapper, k);
 7664  
 7665  av2[ 0 ] = cont;
 7666  av2[ 1 ] = k;
 7667  av2[ 2 ] = wrapper;
 7668  ((C_proc)pr)(3, av2);
 7669}
 7670
 7671
 7672void C_ccall call_cc_wrapper(C_word c, C_word *av)
 7673{
 7674  C_word
 7675    closure = av[ 0 ],
 7676    /* av[ 1 ] is current k and ignored */
 7677    result,
 7678    k = C_block_item(closure, 1);
 7679
 7680  if(c != 3) C_bad_argc(c, 3);
 7681
 7682  result = av[ 2 ];
 7683  C_kontinue(k, result);
 7684}
 7685
 7686
 7687void C_ccall call_cc_values_wrapper(C_word c, C_word *av)
 7688{
 7689  C_word
 7690    closure = av[ 0 ],
 7691    /* av[ 1 ] is current k and ignored */
 7692    k = C_block_item(closure, 1),
 7693    x1,
 7694    n = c;
 7695  
 7696  av[ 0 ] = k;               /* reuse av */
 7697  C_memmove(av + 1, av + 2, (n - 1) * sizeof(C_word));
 7698  C_do_apply(n - 1, av);
 7699}
 7700
 7701
 7702void C_ccall C_continuation_graft(C_word c, C_word *av)
 7703{
 7704  C_word
 7705    /* self = av[ 0 ] */
 7706    /* k = av[ 1 ] */
 7707    kk = av[ 2 ],
 7708    proc = av[ 3 ];
 7709
 7710  av[ 0 ] = proc;               /* reuse av */
 7711  av[ 1 ] = C_block_item(kk, 1);
 7712  ((C_proc)C_fast_retrieve_proc(proc))(2, av);
 7713}
 7714
 7715
 7716void C_ccall C_values(C_word c, C_word *av)
 7717{
 7718  C_word
 7719    /* closure = av[ 0 ] */
 7720    k = av[ 1 ],
 7721    n = c;
 7722
 7723  if(c < 2) C_bad_min_argc(c, 2);
 7724
 7725  /* Check continuation whether it receives multiple values: */
 7726  if(C_block_item(k, 0) == (C_word)values_continuation) {
 7727    av[ 0 ] = k;                /* reuse av */
 7728    C_memmove(av + 1, av + 2, (c - 2) * sizeof(C_word));
 7729    C_do_apply(c - 1, av);
 7730  }
 7731  
 7732  if(c != 3) {
 7733#ifdef RELAX_MULTIVAL_CHECK
 7734    if(c == 2) n = C_SCHEME_UNDEFINED;
 7735    else n = av[ 2 ];
 7736#else
 7737    barf(C_CONTINUATION_CANT_RECEIVE_VALUES_ERROR, "values", k);
 7738#endif
 7739  }
 7740  else n = av[ 2 ];
 7741
 7742  C_kontinue(k, n);
 7743}
 7744
 7745
 7746void C_ccall C_apply_values(C_word c, C_word *av)
 7747{
 7748  C_word
 7749    /* closure = av[ 0 ] */
 7750    k = av[ 1 ],
 7751    lst, len, n;
 7752
 7753  if(c != 3) C_bad_argc(c, 3);
 7754
 7755  lst = av[ 2 ];
 7756
 7757  if(lst != C_SCHEME_END_OF_LIST && (C_immediatep(lst) || C_header_type(lst) != C_PAIR_TYPE))
 7758    barf(C_BAD_ARGUMENT_TYPE_ERROR, "apply", lst);
 7759
 7760  /* Check whether continuation receives multiple values: */
 7761  if(C_block_item(k, 0) == (C_word)values_continuation) {
 7762    C_word *av2, *ptr;
 7763
 7764    len = C_unfix(C_u_i_length(lst));
 7765    n = len + 1;
 7766
 7767    if(C_demand(n))
 7768      stack_check_demand = 0;
 7769    else if(stack_check_demand)
 7770      C_stack_overflow("apply");
 7771    else {
 7772      stack_check_demand = n;
 7773      C_save_and_reclaim((void *)C_apply_values, c, av);
 7774    }
 7775
 7776    av2 = C_alloc(n);
 7777    av2[ 0 ] = k;
 7778    ptr = av2 + 1;
 7779    while(len--) {
 7780      *(ptr++) = C_u_i_car(lst);
 7781      lst = C_u_i_cdr(lst);
 7782    }
 7783
 7784    C_do_apply(n, av2);
 7785  }
 7786  
 7787  if(C_immediatep(lst)) {
 7788#ifdef RELAX_MULTIVAL_CHECK
 7789    n = C_SCHEME_UNDEFINED;
 7790#else
 7791    barf(C_CONTINUATION_CANT_RECEIVE_VALUES_ERROR, "values", k);
 7792#endif
 7793  }
 7794  else if(C_header_type(lst) == C_PAIR_TYPE) {
 7795    if(C_u_i_cdr(lst) == C_SCHEME_END_OF_LIST)
 7796      n = C_u_i_car(lst);
 7797    else {
 7798#ifdef RELAX_MULTIVAL_CHECK
 7799      n = C_u_i_car(lst);
 7800#else
 7801      barf(C_CONTINUATION_CANT_RECEIVE_VALUES_ERROR, "values", k);
 7802#endif
 7803    }
 7804  }
 7805  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "apply", lst);
 7806  
 7807  C_kontinue(k, n);
 7808}
 7809
 7810
 7811void C_ccall C_call_with_values(C_word c, C_word *av)
 7812{
 7813  C_word
 7814    /* closure = av[ 0 ] */
 7815    k = av[ 1 ],
 7816    thunk,
 7817    kont,
 7818    *a = C_alloc(C_SIZEOF_CLOSURE(3)),
 7819    kk;
 7820
 7821  if(c != 4) C_bad_argc(c, 4);
 7822
 7823  thunk = av[ 2 ];
 7824  kont = av[ 3 ];
 7825
 7826  if(C_immediatep(thunk) || C_header_bits(thunk) != C_CLOSURE_TYPE)
 7827    barf(C_BAD_ARGUMENT_TYPE_ERROR, "call-with-values", thunk);
 7828
 7829  if(C_immediatep(kont) || C_header_bits(kont) != C_CLOSURE_TYPE)
 7830    barf(C_BAD_ARGUMENT_TYPE_ERROR, "call-with-values", kont);
 7831
 7832  kk = C_closure(&a, 3, (C_word)values_continuation, kont, k);
 7833  av[ 0 ] = thunk;              /* reuse av */
 7834  av[ 1 ] = kk;
 7835  C_do_apply(2, av);
 7836}
 7837
 7838
 7839void C_ccall C_u_call_with_values(C_word c, C_word *av)
 7840{
 7841  C_word
 7842    /* closure = av[ 0 ] */
 7843    k = av[ 1 ],
 7844    thunk = av[ 2 ],
 7845    kont = av[ 3 ],
 7846    *a = C_alloc(C_SIZEOF_CLOSURE(3)),
 7847    kk;
 7848
 7849  kk = C_closure(&a, 3, (C_word)values_continuation, kont, k);
 7850  av[ 0 ] = thunk;              /* reuse av */
 7851  av[ 1 ] = kk;
 7852  C_do_apply(2, av);
 7853}
 7854
 7855
 7856void C_ccall values_continuation(C_word c, C_word *av)
 7857{
 7858  C_word
 7859    closure = av[ 0 ],
 7860    kont = C_block_item(closure, 1),
 7861    k = C_block_item(closure, 2),
 7862    *av2 = C_alloc(c + 1);
 7863
 7864  av2[ 0 ] = kont;
 7865  av2[ 1 ] = k;
 7866  C_memcpy(av2 + 2, av + 1, (c - 1) * sizeof(C_word));
 7867  C_do_apply(c + 1, av2);
 7868}
 7869
 7870static C_word rat_times_integer(C_word **ptr, C_word rat, C_word i)
 7871{
 7872  C_word ab[C_SIZEOF_FIX_BIGNUM * 2], *a = ab, num, denom, gcd, a_div_g;
 7873
 7874  switch (i) {
 7875  case C_fix(0): return C_fix(0);
 7876  case C_fix(1): return rat;
 7877  case C_fix(-1):
 7878    num = C_s_a_u_i_integer_negate(ptr, 1, C_u_i_ratnum_num(rat));
 7879    return C_ratnum(ptr, num , C_u_i_ratnum_denom(rat));
 7880  /* default: CONTINUE BELOW */
 7881  }
 7882
 7883  num = C_u_i_ratnum_num(rat);
 7884  denom = C_u_i_ratnum_denom(rat);
 7885
 7886  /* a/b * c/d = a*c / b*d  [with b = 1] */
 7887  /*  =  ((a / g) * c) / (d / g) */
 7888  /* With   g = gcd(a, d)   and  a = x   [Knuth, 4.5.1] */
 7889  gcd = C_s_a_u_i_integer_gcd(&a, 2, i, denom);
 7890
 7891  /* Calculate a/g  (= i/gcd), which will later be multiplied by y */
 7892  a_div_g = C_s_a_u_i_integer_quotient(&a, 2, i, gcd);
 7893  if (a_div_g == C_fix(0)) {
 7894    clear_buffer_object(ab, gcd);
 7895    return C_fix(0); /* Save some work */
 7896  }
 7897
 7898  /* Final numerator = a/g * c  (= a_div_g * num) */
 7899  num = C_s_a_u_i_integer_times(ptr, 2, a_div_g, num);
 7900
 7901  /* Final denominator = d/g  (= denom/gcd) */
 7902  denom = C_s_a_u_i_integer_quotient(ptr, 2, denom, gcd);
 7903
 7904  num = move_buffer_object(ptr, ab, num);
 7905  denom = move_buffer_object(ptr, ab, denom);
 7906  
 7907  clear_buffer_object(ab, gcd);
 7908  clear_buffer_object(ab, a_div_g);
 7909
 7910  if (denom == C_fix(1)) return num;
 7911  else return C_ratnum(ptr, num, denom);
 7912}
 7913
 7914static C_word rat_times_rat(C_word **ptr, C_word x, C_word y)
 7915{
 7916  C_word ab[C_SIZEOF_FIX_BIGNUM * 6], *a = ab,
 7917         num, denom, xnum, xdenom, ynum, ydenom,
 7918         g1, g2, a_div_g1, b_div_g2, c_div_g2, d_div_g1;
 7919
 7920  xnum = C_u_i_ratnum_num(x);
 7921  xdenom = C_u_i_ratnum_denom(x);
 7922  ynum = C_u_i_ratnum_num(y);
 7923  ydenom = C_u_i_ratnum_denom(y);
 7924
 7925  /* a/b * c/d = a*c / b*d  [generic] */
 7926  /*   = ((a / g1) * (c / g2)) / ((b / g2) * (d / g1)) */
 7927  /* With  g1 = gcd(a, d)  and   g2 = gcd(b, c) [Knuth, 4.5.1] */
 7928  g1 = C_s_a_u_i_integer_gcd(&a, 2, xnum, ydenom);
 7929  g2 = C_s_a_u_i_integer_gcd(&a, 2, ynum, xdenom);
 7930
 7931  /* Calculate a/g1  (= xnum/g1), which will later be multiplied by c/g2 */
 7932  a_div_g1 = C_s_a_u_i_integer_quotient(&a, 2, xnum, g1);
 7933
 7934  /* Calculate c/g2  (= ynum/g2), which will later be multiplied by a/g1 */
 7935  c_div_g2 = C_s_a_u_i_integer_quotient(&a, 2, ynum, g2);
 7936
 7937  /* Final numerator = a/g1 * c/g2 */
 7938  num = C_s_a_u_i_integer_times(ptr, 2, a_div_g1, c_div_g2);
 7939
 7940  /* Now, do the same for the denominator.... */
 7941
 7942  /* Calculate b/g2  (= xdenom/g2), which will later be multiplied by d/g1 */
 7943  b_div_g2 = C_s_a_u_i_integer_quotient(&a, 2, xdenom, g2);
 7944
 7945  /* Calculate d/g1  (= ydenom/g1), which will later be multiplied by b/g2 */
 7946  d_div_g1 = C_s_a_u_i_integer_quotient(&a, 2, ydenom, g1);
 7947
 7948  /* Final denominator = b/g2 * d/g1 */
 7949  denom = C_s_a_u_i_integer_times(ptr, 2, b_div_g2, d_div_g1);
 7950
 7951  num = move_buffer_object(ptr, ab, num);
 7952  denom = move_buffer_object(ptr, ab, denom);
 7953
 7954  clear_buffer_object(ab, g1);
 7955  clear_buffer_object(ab, g2);
 7956  clear_buffer_object(ab, a_div_g1);
 7957  clear_buffer_object(ab, b_div_g2);
 7958  clear_buffer_object(ab, c_div_g2);
 7959  clear_buffer_object(ab, d_div_g1);
 7960
 7961  if (denom == C_fix(1)) return num;
 7962  else return C_ratnum(ptr, num, denom);
 7963}
 7964
 7965static C_word
 7966cplx_times(C_word **ptr, C_word rx, C_word ix, C_word ry, C_word iy)
 7967{
 7968  /* Allocation here is kind of tricky: Each intermediate result can
 7969   * be at most a ratnum consisting of two bignums (2 digits), so
 7970   * C_SIZEOF_RATNUM + C_SIZEOF_BIGNUM(2) = 9 words
 7971   */
 7972  C_word ab[(C_SIZEOF_RATNUM + C_SIZEOF_BIGNUM(2))*6], *a = ab,
 7973         r1, r2, i1, i2, r, i;
 7974
 7975  /* a+bi * c+di = (a*c - b*d) + (a*d + b*c)i */
 7976  /* We call these:  r1 = a*c, r2 = b*d, i1 = a*d, i2 = b*c */
 7977  r1 = C_s_a_i_times(&a, 2, rx, ry);
 7978  r2 = C_s_a_i_times(&a, 2, ix, iy);
 7979  i1 = C_s_a_i_times(&a, 2, rx, iy);
 7980  i2 = C_s_a_i_times(&a, 2, ix, ry);
 7981  
 7982  r = C_s_a_i_minus(ptr, 2, r1, r2);
 7983  i = C_s_a_i_plus(ptr, 2, i1, i2);
 7984
 7985  r = move_buffer_object(ptr, ab, r);
 7986  i = move_buffer_object(ptr, ab, i);
 7987
 7988  clear_buffer_object(ab, r1);
 7989  clear_buffer_object(ab, r2);
 7990  clear_buffer_object(ab, i1);
 7991  clear_buffer_object(ab, i2);
 7992
 7993  if (C_truep(C_u_i_zerop2(i))) return r;
 7994  else return C_cplxnum(ptr, r, i);
 7995}
 7996
 7997/* The maximum size this needs is that required to store a complex
 7998 * number result, where both real and imag parts consist of ratnums.
 7999 * The maximum size of those ratnums is if they consist of two bignums
 8000 * from a fixnum multiplication (2 digits each), so we're looking at
 8001 * C_SIZEOF_RATNUM * 3 + C_SIZEOF_BIGNUM(2) * 4 = 33 words!
 8002 */
 8003C_regparm C_word C_fcall
 8004C_s_a_i_times(C_word **ptr, C_word n, C_word x, C_word y)
 8005{
 8006  if (x & C_FIXNUM_BIT) {
 8007    if (y & C_FIXNUM_BIT) {
 8008      return C_a_i_fixnum_times(ptr, 2, x, y);
 8009    } else if (C_immediatep(y)) {
 8010      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", y);
 8011    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8012      return C_flonum(ptr, (double)C_unfix(x) * C_flonum_magnitude(y));
 8013    } else if (C_truep(C_bignump(y))) {
 8014      return C_s_a_u_i_integer_times(ptr, 2, x, y);
 8015    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8016      return rat_times_integer(ptr, y, x);
 8017    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8018      return cplx_times(ptr, x, C_fix(0),
 8019                        C_u_i_cplxnum_real(y), C_u_i_cplxnum_imag(y));
 8020    } else {
 8021      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", y);
 8022    }
 8023  } else if (C_immediatep(x)) {
 8024    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", x);
 8025  } else if (C_block_header(x) == C_FLONUM_TAG) {
 8026    if (y & C_FIXNUM_BIT) {
 8027      return C_flonum(ptr, C_flonum_magnitude(x) * (double)C_unfix(y));
 8028    } else if (C_immediatep(y)) {
 8029      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", y);
 8030    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8031      return C_a_i_flonum_times(ptr, 2, x, y);
 8032    } else if (C_truep(C_bignump(y))) {
 8033      return C_flonum(ptr, C_flonum_magnitude(x) * C_bignum_to_double(y));
 8034    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8035      return C_s_a_i_times(ptr, 2, x, C_a_i_exact_to_inexact(ptr, 1, y));
 8036    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8037      C_word ab[C_SIZEOF_FLONUM], *a = ab;
 8038      return cplx_times(ptr, x, C_flonum(&a, 0.0),
 8039                        C_u_i_cplxnum_real(y), C_u_i_cplxnum_imag(y));
 8040    } else {
 8041      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", y);
 8042    }
 8043  } else if (C_truep(C_bignump(x))) {
 8044    if (y & C_FIXNUM_BIT) {
 8045      return C_s_a_u_i_integer_times(ptr, 2, x, y);
 8046    } else if (C_immediatep(y)) {
 8047      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", x);
 8048    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8049      return C_flonum(ptr, C_bignum_to_double(x) * C_flonum_magnitude(y));
 8050    } else if (C_truep(C_bignump(y))) {
 8051      return C_s_a_u_i_integer_times(ptr, 2, x, y);
 8052    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8053      return rat_times_integer(ptr, y, x);
 8054    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8055      return cplx_times(ptr, x, C_fix(0),
 8056                        C_u_i_cplxnum_real(y), C_u_i_cplxnum_imag(y));
 8057    } else {
 8058      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", y);
 8059    }
 8060  } else if (C_block_header(x) == C_RATNUM_TAG) {
 8061    if (y & C_FIXNUM_BIT) {
 8062      return rat_times_integer(ptr, x, y);
 8063    } else if (C_immediatep(y)) {
 8064      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", y);
 8065    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8066      return C_s_a_i_times(ptr, 2, C_a_i_exact_to_inexact(ptr, 1, x), y);
 8067    } else if (C_truep(C_bignump(y))) {
 8068      return rat_times_integer(ptr, x, y);
 8069    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8070        return rat_times_rat(ptr, x, y);
 8071    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8072      return cplx_times(ptr, x, C_fix(0),
 8073                        C_u_i_cplxnum_real(y), C_u_i_cplxnum_imag(y));
 8074    } else {
 8075      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", y);
 8076    }
 8077  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 8078    if (!C_immediatep(y) && C_block_header(y) == C_CPLXNUM_TAG) {
 8079      return cplx_times(ptr, C_u_i_cplxnum_real(x), C_u_i_cplxnum_imag(x),
 8080                        C_u_i_cplxnum_real(y), C_u_i_cplxnum_imag(y));
 8081    } else {
 8082      C_word ab[C_SIZEOF_FLONUM], *a = ab, yi;
 8083      yi = C_truep(C_i_flonump(y)) ? C_flonum(&a,0) : C_fix(0);
 8084      return cplx_times(ptr, C_u_i_ratnum_num(x), C_u_i_ratnum_denom(x), y, yi);
 8085    }
 8086  } else {
 8087    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", x);
 8088  }
 8089}
 8090
 8091
 8092C_regparm C_word C_fcall
 8093C_s_a_u_i_integer_times(C_word **ptr, C_word n, C_word x, C_word y)
 8094{
 8095  if (x & C_FIXNUM_BIT) {
 8096    if (y & C_FIXNUM_BIT) {
 8097      return C_a_i_fixnum_times(ptr, 2, x, y);
 8098    } else {
 8099      C_word tmp = x; /* swap to ensure x is a bignum and y a fixnum */
 8100      x = y;
 8101      y = tmp;
 8102    }
 8103  }
 8104  /* Here, we know for sure that X is a bignum */
 8105  if (y == C_fix(0)) {
 8106    return C_fix(0);
 8107  } else if (y == C_fix(1)) {
 8108    return x;
 8109  } else if (y == C_fix(-1)) {
 8110    return C_s_a_u_i_integer_negate(ptr, 1, x);
 8111  } else if (y & C_FIXNUM_BIT) { /* Any other fixnum */
 8112    C_word absy = (y & C_INT_SIGN_BIT) ? -C_unfix(y) : C_unfix(y),
 8113           negp = C_mk_bool((y & C_INT_SIGN_BIT) ?
 8114                            !C_bignum_negativep(x) :
 8115                            C_bignum_negativep(x));
 8116  
 8117    if (C_fitsinbignumhalfdigitp(absy) ||
 8118        (((C_uword)1 << (C_ilen(absy)-1)) == absy && C_fitsinfixnump(absy))) {
 8119      C_word size, res;
 8120      C_uword *startr, *endr;
 8121      int shift;
 8122      size = C_bignum_size(x) + 1; /* Needs _at most_ one more digit */
 8123      res = C_allocate_scratch_bignum(ptr, C_fix(size), negp, C_SCHEME_FALSE);
 8124
 8125      bignum_digits_destructive_copy(res, x);
 8126
 8127      startr = C_bignum_digits(res);
 8128      endr = startr + size - 1;
 8129      /* Scale up, and sanitise the result. */
 8130      shift = C_ilen(absy) - 1;
 8131      if (((C_uword)1 << shift) == absy) { /* Power of two? */
 8132        *endr = bignum_digits_destructive_shift_left(startr, endr, shift);
 8133      } else {
 8134        *endr = bignum_digits_destructive_scale_up_with_carry(startr, endr,
 8135                                                              absy, 0);
 8136      }
 8137      return C_bignum_simplify(res);
 8138    } else {
 8139      C_word *a = C_alloc(C_SIZEOF_FIX_BIGNUM);
 8140      y = C_a_u_i_fix_to_big(&a, y);
 8141      return bignum_times_bignum_unsigned(ptr, x, y, negp);
 8142    }
 8143  } else {
 8144    C_word negp = C_bignum_negativep(x) ?
 8145                  !C_bignum_negativep(y) :
 8146                  C_bignum_negativep(y);
 8147    return bignum_times_bignum_unsigned(ptr, x, y, C_mk_bool(negp));
 8148  }
 8149}
 8150
 8151static C_regparm C_word
 8152bignum_times_bignum_unsigned(C_word **ptr, C_word x, C_word y, C_word negp)
 8153{
 8154  C_word size, res = C_SCHEME_FALSE;
 8155  if (C_bignum_size(y) < C_bignum_size(x)) { /* Ensure size(x) <= size(y) */
 8156    C_word z = x;
 8157    x = y;
 8158    y = z;
 8159  }
 8160
 8161  if (C_bignum_size(x) >= C_KARATSUBA_THRESHOLD)
 8162    res = bignum_times_bignum_karatsuba(ptr, x, y, negp);
 8163
 8164  if (!C_truep(res)) {
 8165    size = C_bignum_size(x) + C_bignum_size(y);
 8166    res = C_allocate_scratch_bignum(ptr, C_fix(size), negp, C_SCHEME_TRUE);
 8167    bignum_digits_multiply(x, y, res);
 8168    res = C_bignum_simplify(res);
 8169  }
 8170  return res;
 8171}
 8172
 8173/* Karatsuba multiplication: invoked when the two numbers are large
 8174 * enough to make it worthwhile, and we still have enough stack left.
 8175 * Complexity is O(n^log2(3)), where n is max(len(x), len(y)).  The
 8176 * description in [Knuth, 4.3.3] leaves a lot to be desired.  [MCA,
 8177 * 1.3.2] and [MpNT, 3.2] are a bit easier to understand.  We assume
 8178 * that length(x) <= length(y).
 8179 */
 8180static C_regparm C_word
 8181bignum_times_bignum_karatsuba(C_word **ptr, C_word x, C_word y, C_word negp)
 8182{
 8183   C_word kab[C_SIZEOF_FIX_BIGNUM*15+C_SIZEOF_BIGNUM(2)*3], *ka = kab, o[18],
 8184          xhi, xlo, xmid, yhi, ylo, ymid, a, b, c, n, bits;
 8185   int i = 0;
 8186
 8187   /* Ran out of stack?  Fall back to non-recursive multiplication */
 8188   C_stack_check1(return C_SCHEME_FALSE);
 8189   
 8190   /* Split |x| in half: <xhi,xlo> and |y|: <yhi,ylo> with len(ylo)=len(xlo) */
 8191   x = o[i++] = C_s_a_u_i_integer_abs(&ka, 1, x);
 8192   y = o[i++] = C_s_a_u_i_integer_abs(&ka, 1, y);
 8193   n = C_fix(C_bignum_size(y) >> 1);
 8194   xhi = o[i++] = bignum_extract_digits(&ka, 3, x, n, C_SCHEME_FALSE);
 8195   xlo = o[i++] = bignum_extract_digits(&ka, 3, x, C_fix(0), n);
 8196   yhi = o[i++] = bignum_extract_digits(&ka, 3, y, n, C_SCHEME_FALSE);
 8197   ylo = o[i++] = bignum_extract_digits(&ka, 3, y, C_fix(0), n);
 8198
 8199   /* a = xhi * yhi, b = xlo * ylo, c = (xhi - xlo) * (yhi - ylo) */
 8200   a = o[i++] = C_s_a_u_i_integer_times(&ka, 2, xhi, yhi);
 8201   b = o[i++] = C_s_a_u_i_integer_times(&ka, 2, xlo, ylo);
 8202   xmid = o[i++] = C_s_a_u_i_integer_minus(&ka, 2, xhi, xlo);
 8203   ymid = o[i++] = C_s_a_u_i_integer_minus(&ka, 2, yhi, ylo);
 8204   c = o[i++] = C_s_a_u_i_integer_times(&ka, 2, xmid, ymid);
 8205
 8206   /* top(x) = a << (bits - 1)  and  bottom(y) = ((b + (a - c)) << bits) + b */
 8207   bits = C_unfix(n) * C_BIGNUM_DIGIT_LENGTH;
 8208   x = o[i++] = C_s_a_i_arithmetic_shift(&ka, 2, a, C_fix((C_uword)bits << 1));
 8209   c = o[i++] = C_s_a_u_i_integer_minus(&ka, 2, a, c);
 8210   c = o[i++] = C_s_a_u_i_integer_plus(&ka, 2, b, c);
 8211   c = o[i++] = C_s_a_i_arithmetic_shift(&ka, 2, c, C_fix(bits));
 8212   y = o[i++] = C_s_a_u_i_integer_plus(&ka, 2, c, b);
 8213   /* Finally, return top + bottom, and correct for negative */
 8214   n = o[i++] = C_s_a_u_i_integer_plus(&ka, 2, x, y);
 8215   if (C_truep(negp)) n = o[i++] = C_s_a_u_i_integer_negate(&ka, 1, n);
 8216
 8217   n = move_buffer_object(ptr, kab, n);
 8218   while(i--) clear_buffer_object(kab, o[i]);
 8219   return n;
 8220}
 8221
 8222void C_ccall C_times(C_word c, C_word *av)
 8223{
 8224  /* C_word closure = av[ 0 ]; */
 8225  C_word k = av[ 1 ];
 8226  C_word next_val,
 8227    result = C_fix(1),
 8228    prev_result = result;
 8229  C_word ab[2][C_SIZEOF_CPLXNUM + C_SIZEOF_RATNUM*2 + C_SIZEOF_BIGNUM(2) * 4], *a;
 8230
 8231  c -= 2; 
 8232  av += 2;
 8233
 8234  while (c--) {
 8235    next_val = *(av++);
 8236    a = ab[c&1]; /* One may hold prev iteration result, the other is unused */
 8237    result = C_s_a_i_times(&a, 2, result, next_val);
 8238    result = move_buffer_object(&a, ab[(c+1)&1], result);
 8239    clear_buffer_object(ab[(c+1)&1], prev_result);
 8240    prev_result = result;
 8241  }
 8242
 8243  C_kontinue(k, result);
 8244}
 8245
 8246
 8247static C_word bignum_plus_unsigned(C_word **ptr, C_word x, C_word y, C_word negp)
 8248{
 8249  C_word size, result;
 8250  C_uword sum, digit, *scan_y, *end_y, *scan_r, *end_r;
 8251  int carry = 0;
 8252
 8253  if (C_bignum_size(y) > C_bignum_size(x)) {  /* Ensure size(y) <= size(x) */
 8254    C_word z = x;
 8255    x = y;
 8256    y = z;
 8257  }
 8258
 8259  size = C_fix(C_bignum_size(x) + 1); /* One more digit, for possible carry. */
 8260  result = C_allocate_scratch_bignum(ptr, size, negp, C_SCHEME_FALSE);
 8261
 8262  scan_y = C_bignum_digits(y);
 8263  end_y = scan_y + C_bignum_size(y);
 8264  scan_r = C_bignum_digits(result);
 8265  end_r = scan_r + C_bignum_size(result);
 8266
 8267  /* Copy x into r so we can operate on two pointers, which is faster
 8268   * than three, and we can stop earlier after adding y.  It's slower
 8269   * if x and y have equal length.  On average it's slightly faster.
 8270   */
 8271  bignum_digits_destructive_copy(result, x);
 8272  *(end_r-1) = 0; /* Ensure most significant digit is initialised */
 8273
 8274  /* Move over x and y simultaneously, destructively adding digits w/ carry. */
 8275  while (scan_y < end_y) {
 8276    digit = *scan_r;
 8277    if (carry) {
 8278      sum = digit + *scan_y++ + 1;
 8279      carry = sum <= digit;
 8280    } else {
 8281      sum = digit + *scan_y++;
 8282      carry = sum < digit;
 8283    }
 8284    (*scan_r++) = sum;
 8285  }
 8286  
 8287  /* The end of y, the smaller number.  Propagate carry into the rest of x. */
 8288  while (carry) {
 8289    sum = (*scan_r) + 1;
 8290    carry = (sum == 0);
 8291    (*scan_r++) = sum;
 8292  }
 8293  assert(scan_r <= end_r);
 8294
 8295  return C_bignum_simplify(result);
 8296}
 8297
 8298static C_word rat_plusmin_integer(C_word **ptr, C_word rat, C_word i, integer_plusmin_op plusmin_op)
 8299{
 8300  C_word ab[C_SIZEOF_FIX_BIGNUM+C_SIZEOF_BIGNUM(2)], *a = ab,
 8301         num, denom, tmp, res;
 8302
 8303  if (i == C_fix(0)) return rat;
 8304
 8305  num = C_u_i_ratnum_num(rat);
 8306  denom = C_u_i_ratnum_denom(rat);
 8307
 8308  /* a/b [+-] c/d = (a*d [+-] b*c)/(b*d) | d = 1: (num + denom * i) / denom */
 8309  tmp = C_s_a_u_i_integer_times(&a, 2, denom, i);
 8310  res = plusmin_op(&a, 2, num, tmp);
 8311  res = move_buffer_object(ptr, ab, res);
 8312  clear_buffer_object(ab, tmp);
 8313  return C_ratnum(ptr, res, denom);
 8314}
 8315
 8316/* This is needed only for minus: plus is commutative but minus isn't. */
 8317static C_word integer_minus_rat(C_word **ptr, C_word i, C_word rat)
 8318{
 8319  C_word ab[C_SIZEOF_FIX_BIGNUM+C_SIZEOF_BIGNUM(2)], *a = ab,
 8320         num, denom, tmp, res;
 8321
 8322  num = C_u_i_ratnum_num(rat);
 8323  denom = C_u_i_ratnum_denom(rat);
 8324
 8325  if (i == C_fix(0))
 8326    return C_ratnum(ptr, C_s_a_u_i_integer_negate(ptr, 1, num), denom);
 8327
 8328  /* a/b - c/d = (a*d - b*c)/(b*d) | b = 1: (denom * i - num) / denom */
 8329  tmp = C_s_a_u_i_integer_times(&a, 2, denom, i);
 8330  res = C_s_a_u_i_integer_minus(&a, 2, tmp, num);
 8331  res = move_buffer_object(ptr, ab, res);
 8332  clear_buffer_object(ab, tmp);
 8333  return C_ratnum(ptr, res, denom);
 8334}
 8335
 8336/* This is pretty braindead and ugly */
 8337static C_word rat_plusmin_rat(C_word **ptr, C_word x, C_word y, integer_plusmin_op plusmin_op)
 8338{
 8339  C_word ab[C_SIZEOF_FIX_BIGNUM*6 + C_SIZEOF_BIGNUM(2)*2], *a = ab,
 8340         xnum = C_u_i_ratnum_num(x), ynum = C_u_i_ratnum_num(y),
 8341         xdenom = C_u_i_ratnum_denom(x), ydenom = C_u_i_ratnum_denom(y),
 8342         xnorm, ynorm, tmp_r, g1, ydenom_g1, xdenom_g1, norm_sum, g2, len,
 8343         res_num, res_denom;
 8344
 8345  /* Knuth, 4.5.1.  Start with g1 = gcd(xdenom, ydenom) */
 8346  g1 = C_s_a_u_i_integer_gcd(&a, 2, xdenom, ydenom);
 8347
 8348  /* xnorm = xnum * (ydenom/g1) */
 8349  ydenom_g1 = C_s_a_u_i_integer_quotient(&a, 2, ydenom, g1);
 8350  xnorm = C_s_a_u_i_integer_times(&a, 2, xnum, ydenom_g1);
 8351
 8352  /* ynorm = ynum * (xdenom/g1) */
 8353  xdenom_g1 = C_s_a_u_i_integer_quotient(&a, 2, xdenom, g1);
 8354  ynorm = C_s_a_u_i_integer_times(&a, 2, ynum, xdenom_g1);
 8355
 8356  /* norm_sum = xnorm [+-] ynorm */
 8357  norm_sum = plusmin_op(&a, 2, xnorm, ynorm);
 8358
 8359  /* g2 = gcd(norm_sum, g1) */
 8360  g2 = C_s_a_u_i_integer_gcd(&a, 2, norm_sum, g1);
 8361
 8362  /* res_num = norm_sum / g2 */
 8363  res_num = C_s_a_u_i_integer_quotient(ptr, 2, norm_sum, g2);
 8364  if (res_num == C_fix(0)) {
 8365    res_denom = C_fix(0); /* No need to calculate denom: we'll return 0 */
 8366  } else {
 8367    /* res_denom = xdenom_g1 * (ydenom / g2) */
 8368    C_word res_tmp_denom = C_s_a_u_i_integer_quotient(&a, 2, ydenom, g2);
 8369    res_denom = C_s_a_u_i_integer_times(ptr, 2, xdenom_g1, res_tmp_denom);
 8370
 8371    /* Ensure they're allocated in the correct place */
 8372    res_num = move_buffer_object(ptr, ab, res_num);
 8373    res_denom = move_buffer_object(ptr, ab, res_denom);
 8374    clear_buffer_object(ab, res_tmp_denom);
 8375  }
 8376
 8377  clear_buffer_object(ab, xdenom_g1);
 8378  clear_buffer_object(ab, ydenom_g1);
 8379  clear_buffer_object(ab, xnorm);
 8380  clear_buffer_object(ab, ynorm);
 8381  clear_buffer_object(ab, norm_sum);
 8382  clear_buffer_object(ab, g1);
 8383  clear_buffer_object(ab, g2);
 8384
 8385  switch (res_denom) {
 8386  case C_fix(0): return C_fix(0);
 8387  case C_fix(1): return res_num;
 8388  default: return C_ratnum(ptr, res_num, res_denom);
 8389  }
 8390}
 8391
 8392/* The maximum size this needs is that required to store a complex
 8393 * number result, where both real and imag parts consist of ratnums.
 8394 * The maximum size of those ratnums is if they consist of two "fix
 8395 * bignums", so we're looking at C_SIZEOF_CPLXNUM + C_SIZEOF_RATNUM *
 8396 * 2 + C_SIZEOF_FIX_BIGNUM * 4 = 29 words!
 8397 */
 8398C_regparm C_word C_fcall
 8399C_s_a_i_plus(C_word **ptr, C_word n, C_word x, C_word y)
 8400{
 8401  if (x & C_FIXNUM_BIT) {
 8402    if (y & C_FIXNUM_BIT) {
 8403      return C_a_i_fixnum_plus(ptr, 2, x, y);
 8404    } else if (C_immediatep(y)) {
 8405      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", y);
 8406    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8407      return C_flonum(ptr, (double)C_unfix(x) + C_flonum_magnitude(y));
 8408    } else if (C_truep(C_bignump(y))) {
 8409      return C_s_a_u_i_integer_plus(ptr, 2, x, y);
 8410    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8411      return rat_plusmin_integer(ptr, y, x, C_s_a_u_i_integer_plus);
 8412    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8413      C_word real_sum = C_s_a_i_plus(ptr, 2, x, C_u_i_cplxnum_real(y)),
 8414             imag = C_u_i_cplxnum_imag(y);
 8415      if (C_truep(C_u_i_inexactp(real_sum)))
 8416        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8417      return C_cplxnum(ptr, real_sum, imag);
 8418    } else {
 8419      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", y);
 8420    }
 8421  } else if (C_immediatep(x)) {
 8422    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", x);
 8423  } else if (C_block_header(x) == C_FLONUM_TAG) {
 8424    if (y & C_FIXNUM_BIT) {
 8425      return C_flonum(ptr, C_flonum_magnitude(x) + (double)C_unfix(y));
 8426    } else if (C_immediatep(y)) {
 8427      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", y);
 8428    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8429      return C_a_i_flonum_plus(ptr, 2, x, y);
 8430    } else if (C_truep(C_bignump(y))) {
 8431      return C_flonum(ptr, C_flonum_magnitude(x)+C_bignum_to_double(y));
 8432    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8433      return C_s_a_i_plus(ptr, 2, x, C_a_i_exact_to_inexact(ptr, 1, y));
 8434    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8435      C_word real_sum = C_s_a_i_plus(ptr, 2, x, C_u_i_cplxnum_real(y)),
 8436             imag = C_u_i_cplxnum_imag(y);
 8437      if (C_truep(C_u_i_inexactp(real_sum)))
 8438        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8439      return C_cplxnum(ptr, real_sum, imag);
 8440    } else {
 8441      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", y);
 8442    }
 8443  } else if (C_truep(C_bignump(x))) {
 8444    if (y & C_FIXNUM_BIT) {
 8445      return C_s_a_u_i_integer_plus(ptr, 2, x, y);
 8446    } else if (C_immediatep(y)) {
 8447      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", y);
 8448    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8449      return C_flonum(ptr, C_bignum_to_double(x)+C_flonum_magnitude(y));
 8450    } else if (C_truep(C_bignump(y))) {
 8451      return C_s_a_u_i_integer_plus(ptr, 2, x, y);
 8452    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8453      return rat_plusmin_integer(ptr, y, x, C_s_a_u_i_integer_plus);
 8454    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8455      C_word real_sum = C_s_a_i_plus(ptr, 2, x, C_u_i_cplxnum_real(y)),
 8456             imag = C_u_i_cplxnum_imag(y);
 8457      if (C_truep(C_u_i_inexactp(real_sum)))
 8458        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8459      return C_cplxnum(ptr, real_sum, imag);
 8460    } else {
 8461      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", y);
 8462    }
 8463  } else if (C_block_header(x) == C_RATNUM_TAG) {
 8464    if (y & C_FIXNUM_BIT) {
 8465      return rat_plusmin_integer(ptr, x, y, C_s_a_u_i_integer_plus);
 8466    } else if (C_immediatep(y)) {
 8467      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", y);
 8468    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8469      return C_s_a_i_plus(ptr, 2, C_a_i_exact_to_inexact(ptr, 1, x), y);
 8470    } else if (C_truep(C_bignump(y))) {
 8471      return rat_plusmin_integer(ptr, x, y, C_s_a_u_i_integer_plus);
 8472    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8473      return rat_plusmin_rat(ptr, x, y, C_s_a_u_i_integer_plus);
 8474    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8475      C_word real_sum = C_s_a_i_plus(ptr, 2, x, C_u_i_cplxnum_real(y)),
 8476             imag = C_u_i_cplxnum_imag(y);
 8477      if (C_truep(C_u_i_inexactp(real_sum)))
 8478        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8479      return C_cplxnum(ptr, real_sum, imag);
 8480    } else {
 8481      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", y);
 8482    }
 8483  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 8484    if (!C_immediatep(y) && C_block_header(y) == C_CPLXNUM_TAG) {
 8485      C_word real_sum, imag_sum;
 8486      real_sum = C_s_a_i_plus(ptr, 2, C_u_i_cplxnum_real(x), C_u_i_cplxnum_real(y));
 8487      imag_sum = C_s_a_i_plus(ptr, 2, C_u_i_cplxnum_imag(x), C_u_i_cplxnum_imag(y));
 8488      if (C_truep(C_u_i_zerop2(imag_sum))) return real_sum;
 8489      else return C_cplxnum(ptr, real_sum, imag_sum);
 8490    } else {
 8491      C_word real_sum = C_s_a_i_plus(ptr, 2, C_u_i_cplxnum_real(x), y),
 8492             imag = C_u_i_cplxnum_imag(x);
 8493      if (C_truep(C_u_i_inexactp(real_sum)))
 8494        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8495      return C_cplxnum(ptr, real_sum, imag);
 8496    }
 8497  } else {
 8498    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", x);
 8499  }
 8500}
 8501
 8502C_regparm C_word C_fcall
 8503C_s_a_u_i_integer_plus(C_word **ptr, C_word n, C_word x, C_word y)
 8504{
 8505  if ((x & y) & C_FIXNUM_BIT) {
 8506    return C_a_i_fixnum_plus(ptr, 2, x, y);
 8507  } else {
 8508    C_word ab[C_SIZEOF_FIX_BIGNUM * 2 + C_SIZEOF_BIGNUM_WRAPPER], *a = ab;
 8509    if (x & C_FIXNUM_BIT) x = C_a_u_i_fix_to_big(&a, x);
 8510    if (y & C_FIXNUM_BIT) y = C_a_u_i_fix_to_big(&a, y);
 8511
 8512    if (C_bignum_negativep(x)) {
 8513      if (C_bignum_negativep(y)) {
 8514        return bignum_plus_unsigned(ptr, x, y, C_SCHEME_TRUE);
 8515      } else {
 8516        return bignum_minus_unsigned(ptr, y, x);
 8517      }
 8518    } else {
 8519      if (C_bignum_negativep(y)) {
 8520        return bignum_minus_unsigned(ptr, x, y);
 8521      } else {
 8522        return bignum_plus_unsigned(ptr, x, y, C_SCHEME_FALSE);
 8523      }
 8524    }
 8525  }
 8526}
 8527
 8528void C_ccall C_plus(C_word c, C_word *av)
 8529{
 8530  /* C_word closure = av[ 0 ]; */
 8531  C_word k = av[ 1 ];
 8532  C_word next_val,
 8533    result = C_fix(0),
 8534    prev_result = result;
 8535  C_word ab[2][C_SIZEOF_CPLXNUM + C_SIZEOF_RATNUM*2 + C_SIZEOF_FIX_BIGNUM * 4], *a;
 8536
 8537  c -= 2; 
 8538  av += 2;
 8539
 8540  while (c--) {
 8541    next_val = *(av++);
 8542    a = ab[c&1]; /* One may hold last iteration result, the other is unused */
 8543    result = C_s_a_i_plus(&a, 2, result, next_val);
 8544    result = move_buffer_object(&a, ab[(c+1)&1], result);
 8545    clear_buffer_object(ab[(c+1)&1], prev_result);
 8546    prev_result = result;
 8547  }
 8548
 8549  C_kontinue(k, result);
 8550}
 8551
 8552static C_word bignum_minus_unsigned(C_word **ptr, C_word x, C_word y)
 8553{
 8554  C_word res, size;
 8555  C_uword *scan_r, *end_r, *scan_y, *end_y, difference, digit;
 8556  int borrow = 0;
 8557
 8558  switch(bignum_cmp_unsigned(x, y)) {
 8559  case 0:	      /* x = y, return 0 */
 8560    return C_fix(0);
 8561  case -1:	      /* abs(x) < abs(y), return -(abs(y) - abs(x)) */
 8562    size = C_fix(C_bignum_size(y)); /* Maximum size of result is length of y. */
 8563    res = C_allocate_scratch_bignum(ptr, size, C_SCHEME_TRUE, C_SCHEME_FALSE);
 8564    size = y;
 8565    y = x;
 8566    x = size;
 8567    break;
 8568  case 1:	      /* abs(x) > abs(y), return abs(x) - abs(y) */
 8569  default:
 8570    size = C_fix(C_bignum_size(x)); /* Maximum size of result is length of x. */
 8571    res = C_allocate_scratch_bignum(ptr, size, C_SCHEME_FALSE, C_SCHEME_FALSE);
 8572    break;
 8573  }
 8574
 8575  scan_r = C_bignum_digits(res);
 8576  end_r = scan_r + C_bignum_size(res);
 8577  scan_y = C_bignum_digits(y);
 8578  end_y = scan_y + C_bignum_size(y);
 8579
 8580  bignum_digits_destructive_copy(res, x); /* See bignum_plus_unsigned */
 8581
 8582  /* Destructively subtract y's digits w/ borrow from and back into r. */
 8583  while (scan_y < end_y) {
 8584    digit = *scan_r;
 8585    if (borrow) {
 8586      difference = digit - *scan_y++ - 1;
 8587      borrow = difference >= digit;
 8588    } else {
 8589      difference = digit - *scan_y++;
 8590      borrow = difference > digit;
 8591    }
 8592    (*scan_r++) = difference;
 8593  }
 8594
 8595  /* The end of y, the smaller number.  Propagate borrow into the rest of x. */
 8596  while (borrow) {
 8597    digit = *scan_r;
 8598    difference = digit - borrow;
 8599    borrow = difference >= digit;
 8600    (*scan_r++) = difference;
 8601  }
 8602
 8603  assert(scan_r <= end_r);
 8604
 8605  return C_bignum_simplify(res);
 8606}
 8607
 8608/* Like C_s_a_i_plus, this needs at most 29 words */
 8609C_regparm C_word C_fcall
 8610C_s_a_i_minus(C_word **ptr, C_word n, C_word x, C_word y)
 8611{
 8612  if (x & C_FIXNUM_BIT) {
 8613    if (y & C_FIXNUM_BIT) {
 8614      return C_a_i_fixnum_difference(ptr, 2, x, y);
 8615    } else if (C_immediatep(y)) {
 8616      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", y);
 8617    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8618      return C_flonum(ptr, (double)C_unfix(x) - C_flonum_magnitude(y));
 8619    } else if (C_truep(C_bignump(y))) {
 8620      return C_s_a_u_i_integer_minus(ptr, 2, x, y);
 8621    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8622      return integer_minus_rat(ptr, x, y);
 8623    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8624      C_word real_diff = C_s_a_i_minus(ptr, 2, x, C_u_i_cplxnum_real(y)),
 8625             imag = C_s_a_i_negate(ptr, 1, C_u_i_cplxnum_imag(y));
 8626      if (C_truep(C_u_i_inexactp(real_diff)))
 8627        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8628      return C_cplxnum(ptr, real_diff, imag);
 8629    } else {
 8630      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", y);
 8631    }
 8632  } else if (C_immediatep(x)) {
 8633    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", x);
 8634  } else if (C_block_header(x) == C_FLONUM_TAG) {
 8635    if (y & C_FIXNUM_BIT) {
 8636      return C_flonum(ptr, C_flonum_magnitude(x) - (double)C_unfix(y));
 8637    } else if (C_immediatep(y)) {
 8638      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", y);
 8639    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8640      return C_a_i_flonum_difference(ptr, 2, x, y);
 8641    } else if (C_truep(C_bignump(y))) {
 8642      return C_flonum(ptr, C_flonum_magnitude(x)-C_bignum_to_double(y));
 8643    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8644      return C_s_a_i_minus(ptr, 2, x, C_a_i_exact_to_inexact(ptr, 1, y));
 8645    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8646      C_word real_diff = C_s_a_i_minus(ptr, 2, x, C_u_i_cplxnum_real(y)),
 8647             imag = C_s_a_i_negate(ptr, 1, C_u_i_cplxnum_imag(y));
 8648      if (C_truep(C_u_i_inexactp(real_diff)))
 8649        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8650      return C_cplxnum(ptr, real_diff, imag);
 8651    } else {
 8652      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", y);
 8653    }
 8654  } else if (C_truep(C_bignump(x))) {
 8655    if (y & C_FIXNUM_BIT) {
 8656      return C_s_a_u_i_integer_minus(ptr, 2, x, y);
 8657    } else if (C_immediatep(y)) {
 8658      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", y);
 8659    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8660      return C_flonum(ptr, C_bignum_to_double(x)-C_flonum_magnitude(y));
 8661    } else if (C_truep(C_bignump(y))) {
 8662      return C_s_a_u_i_integer_minus(ptr, 2, x, y);
 8663    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8664      return integer_minus_rat(ptr, x, y);
 8665    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8666      C_word real_diff = C_s_a_i_minus(ptr, 2, x, C_u_i_cplxnum_real(y)),
 8667             imag = C_s_a_i_negate(ptr, 1, C_u_i_cplxnum_imag(y));
 8668      if (C_truep(C_u_i_inexactp(real_diff)))
 8669        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8670      return C_cplxnum(ptr, real_diff, imag);
 8671    } else {
 8672      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", y);
 8673    }
 8674  } else if (C_block_header(x) == C_RATNUM_TAG) {
 8675    if (y & C_FIXNUM_BIT) {
 8676      return rat_plusmin_integer(ptr, x, y, C_s_a_u_i_integer_minus);
 8677    } else if (C_immediatep(y)) {
 8678      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", y);
 8679    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8680      return C_s_a_i_minus(ptr, 2, C_a_i_exact_to_inexact(ptr, 1, x), y);
 8681    } else if (C_truep(C_bignump(y))) {
 8682      return rat_plusmin_integer(ptr, x, y, C_s_a_u_i_integer_minus);
 8683    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8684      return rat_plusmin_rat(ptr, x, y, C_s_a_u_i_integer_minus);
 8685    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8686      C_word real_diff = C_s_a_i_minus(ptr, 2, x, C_u_i_cplxnum_real(y)),
 8687             imag = C_s_a_i_negate(ptr, 1, C_u_i_cplxnum_imag(y));
 8688      if (C_truep(C_u_i_inexactp(real_diff)))
 8689        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8690      return C_cplxnum(ptr, real_diff, imag);
 8691    } else {
 8692      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", y);
 8693    }
 8694  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 8695    if (!C_immediatep(y) && C_block_header(y) == C_CPLXNUM_TAG) {
 8696      C_word real_diff, imag_diff;
 8697      real_diff = C_s_a_i_minus(ptr,2,C_u_i_cplxnum_real(x),C_u_i_cplxnum_real(y));
 8698      imag_diff = C_s_a_i_minus(ptr,2,C_u_i_cplxnum_imag(x),C_u_i_cplxnum_imag(y));
 8699      if (C_truep(C_u_i_zerop2(imag_diff))) return real_diff;
 8700      else return C_cplxnum(ptr, real_diff, imag_diff);
 8701    } else {
 8702      C_word real_diff = C_s_a_i_minus(ptr, 2, C_u_i_cplxnum_real(x), y),
 8703             imag = C_u_i_cplxnum_imag(x);
 8704      if (C_truep(C_u_i_inexactp(real_diff)))
 8705        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8706      return C_cplxnum(ptr, real_diff, imag);
 8707    }
 8708  } else {
 8709    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", x);
 8710  }
 8711}
 8712
 8713C_regparm C_word C_fcall
 8714C_s_a_u_i_integer_minus(C_word **ptr, C_word n, C_word x, C_word y)
 8715{
 8716  if ((x & y) & C_FIXNUM_BIT) {
 8717    return C_a_i_fixnum_difference(ptr, 2, x, y);
 8718  } else {
 8719    C_word ab[C_SIZEOF_FIX_BIGNUM * 2 + C_SIZEOF_BIGNUM_WRAPPER], *a = ab;
 8720    if (x & C_FIXNUM_BIT) x = C_a_u_i_fix_to_big(&a, x);
 8721    if (y & C_FIXNUM_BIT) y = C_a_u_i_fix_to_big(&a, y);
 8722
 8723    if (C_bignum_negativep(x)) {
 8724      if (C_bignum_negativep(y)) {
 8725        return bignum_minus_unsigned(ptr, y, x);
 8726      } else {
 8727        return bignum_plus_unsigned(ptr, x, y, C_SCHEME_TRUE);
 8728      }
 8729    } else {
 8730      if (C_bignum_negativep(y)) {
 8731        return bignum_plus_unsigned(ptr, x, y, C_SCHEME_FALSE);
 8732      } else {
 8733        return bignum_minus_unsigned(ptr, x, y);
 8734      }
 8735    }
 8736  }
 8737}
 8738
 8739void C_ccall C_minus(C_word c, C_word *av)
 8740{
 8741  /* C_word closure = av[ 0 ]; */
 8742  C_word k = av[ 1 ];
 8743  C_word next_val, result, prev_result;
 8744  C_word ab[2][C_SIZEOF_CPLXNUM + C_SIZEOF_RATNUM*2 + C_SIZEOF_FIX_BIGNUM * 4], *a;
 8745
 8746  if (c < 3) {
 8747    C_bad_min_argc(c, 3);
 8748  } else if (c == 3) {
 8749    a = ab[0];
 8750    C_kontinue(k, C_s_a_i_negate(&a, 1, av[ 2 ]));
 8751  } else {
 8752    prev_result = result = av[ 2 ];
 8753    c -= 3;
 8754    av += 3;
 8755
 8756    while (c--) {
 8757      next_val = *(av++);
 8758      a = ab[c&1]; /* One may hold last iteration result, the other is unused */
 8759      result = C_s_a_i_minus(&a, 2, result, next_val);
 8760      result = move_buffer_object(&a, ab[(c+1)&1], result);
 8761      clear_buffer_object(ab[(c+1)&1], prev_result);
 8762      prev_result = result;
 8763    }
 8764
 8765    C_kontinue(k, result);
 8766  }
 8767}
 8768
 8769
 8770static C_regparm void
 8771integer_divrem(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r)
 8772{
 8773  if (!(y & C_FIXNUM_BIT)) { /* y is bignum. */
 8774    if (x & C_FIXNUM_BIT) {
 8775      /* abs(x) < abs(y), so it will always be [0, x] except for this case: */
 8776      if (x == C_fix(C_MOST_NEGATIVE_FIXNUM) &&
 8777          C_bignum_negated_fitsinfixnump(y)) {
 8778        if (q != NULL) *q = C_fix(-1);
 8779        if (r != NULL) *r = C_fix(0);
 8780      } else {
 8781        if (q != NULL) *q = C_fix(0);
 8782        if (r != NULL) *r = x;
 8783      }
 8784    } else {
 8785      bignum_divrem(ptr, x, y, q, r);
 8786    }
 8787  } else if (x & C_FIXNUM_BIT) { /* both x and y are fixnum. */
 8788    if (q != NULL) *q = C_a_i_fixnum_quotient_checked(ptr, 2, x, y);
 8789    if (r != NULL) *r = C_i_fixnum_remainder_checked(x, y);
 8790  } else { /* x is bignum, y is fixnum. */
 8791    C_word absy = (y & C_INT_SIGN_BIT) ? -C_unfix(y) : C_unfix(y);
 8792
 8793    if (y == C_fix(1)) {
 8794      if (q != NULL) *q = x;
 8795      if (r != NULL) *r = C_fix(0);
 8796    } else if (y == C_fix(-1)) {
 8797      if (q != NULL) *q = C_s_a_u_i_integer_negate(ptr, 1, x);
 8798      if (r != NULL) *r = C_fix(0);
 8799    } else if (C_fitsinbignumhalfdigitp(absy) ||
 8800               ((((C_uword)1 << (C_ilen(absy)-1)) == absy) &&
 8801                C_fitsinfixnump(absy))) {
 8802      assert(y != C_fix(0)); /* _must_ be checked by caller */
 8803      if (q != NULL) {
 8804        bignum_destructive_divide_unsigned_small(ptr, x, y, q, r);
 8805      } else { /* We assume r isn't NULL here (that makes no sense) */
 8806        C_word rem;
 8807	C_uword next_power = (C_uword)1 << (C_ilen(absy)-1);
 8808
 8809	if (next_power == absy) { /* Is absy a power of two? */
 8810          rem = *(C_bignum_digits(x)) & (next_power - 1);
 8811        } else { /* Too bad, we have to do some real work */
 8812          rem = bignum_remainder_unsigned_halfdigit(x, absy);
 8813	}
 8814        *r = C_bignum_negativep(x) ? C_fix(-rem) : C_fix(rem);
 8815      }
 8816    } else {			/* Just divide it as two bignums */
 8817      C_word ab[C_SIZEOF_FIX_BIGNUM], *a = ab;
 8818      bignum_divrem(ptr, x, C_a_u_i_fix_to_big(&a, y), q, r);
 8819      if (q != NULL) *q = move_buffer_object(ptr, ab, *q);
 8820      if (r != NULL) *r = move_buffer_object(ptr, ab, *r);
 8821    }
 8822  }
 8823}
 8824
 8825/* This _always_ needs two bignum wrappers in ptr! */
 8826static C_regparm void
 8827bignum_divrem(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r)
 8828{
 8829  C_word q_negp = C_mk_bool(C_bignum_negativep(y) != C_bignum_negativep(x)),
 8830         r_negp = C_mk_bool(C_bignum_negativep(x)), res, size;
 8831
 8832  switch(bignum_cmp_unsigned(x, y)) {
 8833  case 0:
 8834    if (q != NULL) *q = C_truep(q_negp) ? C_fix(-1) : C_fix(1);
 8835    if (r != NULL) *r = C_fix(0);
 8836    break;
 8837  case -1:
 8838    if (q != NULL) *q = C_fix(0);
 8839    if (r != NULL) *r = x;
 8840    break;
 8841  case 1:
 8842  default:
 8843    res = C_SCHEME_FALSE;
 8844    size = C_bignum_size(x) - C_bignum_size(y);
 8845    if (C_bignum_size(y) > C_BURNIKEL_ZIEGLER_THRESHOLD &&
 8846        size > C_BURNIKEL_ZIEGLER_THRESHOLD) {
 8847      res = bignum_divide_burnikel_ziegler(ptr, x, y, q, r);
 8848    }
 8849
 8850    if (!C_truep(res)) {
 8851      bignum_divide_unsigned(ptr, x, y, q, q_negp, r, r_negp);
 8852      if (q != NULL) *q = C_bignum_simplify(*q);
 8853      if (r != NULL) *r = C_bignum_simplify(*r);
 8854    }
 8855    break;
 8856  }
 8857}
 8858
 8859/* Burnikel-Ziegler recursive division: Split high number (x) in three
 8860 * or four parts and divide by the lowest number (y), split in two
 8861 * parts.  There are descriptions in [MpNT, 4.2], [MCA, 1.4.3] and the
 8862 * paper "Fast Recursive Division" by Christoph Burnikel & Joachim
 8863 * Ziegler is freely available.  There is also a description in Karl
 8864 * Hasselstrom's thesis "Fast Division of Integers".
 8865 *
 8866 * The complexity of this is supposedly O(r*s^{log(3)-1} + r*log(s)),
 8867 * where s is the length of x, and r is the length of y (in digits).
 8868 *
 8869 * TODO: See if it's worthwhile to implement "division without remainder"
 8870 * from the Burnikel-Ziegler paper.
 8871 */
 8872static C_regparm C_word
 8873bignum_divide_burnikel_ziegler(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r)
 8874{
 8875  C_word ab[C_SIZEOF_FIX_BIGNUM*9], *a = ab,
 8876         lab[2][C_SIZEOF_FIX_BIGNUM*10], *la,
 8877         q_negp = (C_bignum_negativep(y) ? C_mk_nbool(C_bignum_negativep(x)) :
 8878                   C_mk_bool(C_bignum_negativep(x))),
 8879         r_negp = C_mk_bool(C_bignum_negativep(x)), s, m, n, i, j, l, shift,
 8880         yhi, ylo, zi, zi_orig, newx, newy, quot, qi, ri;
 8881
 8882  /* Ran out of stack?  Fall back to non-recursive division */
 8883  C_stack_check1(return C_SCHEME_FALSE);
 8884
 8885  x = C_s_a_u_i_integer_abs(&a, 1, x);
 8886  y = C_s_a_u_i_integer_abs(&a, 1, y);
 8887
 8888  /* Define m as min{2^k|(2^k)*BURNIKEL_ZIEGLER_DIFF_THRESHOLD > s}
 8889   * This ensures we shift as little as possible (less pressure
 8890   * on the GC) while maintaining a power of two until we drop
 8891   * below the threshold, so we can always split N in half.
 8892   */
 8893  s = C_bignum_size(y);
 8894  m = 1 << C_ilen(s / C_BURNIKEL_ZIEGLER_THRESHOLD);
 8895  j = (s+m-1) / m;              /* j = s/m, rounded up */
 8896  n = j * m;
 8897
 8898  shift = (C_BIGNUM_DIGIT_LENGTH * n) - integer_length_abs(y);
 8899  newx = C_s_a_i_arithmetic_shift(&a, 2, x, C_fix(shift));
 8900  newy = C_s_a_i_arithmetic_shift(&a, 2, y, C_fix(shift));
 8901  if (shift != 0) {
 8902    clear_buffer_object(ab, x);
 8903    clear_buffer_object(ab, y);
 8904  }
 8905  x = newx;
 8906  y = newy;
 8907
 8908  /* l needs to be the smallest value so that a < base^{l*n}/2 */
 8909  l = (C_bignum_size(x) + n) / n;
 8910  if ((C_BIGNUM_DIGIT_LENGTH * l) == integer_length_abs(x)) l++;
 8911  l = nmax(l, 2);
 8912
 8913  yhi = bignum_extract_digits(&a, 3, y, C_fix(n >> 1), C_SCHEME_FALSE);
 8914  ylo = bignum_extract_digits(&a, 3, y, C_fix(0), C_fix(n >> 1));
 8915
 8916  s = (l - 2) * n * C_BIGNUM_DIGIT_LENGTH;
 8917  zi_orig = zi = C_s_a_i_arithmetic_shift(&a, 2, x, C_fix(-s));
 8918  quot = C_fix(0);
 8919
 8920  for(i = l - 2; i >= 0; --i) {
 8921    la = lab[i&1];
 8922
 8923    burnikel_ziegler_2n_div_1n(&la, zi, y, yhi, ylo, C_fix(n), &qi, &ri);
 8924
 8925    newx = C_s_a_i_arithmetic_shift(&la, 2, quot, C_fix(n*C_BIGNUM_DIGIT_LENGTH));
 8926    clear_buffer_object(lab, quot);
 8927    quot = C_s_a_u_i_integer_plus(&la, 2, newx, qi);
 8928    move_buffer_object(&la, lab[(i+1)&1], quot);
 8929    clear_buffer_object(lab, newx);
 8930    clear_buffer_object(lab, qi);
 8931
 8932    if (i > 0) {  /* Set z_{i-1} = [r{i}, x{i-1}] */
 8933      newx = bignum_extract_digits(&la, 3, x, C_fix(n * (i-1)), C_fix(n * i));
 8934      newy = C_s_a_i_arithmetic_shift(&la, 2, ri, C_fix(n*C_BIGNUM_DIGIT_LENGTH));
 8935      clear_buffer_object(lab, zi);
 8936      zi = C_s_a_u_i_integer_plus(&la, 2, newx, newy);
 8937      move_buffer_object(&la, lab[(i+1)&1], zi);
 8938      move_buffer_object(&la, lab[(i+1)&1], quot);
 8939      clear_buffer_object(lab, newx);
 8940      clear_buffer_object(lab, newy);
 8941      clear_buffer_object(lab, ri);
 8942    }
 8943  }
 8944  clear_buffer_object(ab, x);
 8945  clear_buffer_object(ab, y);
 8946  clear_buffer_object(ab, yhi);
 8947  clear_buffer_object(ab, ylo);
 8948  clear_buffer_object(ab, zi_orig);
 8949  clear_buffer_object(lab, zi);
 8950
 8951  if (q != NULL) {
 8952    if (C_truep(q_negp)) {
 8953      newx = C_s_a_u_i_integer_negate(&la, 1, quot);
 8954      clear_buffer_object(lab, quot);
 8955      quot = newx;
 8956    }
 8957    *q = move_buffer_object(ptr, lab, quot);
 8958  }
 8959  clear_buffer_object(lab, quot);
 8960
 8961  if (r != NULL) {
 8962    newx = C_s_a_i_arithmetic_shift(&la, 2, ri, C_fix(-shift));
 8963    if (C_truep(r_negp)) {
 8964      newy = C_s_a_u_i_integer_negate(ptr, 1, newx);
 8965      clear_buffer_object(lab, newx);
 8966      newx = newy;
 8967    }
 8968    *r = move_buffer_object(ptr, lab, newx);
 8969  }
 8970  clear_buffer_object(lab, ri);
 8971
 8972  return C_SCHEME_TRUE;
 8973}
 8974
 8975static C_regparm void
 8976burnikel_ziegler_3n_div_2n(C_word **ptr, C_word a12, C_word a3, C_word b, C_word b1, C_word b2, C_word n, C_word *q, C_word *r)
 8977{
 8978  C_word kab[C_SIZEOF_FIX_BIGNUM*6 + C_SIZEOF_BIGNUM(2)], *ka = kab,
 8979         lab[2][C_SIZEOF_FIX_BIGNUM*4], *la,
 8980         size, tmp, less, qhat, rhat, r1, r1a3, i = 0;
 8981
 8982  size = C_unfix(n) * C_BIGNUM_DIGIT_LENGTH;
 8983  tmp = C_s_a_i_arithmetic_shift(&ka, 2, a12, C_fix(-size));
 8984  less = C_i_integer_lessp(tmp, b1); /* a1 < b1 ? */
 8985  clear_buffer_object(kab, tmp);
 8986
 8987  if (C_truep(less)) {
 8988    C_word atmpb[C_SIZEOF_FIX_BIGNUM*2], *atmp = atmpb, b11, b12, halfn;
 8989
 8990    halfn = C_fix(C_unfix(n) >> 1);
 8991    b11 = bignum_extract_digits(&atmp, 3, b1, halfn, C_SCHEME_FALSE);
 8992    b12 = bignum_extract_digits(&atmp, 3, b1, C_fix(0), halfn);
 8993
 8994    burnikel_ziegler_2n_div_1n(&ka, a12, b1, b11, b12, n, &qhat, &r1);
 8995    qhat = move_buffer_object(&ka, atmpb, qhat);
 8996    r1 = move_buffer_object(&ka, atmpb, r1);
 8997
 8998    clear_buffer_object(atmpb, b11);
 8999    clear_buffer_object(atmpb, b12);
 9000  } else {
 9001    C_word atmpb[C_SIZEOF_FIX_BIGNUM*5], *atmp = atmpb, tmp2;
 9002
 9003    tmp = C_s_a_i_arithmetic_shift(&atmp, 2, C_fix(1), C_fix(size));
 9004    qhat = C_s_a_u_i_integer_minus(&ka, 2, tmp, C_fix(1));  /* B^n - 1 */
 9005    qhat = move_buffer_object(&ka, atmpb, qhat);
 9006    clear_buffer_object(atmpb, tmp);
 9007
 9008    /* r1 = (a12 - b1*B^n) + b1 */
 9009    tmp = C_s_a_i_arithmetic_shift(&atmp, 2, b1, C_fix(size));
 9010    tmp2 = C_s_a_u_i_integer_minus(&atmp, 2, a12, tmp);
 9011    r1 = C_s_a_u_i_integer_plus(&ka, 2, tmp2, b1);
 9012    r1 = move_buffer_object(&ka, atmpb, r1);
 9013    clear_buffer_object(atmpb, tmp);
 9014    clear_buffer_object(atmpb, tmp2);
 9015  }
 9016
 9017  tmp = C_s_a_i_arithmetic_shift(&ka, 2, r1, C_fix(size));
 9018  clear_buffer_object(kab, r1);
 9019  r1a3 = C_s_a_u_i_integer_plus(&ka, 2, tmp, a3);
 9020  b2 = C_s_a_u_i_integer_times(&ka, 2, qhat, b2);
 9021
 9022  la = lab[0];
 9023  rhat = C_s_a_u_i_integer_minus(&la, 2, r1a3, b2);
 9024  rhat = move_buffer_object(&la, kab, rhat);
 9025  qhat = move_buffer_object(&la, kab, qhat);
 9026
 9027  clear_buffer_object(kab, tmp);
 9028  clear_buffer_object(kab, r1a3);
 9029  clear_buffer_object(kab, b2);
 9030
 9031  while(C_truep(C_i_negativep(rhat))) {
 9032    la = lab[(++i)&1];
 9033    /* rhat += b */
 9034    r1 = C_s_a_u_i_integer_plus(&la, 2, rhat, b);
 9035    tmp = move_buffer_object(&la, lab[(i-1)&1], r1);
 9036    clear_buffer_object(lab[(i-1)&1], r1);
 9037    clear_buffer_object(lab[(i-1)&1], rhat);
 9038    clear_buffer_object(kab, rhat);
 9039    rhat = tmp;
 9040
 9041    /* qhat -= 1 */
 9042    r1 = C_s_a_u_i_integer_minus(&la, 2, qhat, C_fix(1));
 9043    tmp = move_buffer_object(&la, lab[(i-1)&1], r1);
 9044    clear_buffer_object(lab[(i-1)&1], r1);
 9045    clear_buffer_object(lab[(i-1)&1], qhat);
 9046    clear_buffer_object(kab, qhat);
 9047    qhat = tmp;
 9048  }
 9049
 9050  if (q != NULL) *q = move_buffer_object(ptr, lab, qhat);
 9051  if (r != NULL) *r = move_buffer_object(ptr, lab, rhat);
 9052  clear_buffer_object(lab, qhat);
 9053  clear_buffer_object(lab, rhat);
 9054}
 9055
 9056static C_regparm void
 9057burnikel_ziegler_2n_div_1n(C_word **ptr, C_word a, C_word b, C_word b1, C_word b2, C_word n, C_word *q, C_word *r)
 9058{
 9059  C_word kab[2][C_SIZEOF_FIX_BIGNUM*7], *ka, a12, a3, a4,
 9060         q1 = C_fix(0), r1, q2 = C_fix(0), r2, *qp;
 9061  int stack_full = 0;
 9062
 9063  C_stack_check1(stack_full = 1);
 9064
 9065  n = C_unfix(n);
 9066  if (stack_full || (n & 1) || (n < C_BURNIKEL_ZIEGLER_THRESHOLD)) {
 9067    integer_divrem(ptr, a, b, q, r);
 9068  } else {
 9069    ka = kab[0];
 9070    a12 = bignum_extract_digits(&ka, 3, a, C_fix(n), C_SCHEME_FALSE);
 9071    a3 = bignum_extract_digits(&ka, 3, a, C_fix(n >> 1), C_fix(n));
 9072
 9073    qp = (q == NULL) ? NULL : &q1;
 9074    ka = kab[1];
 9075    burnikel_ziegler_3n_div_2n(&ka, a12, a3, b, b1, b2, C_fix(n >> 1), qp, &r1);
 9076    q1 = move_buffer_object(&ka, kab[0], q1);
 9077    r1 = move_buffer_object(&ka, kab[0], r1);
 9078    clear_buffer_object(kab[0], a12);
 9079    clear_buffer_object(kab[0], a3);
 9080
 9081    a4 = bignum_extract_digits(&ka, 3, a, C_fix(0), C_fix(n >> 1));
 9082
 9083    qp = (q == NULL) ? NULL : &q2;
 9084    ka = kab[0];
 9085    burnikel_ziegler_3n_div_2n(&ka, r1, a4, b, b1, b2, C_fix(n >> 1), qp, r);
 9086    if (r != NULL) *r = move_buffer_object(ptr, kab[0], *r);
 9087    clear_buffer_object(kab[1], r1);
 9088
 9089    if (q != NULL) {
 9090      C_word halfn_bits = (n >> 1) * C_BIGNUM_DIGIT_LENGTH;
 9091      r1 = C_s_a_i_arithmetic_shift(&ka, 2, q1, C_fix(halfn_bits));
 9092      *q = C_s_a_i_plus(ptr, 2, r1, q2); /* q = [q1, q2] */
 9093      *q = move_buffer_object(ptr, kab[0], *q);
 9094      clear_buffer_object(kab[0], r1);
 9095      clear_buffer_object(kab[1], q1);
 9096      clear_buffer_object(kab[0], q2);
 9097    }
 9098    clear_buffer_object(kab[1], a4);
 9099  }
 9100}
 9101
 9102
 9103static C_regparm C_word bignum_remainder_unsigned_halfdigit(C_word x, C_word y)
 9104{
 9105  C_uword *start = C_bignum_digits(x),
 9106          *scan = start + C_bignum_size(x),
 9107          rem = 0, two_digits;
 9108
 9109  assert((y > 1) && (C_fitsinbignumhalfdigitp(y)));
 9110  while (start < scan) {
 9111    two_digits = (*--scan);
 9112    rem = C_BIGNUM_DIGIT_COMBINE(rem, C_BIGNUM_DIGIT_HI_HALF(two_digits)) % y;
 9113    rem = C_BIGNUM_DIGIT_COMBINE(rem, C_BIGNUM_DIGIT_LO_HALF(two_digits)) % y;
 9114  }
 9115  return rem;
 9116}
 9117
 9118/* There doesn't seem to be a way to return two values from inline functions */
 9119void C_ccall C_quotient_and_remainder(C_word c, C_word *av)
 9120{
 9121  C_word ab[C_SIZEOF_FIX_BIGNUM*4+C_SIZEOF_FLONUM*2], *a = ab,
 9122    nx = C_SCHEME_FALSE, ny = C_SCHEME_FALSE,
 9123    q, r, k, x, y;
 9124
 9125  if (c != 4) C_bad_argc_2(c, 4, av[ 0 ]);
 9126
 9127  k = av[ 1 ];
 9128  x = av[ 2 ];
 9129  y = av[ 3 ];
 9130
 9131  if (!C_truep(C_i_integerp(x)))
 9132    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "quotient&remainder", x);
 9133  if (!C_truep(C_i_integerp(y)))
 9134    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "quotient&remainder", y);
 9135  if (C_truep(C_i_zerop(y))) C_div_by_zero_error("quotient&remainder");
 9136
 9137  if (C_truep(C_i_flonump(x))) {
 9138    if C_truep(C_i_flonump(y)) {
 9139      double dx = C_flonum_magnitude(x), dy = C_flonum_magnitude(y), tmp;
 9140
 9141      C_modf(dx / dy, &tmp);
 9142      q = C_flonum(&a, tmp);
 9143      r = C_flonum(&a, dx - tmp * dy);
 9144      /* reuse av */
 9145      av[ 0 ] = C_SCHEME_UNDEFINED;
 9146      /* av[ 1 ] = k; */ /* stays the same */
 9147      av[ 2 ] = q;
 9148      av[ 3 ] = r;
 9149      C_values(4, av);
 9150    }
 9151    x = nx = C_s_a_u_i_flo_to_int(&a, 1, x);
 9152  }
 9153  if (C_truep(C_i_flonump(y))) {
 9154    y = ny = C_s_a_u_i_flo_to_int(&a, 1, y);
 9155  }
 9156
 9157  integer_divrem(&a, x, y, &q, &r);
 9158
 9159  if (C_truep(nx) || C_truep(ny)) {
 9160    C_word newq, newr;
 9161    newq = C_a_i_exact_to_inexact(&a, 1, q);
 9162    newr = C_a_i_exact_to_inexact(&a, 1, r);
 9163    clear_buffer_object(ab, q);
 9164    clear_buffer_object(ab, r);
 9165    q = newq;
 9166    r = newr;
 9167
 9168    clear_buffer_object(ab, nx);
 9169    clear_buffer_object(ab, ny);
 9170  }
 9171  /* reuse av */
 9172  av[ 0 ] = C_SCHEME_UNDEFINED;
 9173  /* av[ 1 ] = k; */ /* stays the same */
 9174  av[ 2 ] = q;
 9175  av[ 3 ] = r;
 9176  C_values(4, av);
 9177}
 9178
 9179void C_ccall C_u_integer_quotient_and_remainder(C_word c, C_word *av)
 9180{
 9181  C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, q, r;
 9182
 9183  if (av[ 3 ] == C_fix(0)) C_div_by_zero_error("quotient&remainder");
 9184
 9185  integer_divrem(&a, av[ 2 ], av[ 3 ], &q, &r);
 9186
 9187  /* reuse av */
 9188  av[ 0 ] = C_SCHEME_UNDEFINED;
 9189  /* av[ 1 ] = k; */ /* stays the same */
 9190  av[ 2 ] = q;
 9191  av[ 3 ] = r;
 9192  C_values(4, av);
 9193}
 9194
 9195C_regparm C_word C_fcall
 9196C_s_a_i_remainder(C_word **ptr, C_word n, C_word x, C_word y)
 9197{
 9198  C_word ab[C_SIZEOF_FIX_BIGNUM*4+C_SIZEOF_FLONUM*2], *a = ab, r,
 9199         nx = C_SCHEME_FALSE, ny = C_SCHEME_FALSE;
 9200
 9201  if (!C_truep(C_i_integerp(x)))
 9202    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "remainder", x);
 9203  if (!C_truep(C_i_integerp(y)))
 9204    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "remainder", y);
 9205  if (C_truep(C_i_zerop(y))) C_div_by_zero_error("remainder");
 9206
 9207  if (C_truep(C_i_flonump(x))) {
 9208    if C_truep(C_i_flonump(y)) {
 9209      double dx = C_flonum_magnitude(x), dy = C_flonum_magnitude(y), tmp;
 9210
 9211      C_modf(dx / dy, &tmp);
 9212      return C_flonum(ptr, dx - tmp * dy);
 9213    }
 9214    x = nx = C_s_a_u_i_flo_to_int(&a, 1, x);
 9215  }
 9216  if (C_truep(C_i_flonump(y))) {
 9217    y = ny = C_s_a_u_i_flo_to_int(&a, 1, y);
 9218  }
 9219
 9220  integer_divrem(&a, x, y, NULL, &r);
 9221
 9222  if (C_truep(nx) || C_truep(ny)) {
 9223    C_word newr = C_a_i_exact_to_inexact(ptr, 1, r);
 9224    clear_buffer_object(ab, r);
 9225    r = newr;
 9226
 9227    clear_buffer_object(ab, nx);
 9228    clear_buffer_object(ab, ny);
 9229  }
 9230  return move_buffer_object(ptr, ab, r);
 9231}
 9232
 9233C_regparm C_word C_fcall
 9234C_s_a_u_i_integer_remainder(C_word **ptr, C_word n, C_word x, C_word y)
 9235{
 9236  C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, r;
 9237  if (y == C_fix(0)) C_div_by_zero_error("remainder");
 9238  integer_divrem(&a, x, y, NULL, &r);
 9239  return move_buffer_object(ptr, ab, r);
 9240}
 9241
 9242/* Modulo's sign follows y (whereas remainder's sign follows x) */
 9243C_regparm C_word C_fcall
 9244C_s_a_i_modulo(C_word **ptr, C_word n, C_word x, C_word y)
 9245{
 9246  C_word ab[C_SIZEOF_FIX_BIGNUM], *a = ab, r,
 9247         nx = C_SCHEME_FALSE, ny = C_SCHEME_FALSE;
 9248
 9249  if (!C_truep(C_i_integerp(x)))
 9250    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "modulo", x);
 9251  if (!C_truep(C_i_integerp(y)))
 9252    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "modulo", y);
 9253  if (C_truep(C_i_zerop(y))) C_div_by_zero_error("modulo");
 9254
 9255  if (C_truep(C_i_flonump(x))) {
 9256    if C_truep(C_i_flonump(y)) {
 9257      double dx = C_flonum_magnitude(x), dy = C_flonum_magnitude(y), tmp;
 9258
 9259      C_modf(dx / dy, &tmp);
 9260      tmp = dx - tmp * dy;
 9261      if ((dx > 0.0) != (dy > 0.0) && tmp != 0.0) {
 9262        return C_flonum(ptr, tmp + dy);
 9263      } else {
 9264        return C_flonum(ptr, tmp);
 9265      }
 9266    }
 9267    x = nx = C_s_a_u_i_flo_to_int(&a, 1, x);
 9268  }
 9269  if (C_truep(C_i_flonump(y))) {
 9270    y = ny = C_s_a_u_i_flo_to_int(&a, 1, y);
 9271  }
 9272
 9273  integer_divrem(&a, x, y, NULL, &r);
 9274  if (C_i_positivep(y) != C_i_positivep(r) && r != C_fix(0)) {
 9275    C_word m = C_s_a_i_plus(ptr, 2, r, y);
 9276    m = move_buffer_object(ptr, ab, m);
 9277    clear_buffer_object(ab, r);
 9278    r = m;
 9279  }
 9280
 9281  if (C_truep(nx) || C_truep(ny)) {
 9282    C_word newr = C_a_i_exact_to_inexact(ptr, 1, r);
 9283    clear_buffer_object(ab, r);
 9284    r = newr;
 9285
 9286    clear_buffer_object(ab, nx);
 9287    clear_buffer_object(ab, ny);
 9288  }
 9289
 9290  return move_buffer_object(ptr, ab, r);
 9291}
 9292
 9293C_regparm C_word C_fcall
 9294C_s_a_u_i_integer_modulo(C_word **ptr, C_word n, C_word x, C_word y)
 9295{
 9296  C_word ab[C_SIZEOF_FIX_BIGNUM], *a = ab, r;
 9297  if (y == C_fix(0)) C_div_by_zero_error("modulo");
 9298
 9299  integer_divrem(&a, x, y, NULL, &r);
 9300  if (C_i_positivep(y) != C_i_positivep(r) && r != C_fix(0)) {
 9301    C_word m = C_s_a_u_i_integer_plus(ptr, 2, r, y);
 9302    m = move_buffer_object(ptr, ab, m);
 9303    clear_buffer_object(ab, r);
 9304    r = m;
 9305  }
 9306  return move_buffer_object(ptr, ab, r);
 9307}
 9308
 9309C_regparm C_word C_fcall
 9310C_s_a_i_quotient(C_word **ptr, C_word n, C_word x, C_word y)
 9311{
 9312  C_word ab[C_SIZEOF_FIX_BIGNUM*4+C_SIZEOF_FLONUM*2], *a = ab, q,
 9313         nx = C_SCHEME_FALSE, ny = C_SCHEME_FALSE;
 9314
 9315  if (!C_truep(C_i_integerp(x)))
 9316    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "quotient", x);
 9317  if (!C_truep(C_i_integerp(y)))
 9318    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "quotient", y);
 9319  if (C_truep(C_i_zerop(y))) C_div_by_zero_error("quotient");
 9320
 9321  if (C_truep(C_i_flonump(x))) {
 9322    if C_truep(C_i_flonump(y)) {
 9323      double dx = C_flonum_magnitude(x), dy = C_flonum_magnitude(y), tmp;
 9324
 9325      C_modf(dx / dy, &tmp);
 9326      return C_flonum(ptr, tmp);
 9327    }
 9328    x = nx = C_s_a_u_i_flo_to_int(&a, 1, x);
 9329  }
 9330  if (C_truep(C_i_flonump(y))) {
 9331    y = ny = C_s_a_u_i_flo_to_int(&a, 1, y);
 9332  }
 9333
 9334  integer_divrem(&a, x, y, &q, NULL);
 9335
 9336  if (C_truep(nx) || C_truep(ny)) {
 9337    C_word newq = C_a_i_exact_to_inexact(ptr, 1, q);
 9338    clear_buffer_object(ab, q);
 9339    q = newq;
 9340
 9341    clear_buffer_object(ab, nx);
 9342    clear_buffer_object(ab, ny);
 9343  }
 9344  return move_buffer_object(ptr, ab, q);
 9345}
 9346
 9347C_regparm C_word C_fcall
 9348C_s_a_u_i_integer_quotient(C_word **ptr, C_word n, C_word x, C_word y)
 9349{
 9350  C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, q;
 9351  if (y == C_fix(0)) C_div_by_zero_error("quotient");
 9352  integer_divrem(&a, x, y, &q, NULL);
 9353  return move_buffer_object(ptr, ab, q);
 9354}
 9355
 9356
 9357/* For help understanding this algorithm, see:
 9358   Knuth, Donald E., "The Art of Computer Programming",
 9359   volume 2, "Seminumerical Algorithms"
 9360   section 4.3.1, "Multiple-Precision Arithmetic".
 9361
 9362   [Yeah, that's a nice book but that particular section is not
 9363   helpful at all, which is also pointed out by P. Brinch Hansen's
 9364   "Multiple-Length Division Revisited: A Tour Of The Minefield".
 9365   That's a more down-to-earth step-by-step explanation of the
 9366   algorithm.  Add to this the C implementation in Hacker's Delight
 9367   (section 9-2, p141--142) and you may be able to grok this...
 9368   ...barely, if you're as math-challenged as I am -- sjamaan]
 9369
 9370   This assumes that numerator >= denominator!
 9371*/
 9372static void
 9373bignum_divide_unsigned(C_word **ptr, C_word num, C_word denom, C_word *q, C_word q_negp, C_word *r, C_word r_negp)
 9374{
 9375  C_word quotient = C_SCHEME_UNDEFINED, remainder = C_SCHEME_UNDEFINED,
 9376         return_rem = C_mk_nbool(r == NULL), size;
 9377
 9378  if (q != NULL) {
 9379    size = C_fix(C_bignum_size(num) + 1 - C_bignum_size(denom));
 9380    quotient = C_allocate_scratch_bignum(ptr, size, q_negp, C_SCHEME_FALSE);
 9381  }
 9382
 9383  /* An object is always required to receive the remainder */
 9384  size = C_fix(C_bignum_size(num) + 1);
 9385  remainder = C_allocate_scratch_bignum(ptr, size, r_negp, C_SCHEME_FALSE);
 9386  bignum_destructive_divide_full(num, denom, quotient, remainder, return_rem);
 9387
 9388  /* Simplification must be done by the caller, for consistency */
 9389  if (q != NULL) *q = quotient;
 9390  if (r == NULL) {
 9391    C_mutate_scratch_slot(NULL, C_internal_bignum_vector(remainder));
 9392  } else {
 9393    *r = remainder;
 9394  }
 9395}
 9396
 9397/* Compare two numbers as ratnums.  Either may be rat-, fix- or bignums */
 9398static C_word rat_cmp(C_word x, C_word y)
 9399{
 9400  C_word ab[C_SIZEOF_FIX_BIGNUM*4], *a = ab, x1, x2, y1, y2,
 9401         s, t, ssize, tsize, result, negp;
 9402  C_uword *scan;
 9403
 9404  /* Check for 1 or 0; if x or y is this, the other must be the ratnum */
 9405  if (x == C_fix(0)) {	      /* Only the sign of y1 matters */
 9406    return basic_cmp(x, C_u_i_ratnum_num(y), "ratcmp", 0);
 9407  } else if (x == C_fix(1)) { /* x1*y1 <> x2*y2 --> y2 <> y1 | x1/x2 = 1/1 */
 9408    return basic_cmp(C_u_i_ratnum_denom(y), C_u_i_ratnum_num(y), "ratcmp", 0);
 9409  } else if (y == C_fix(0)) { /* Only the sign of x1 matters */
 9410    return basic_cmp(C_u_i_ratnum_num(x), y, "ratcmp", 0);
 9411  } else if (y == C_fix(1)) { /* x1*y1 <> x2*y2 --> x1 <> x2 | y1/y2 = 1/1 */
 9412    return basic_cmp(C_u_i_ratnum_num(x), C_u_i_ratnum_denom(x), "ratcmp", 0);
 9413  }
 9414
 9415  /* Extract components x=x1/x2 and y=y1/y2 */
 9416  if (x & C_FIXNUM_BIT || C_truep(C_bignump(x))) {
 9417    x1 = x;
 9418    x2 = C_fix(1);
 9419  } else {
 9420    x1 = C_u_i_ratnum_num(x);
 9421    x2 = C_u_i_ratnum_denom(x);
 9422  }
 9423
 9424  if (y & C_FIXNUM_BIT || C_truep(C_bignump(y))) {
 9425    y1 = y;
 9426    y2 = C_fix(1);
 9427  } else {
 9428    y1 = C_u_i_ratnum_num(y);
 9429    y2 = C_u_i_ratnum_denom(y);
 9430  }
 9431
 9432  /* We only want to deal with bignums (this is tricky enough) */
 9433  if (x1 & C_FIXNUM_BIT) x1 = C_a_u_i_fix_to_big(&a, x1);
 9434  if (x2 & C_FIXNUM_BIT) x2 = C_a_u_i_fix_to_big(&a, x2);
 9435  if (y1 & C_FIXNUM_BIT) y1 = C_a_u_i_fix_to_big(&a, y1);
 9436  if (y2 & C_FIXNUM_BIT) y2 = C_a_u_i_fix_to_big(&a, y2);
 9437
 9438  /* We multiply using schoolbook method, so this will be very slow in
 9439   * extreme cases.  This is a tradeoff we make so that comparisons
 9440   * are inlineable, which makes a big difference for the common case.
 9441   */
 9442  ssize = C_bignum_size(x1) + C_bignum_size(y2);
 9443  negp = C_mk_bool(C_bignum_negativep(x1));
 9444  s = allocate_tmp_bignum(C_fix(ssize), negp, C_SCHEME_TRUE);
 9445  bignum_digits_multiply(x1, y2, s); /* Swap args if x1 < y2? */
 9446
 9447  tsize = C_bignum_size(y1) + C_bignum_size(x2);
 9448  negp = C_mk_bool(C_bignum_negativep(y1));
 9449  t = allocate_tmp_bignum(C_fix(tsize), negp, C_SCHEME_TRUE);
 9450  bignum_digits_multiply(y1, x2, t); /* Swap args if y1 < x2? */
 9451
 9452  /* Shorten the numbers if needed */
 9453  for (scan = C_bignum_digits(s)+ssize-1; *scan == 0; scan--) ssize--;
 9454  C_bignum_mutate_size(s, ssize);
 9455  for (scan = C_bignum_digits(t)+tsize-1; *scan == 0; scan--) tsize--;
 9456  C_bignum_mutate_size(t, tsize);
 9457
 9458  result = C_i_bignum_cmp(s, t);
 9459
 9460  free_tmp_bignum(t);
 9461  free_tmp_bignum(s);
 9462  return result;
 9463}
 9464
 9465C_regparm double C_fcall C_bignum_to_double(C_word bignum)
 9466{
 9467  double accumulator = 0;
 9468  C_uword *start = C_bignum_digits(bignum),
 9469          *scan = start + C_bignum_size(bignum);
 9470  while (start < scan) {
 9471    accumulator *= (C_uword)1 << C_BIGNUM_HALF_DIGIT_LENGTH;
 9472    accumulator *= (C_uword)1 << C_BIGNUM_HALF_DIGIT_LENGTH;
 9473    accumulator += (*--scan);
 9474  }
 9475  return(C_bignum_negativep(bignum) ? -accumulator : accumulator);
 9476}
 9477
 9478C_regparm C_word C_fcall
 9479C_s_a_u_i_flo_to_int(C_word **ptr, C_word n, C_word x)
 9480{
 9481  int exponent;
 9482  double significand = frexp(C_flonum_magnitude(x), &exponent);
 9483
 9484  assert(C_truep(C_u_i_fpintegerp(x)));
 9485
 9486  if (exponent <= 0) {
 9487    return C_fix(0);
 9488  } else if (exponent == 1) { /* TODO: check significand * 2^exp fits fixnum? */
 9489    return significand < 0.0 ? C_fix(-1) : C_fix(1);
 9490  } else {
 9491    C_word size, negp = C_mk_bool(C_flonum_magnitude(x) < 0.0), result;
 9492    C_uword *start, *end;
 9493
 9494    size = C_fix(C_BIGNUM_BITS_TO_DIGITS(exponent));
 9495    result = C_allocate_scratch_bignum(ptr, size, negp, C_SCHEME_FALSE);
 9496
 9497    start = C_bignum_digits(result);
 9498    end = start + C_bignum_size(result);
 9499
 9500    fabs_frexp_to_digits(exponent, fabs(significand), start, end);
 9501    return C_bignum_simplify(result);
 9502  }
 9503}
 9504
 9505static void
 9506fabs_frexp_to_digits(C_uword exp, double sign, C_uword *start, C_uword *scan)
 9507{
 9508  C_uword digit, odd_bits = exp % C_BIGNUM_DIGIT_LENGTH;
 9509
 9510  assert(C_isfinite(sign));
 9511  assert(0.5 <= sign && sign < 1); /* Guaranteed by frexp() and fabs() */
 9512  assert((scan - start) == C_BIGNUM_BITS_TO_DIGITS(exp));
 9513  
 9514  if (odd_bits > 0) { /* Handle most significant digit first */
 9515    sign *= (C_uword)1 << odd_bits;
 9516    digit = (C_uword)sign;
 9517    (*--scan) = digit;
 9518    sign -= (double)digit;
 9519  }
 9520
 9521  while (start < scan && sign > 0) {
 9522    sign *= pow(2.0, C_BIGNUM_DIGIT_LENGTH);
 9523    digit = (C_uword)sign;
 9524    (*--scan) = digit;
 9525    sign -= (double)digit;
 9526  }
 9527
 9528  /* Finish up by clearing any remaining, lower, digits */
 9529  while (start < scan)
 9530    (*--scan) = 0;
 9531}
 9532
 9533/* This is a bit weird: We have to compare flonums as bignums due to
 9534 * precision loss on 64-bit platforms.  For simplicity, we convert
 9535 * fixnums to bignums here.
 9536 */
 9537static C_word int_flo_cmp(C_word intnum, C_word flonum)
 9538{
 9539  C_word ab[C_SIZEOF_FIX_BIGNUM + C_SIZEOF_FLONUM], *a = ab, flo_int, res;
 9540  double i, f;
 9541
 9542  f = C_flonum_magnitude(flonum);
 9543
 9544  if (C_isnan(f)) {
 9545    return C_SCHEME_FALSE; /* "mu" */
 9546  } else if (C_isinf(f)) {
 9547    return C_fix((f > 0.0) ? -1 : 1); /* x is smaller if f is +inf.0 */
 9548  } else {
 9549    f = modf(f, &i);
 9550
 9551    flo_int = C_s_a_u_i_flo_to_int(&a, 1, C_flonum(&a, i));
 9552
 9553    res = basic_cmp(intnum, flo_int, "int_flo_cmp", 0);
 9554    clear_buffer_object(ab, flo_int);
 9555
 9556    if (res == C_fix(0)) /* Use fraction to break tie. If f > 0, x is smaller */
 9557      return C_fix((f > 0.0) ? -1 : ((f < 0.0) ? 1 : 0));
 9558    else
 9559      return res;
 9560  }
 9561}
 9562
 9563/* For convenience (ie, to reduce the degree of mindfuck) */
 9564static C_word flo_int_cmp(C_word flonum, C_word intnum)
 9565{
 9566  C_word res = int_flo_cmp(intnum, flonum);
 9567  switch(res) {
 9568  case C_fix(1): return C_fix(-1);
 9569  case C_fix(-1): return C_fix(1);
 9570  default: return res; /* Can be either C_fix(0) or C_SCHEME_FALSE(!) */
 9571  }
 9572}
 9573
 9574/* This code is a bit tedious, but it makes inline comparisons possible! */
 9575static C_word rat_flo_cmp(C_word ratnum, C_word flonum)
 9576{
 9577  C_word ab[C_SIZEOF_FIX_BIGNUM * 4 + C_SIZEOF_FLONUM], *a = ab,
 9578         num, denom, i_int, res, nscaled, iscaled, negp, shift_amount;
 9579  C_uword *scan;
 9580  double i, f;
 9581
 9582  f = C_flonum_magnitude(flonum);
 9583
 9584  if (C_isnan(f)) {
 9585    return C_SCHEME_FALSE; /* "mu" */
 9586  } else if (C_isinf(f)) {
 9587    return C_fix((f > 0.0) ? -1 : 1); /* x is smaller if f is +inf.0 */
 9588  } else {
 9589    /* Scale up the floating-point number to become a whole integer,
 9590     * and remember power of two (# of bits) to shift the numerator.
 9591     */
 9592    shift_amount = 0;
 9593
 9594    /* TODO: This doesn't work for denormalized flonums! */
 9595    while (modf(f, &i) != 0.0) {
 9596      f = ldexp(f, 1);
 9597      shift_amount++;
 9598    }
 9599
 9600    i = f; /* TODO: split i and f so it'll work for denormalized flonums */
 9601
 9602    num = C_u_i_ratnum_num(ratnum);
 9603    negp = C_i_negativep(num);
 9604
 9605    if (C_truep(negp) && i >= 0.0) { /* Save some time if signs differ */
 9606      return C_fix(-1);
 9607    } else if (!C_truep(negp) && i <= 0.0) { /* num is never 0 */
 9608      return C_fix(1);
 9609    } else {
 9610      denom = C_u_i_ratnum_denom(ratnum);
 9611      i_int = C_s_a_u_i_flo_to_int(&a, 1, C_flonum(&a, i));
 9612
 9613      /* Multiply the scaled flonum integer by the denominator, and
 9614       * shift the numerator so that they may be directly compared. */
 9615      iscaled = C_s_a_u_i_integer_times(&a, 2, i_int, denom);
 9616      nscaled = C_s_a_i_arithmetic_shift(&a, 2, num, C_fix(shift_amount));
 9617
 9618      /* Finally, we're ready to compare them! */
 9619      res = basic_cmp(nscaled, iscaled, "rat_flo_cmp", 0);
 9620      clear_buffer_object(ab, nscaled);
 9621      clear_buffer_object(ab, iscaled);
 9622      clear_buffer_object(ab, i_int);
 9623
 9624      return res;
 9625    }
 9626  }
 9627}
 9628
 9629static C_word flo_rat_cmp(C_word flonum, C_word ratnum)
 9630{
 9631  C_word res = rat_flo_cmp(ratnum, flonum);
 9632  switch(res) {
 9633  case C_fix(1): return C_fix(-1);
 9634  case C_fix(-1): return C_fix(1);
 9635  default: return res; /* Can be either C_fix(0) or C_SCHEME_FALSE(!) */
 9636  }
 9637}
 9638
 9639/* The primitive comparison operator.  eqp should be 1 if we're only
 9640 * interested in equality testing (can speed things up and in case of
 9641 * compnums, equality checking is the only available operation).  This
 9642 * may return #f, in case there is no answer (for NaNs) or as a quick
 9643 * and dirty non-zero answer when eqp is true.  Ugly but effective :)
 9644 */
 9645static C_word basic_cmp(C_word x, C_word y, char *loc, int eqp)
 9646{
 9647  if (x & C_FIXNUM_BIT) {
 9648    if (y & C_FIXNUM_BIT) {
 9649      return C_fix((x < y) ? -1 : ((x > y) ? 1 : 0));
 9650    } else if (C_immediatep(y)) {
 9651      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9652    } else if (C_block_header(y) == C_FLONUM_TAG) {
 9653      return int_flo_cmp(x, y);
 9654    } else if (C_truep(C_bignump(y))) {
 9655      C_word ab[C_SIZEOF_FIX_BIGNUM], *a = ab;
 9656      return C_i_bignum_cmp(C_a_u_i_fix_to_big(&a, x), y);
 9657    } else if (C_block_header(y) == C_RATNUM_TAG) {
 9658      if (eqp) return C_SCHEME_FALSE;
 9659      else return rat_cmp(x, y);
 9660    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 9661      if (eqp) return C_SCHEME_FALSE;
 9662      else barf(C_BAD_ARGUMENT_TYPE_COMPLEX_NO_ORDERING_ERROR, loc, y);
 9663    } else {
 9664      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9665    }
 9666  } else if (C_immediatep(x)) {
 9667    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, x);
 9668  } else if (C_block_header(x) == C_FLONUM_TAG) {
 9669    if (y & C_FIXNUM_BIT) {
 9670      return flo_int_cmp(x, y);
 9671    } else if (C_immediatep(y)) {
 9672      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9673    } else if (C_block_header(y) == C_FLONUM_TAG) {
 9674      double a = C_flonum_magnitude(x), b = C_flonum_magnitude(y);
 9675      if (C_isnan(a) || C_isnan(b)) return C_SCHEME_FALSE; /* "mu" */
 9676      else return C_fix((a < b) ? -1 : ((a > b) ? 1 : 0));
 9677    } else if (C_truep(C_bignump(y))) {
 9678      return flo_int_cmp(x, y);
 9679    } else if (C_block_header(y) == C_RATNUM_TAG) {
 9680      return flo_rat_cmp(x, y);
 9681    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 9682      if (eqp) return C_SCHEME_FALSE;
 9683      else barf(C_BAD_ARGUMENT_TYPE_COMPLEX_NO_ORDERING_ERROR, loc, y);
 9684    } else {
 9685      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9686    }
 9687  } else if (C_truep(C_bignump(x))) {
 9688    if (y & C_FIXNUM_BIT) {
 9689      C_word ab[C_SIZEOF_FIX_BIGNUM], *a = ab;
 9690      return C_i_bignum_cmp(x, C_a_u_i_fix_to_big(&a, y));
 9691    } else if (C_immediatep(y)) {
 9692      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9693    } else if (C_block_header(y) == C_FLONUM_TAG) {
 9694      return int_flo_cmp(x, y);
 9695    } else if (C_truep(C_bignump(y))) {
 9696      return C_i_bignum_cmp(x, y);
 9697    } else if (C_block_header(y) == C_RATNUM_TAG) {
 9698      if (eqp) return C_SCHEME_FALSE;
 9699      else return rat_cmp(x, y);
 9700    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 9701      if (eqp) return C_SCHEME_FALSE;
 9702      else barf(C_BAD_ARGUMENT_TYPE_COMPLEX_NO_ORDERING_ERROR, loc, y);
 9703    } else {
 9704      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9705    }
 9706  } else if (C_block_header(x) == C_RATNUM_TAG) {
 9707    if (y & C_FIXNUM_BIT) {
 9708      if (eqp) return C_SCHEME_FALSE;
 9709      else return rat_cmp(x, y);
 9710    } else if (C_immediatep(y)) {
 9711      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9712    } else if (C_block_header(y) == C_FLONUM_TAG) {
 9713      return rat_flo_cmp(x, y);
 9714    } else if (C_truep(C_bignump(y))) {
 9715      if (eqp) return C_SCHEME_FALSE;
 9716      else return rat_cmp(x, y);
 9717    } else if (C_block_header(y) == C_RATNUM_TAG) {
 9718      if (eqp) {
 9719        return C_and(C_and(C_i_integer_equalp(C_u_i_ratnum_num(x),
 9720                                              C_u_i_ratnum_num(y)),
 9721                           C_i_integer_equalp(C_u_i_ratnum_denom(x),
 9722                                              C_u_i_ratnum_denom(y))),
 9723                     C_fix(0));
 9724      } else {
 9725        return rat_cmp(x, y);
 9726      }
 9727    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 9728      if (eqp) return C_SCHEME_FALSE;
 9729      else barf(C_BAD_ARGUMENT_TYPE_COMPLEX_NO_ORDERING_ERROR, loc, y);
 9730    } else {
 9731      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9732    }
 9733  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 9734    if (!eqp) {
 9735      barf(C_BAD_ARGUMENT_TYPE_COMPLEX_NO_ORDERING_ERROR, loc, x);
 9736    } else if (y & C_FIXNUM_BIT) {
 9737      return C_SCHEME_FALSE;
 9738    } else if (C_immediatep(y)) {
 9739      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9740    } else if (C_block_header(y) == C_FLONUM_TAG ||
 9741               C_truep(C_bignump(x)) ||
 9742               C_block_header(y) == C_RATNUM_TAG) {
 9743      return C_SCHEME_FALSE;
 9744    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 9745      return C_and(C_and(C_i_nequalp(C_u_i_cplxnum_real(x), C_u_i_cplxnum_real(y)),
 9746                         C_i_nequalp(C_u_i_cplxnum_imag(x), C_u_i_cplxnum_imag(y))),
 9747                   C_fix(0));
 9748    } else {
 9749      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9750    }
 9751  } else {
 9752    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, x);
 9753  }
 9754}
 9755
 9756static int bignum_cmp_unsigned(C_word x, C_word y)
 9757{
 9758  C_word xlen = C_bignum_size(x), ylen = C_bignum_size(y);
 9759
 9760  if (xlen < ylen) {
 9761    return -1;
 9762  } else if (xlen > ylen) {
 9763    return 1;
 9764  } else if (x == y) {
 9765    return 0;
 9766  } else {
 9767    C_uword *startx = C_bignum_digits(x),
 9768            *scanx = startx + xlen,
 9769            *scany = C_bignum_digits(y) + ylen;
 9770
 9771    while (startx < scanx) {
 9772      C_uword xdigit = (*--scanx), ydigit = (*--scany);
 9773      if (xdigit < ydigit)
 9774        return -1;
 9775      if (xdigit > ydigit)
 9776        return 1;
 9777    }
 9778    return 0;
 9779  }
 9780}
 9781
 9782C_regparm C_word C_fcall C_i_bignum_cmp(C_word x, C_word y)
 9783{
 9784  if (C_bignum_negativep(x)) {
 9785    if (C_bignum_negativep(y)) { /* Largest negative number is smallest */
 9786      return C_fix(bignum_cmp_unsigned(y, x));
 9787    } else {
 9788      return C_fix(-1);
 9789    }
 9790  } else {
 9791    if (C_bignum_negativep(y)) {
 9792      return C_fix(1);
 9793    } else {
 9794      return C_fix(bignum_cmp_unsigned(x, y));
 9795    }
 9796  }
 9797}
 9798
 9799void C_ccall C_nequalp(C_word c, C_word *av)
 9800{
 9801  /* C_word closure = av[ 0 ]; */
 9802  C_word k = av[ 1 ];
 9803  C_word x, y, result = C_SCHEME_TRUE;
 9804
 9805  c -= 2;
 9806  av += 2;
 9807  if (c == 0) C_kontinue(k, result);
 9808  x = *(av++);
 9809
 9810  if (c == 1 && !C_truep(C_i_numberp(x)))
 9811    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "=", x);
 9812
 9813  while(--c) {
 9814    y = *(av++);
 9815    result = C_i_nequalp(x, y);
 9816    if (result == C_SCHEME_FALSE) break;
 9817  }
 9818
 9819  C_kontinue(k, result);
 9820}
 9821
 9822C_regparm C_word C_fcall C_i_nequalp(C_word x, C_word y)
 9823{
 9824   return C_mk_bool(basic_cmp(x, y, "=", 1) == C_fix(0));
 9825}
 9826
 9827C_regparm C_word C_fcall C_i_integer_equalp(C_word x, C_word y)
 9828{
 9829  if (x & C_FIXNUM_BIT)
 9830    return C_mk_bool(x == y);
 9831  else if (y & C_FIXNUM_BIT)
 9832    return C_SCHEME_FALSE;
 9833  else
 9834    return C_mk_bool(C_i_bignum_cmp(x, y) == C_fix(0));
 9835}
 9836
 9837
 9838void C_ccall C_greaterp(C_word c, C_word *av)
 9839{
 9840  C_word x, y,
 9841    /* closure = av[ 0 ] */
 9842    k = av[ 1 ],
 9843    result = C_SCHEME_TRUE;
 9844
 9845  c -= 2; 
 9846  av += 2;
 9847  if (c == 0) C_kontinue(k, result);
 9848
 9849  x = *(av++);
 9850
 9851  if (c == 1 && !C_truep(C_i_numberp(x)))
 9852    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, ">", x);
 9853
 9854  while(--c) {
 9855    y = *(av++);
 9856    result = C_i_greaterp(x, y);
 9857    if (result == C_SCHEME_FALSE) break;
 9858    x = y;
 9859  }
 9860
 9861  C_kontinue(k, result);
 9862}
 9863
 9864
 9865C_regparm C_word C_fcall C_i_greaterp(C_word x, C_word y)
 9866{
 9867   return C_mk_bool(basic_cmp(x, y, ">", 0) == C_fix(1));
 9868}
 9869
 9870C_regparm C_word C_fcall C_i_integer_greaterp(C_word x, C_word y)
 9871{
 9872  if (x & C_FIXNUM_BIT) {
 9873    if (y & C_FIXNUM_BIT) {
 9874      return C_mk_bool(C_unfix(x) > C_unfix(y));
 9875    } else {
 9876      return C_mk_bool(C_bignum_negativep(y));
 9877    }
 9878  } else if (y & C_FIXNUM_BIT) {
 9879    return C_mk_nbool(C_bignum_negativep(x));
 9880  } else {
 9881    return C_mk_bool(C_i_bignum_cmp(x, y) == C_fix(1));
 9882  }
 9883}
 9884
 9885void C_ccall C_lessp(C_word c, C_word *av)
 9886{
 9887  C_word x, y,
 9888    /* closure = av[ 0 ] */
 9889    k = av[ 1 ],
 9890    result = C_SCHEME_TRUE;
 9891
 9892  c -= 2; 
 9893  av += 2;
 9894  if (c == 0) C_kontinue(k, result);
 9895
 9896  x = *(av++);
 9897
 9898  if (c == 1 && !C_truep(C_i_numberp(x)))
 9899    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "<", x);
 9900
 9901  while(--c) {
 9902    y = *(av++);
 9903    result = C_i_lessp(x, y);
 9904    if (result == C_SCHEME_FALSE) break;
 9905    x = y;
 9906  }
 9907
 9908  C_kontinue(k, result);
 9909}
 9910
 9911
 9912C_regparm C_word C_fcall C_i_lessp(C_word x, C_word y)
 9913{
 9914   return C_mk_bool(basic_cmp(x, y, "<", 0) == C_fix(-1));
 9915}
 9916
 9917C_regparm C_word C_fcall C_i_integer_lessp(C_word x, C_word y)
 9918{
 9919  if (x & C_FIXNUM_BIT) {
 9920    if (y & C_FIXNUM_BIT) {
 9921      return C_mk_bool(C_unfix(x) < C_unfix(y));
 9922    } else {
 9923      return C_mk_nbool(C_bignum_negativep(y));
 9924    }
 9925  } else if (y & C_FIXNUM_BIT) {
 9926    return C_mk_bool(C_bignum_negativep(x));
 9927  } else {
 9928    return C_mk_bool(C_i_bignum_cmp(x, y) == C_fix(-1));
 9929  }
 9930}
 9931
 9932void C_ccall C_greater_or_equal_p(C_word c, C_word *av)
 9933{
 9934  C_word x, y,
 9935    /* closure = av[ 0 ] */
 9936    k = av[ 1 ],
 9937    result = C_SCHEME_TRUE;
 9938
 9939  c -= 2; 
 9940  av += 2;
 9941  if (c == 0) C_kontinue(k, result);
 9942
 9943  x = *(av++);
 9944
 9945  if (c == 1 && !C_truep(C_i_numberp(x)))
 9946    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, ">=", x);
 9947
 9948  while(--c) {
 9949    y = *(av++);
 9950    result = C_i_greater_or_equalp(x, y);
 9951    if (result == C_SCHEME_FALSE) break;
 9952    x = y;
 9953  }
 9954
 9955  C_kontinue(k, result);
 9956}
 9957
 9958
 9959C_regparm C_word C_fcall C_i_greater_or_equalp(C_word x, C_word y)
 9960{
 9961   C_word res = basic_cmp(x, y, ">=", 0);
 9962   return C_mk_bool(res == C_fix(0) || res == C_fix(1));
 9963}
 9964
 9965C_regparm C_word C_fcall C_i_integer_greater_or_equalp(C_word x, C_word y)
 9966{
 9967  if (x & C_FIXNUM_BIT) {
 9968    if (y & C_FIXNUM_BIT) {
 9969      return C_mk_bool(C_unfix(x) >= C_unfix(y));
 9970    } else {
 9971      return C_mk_bool(C_bignum_negativep(y));
 9972    }
 9973  } else if (y & C_FIXNUM_BIT) {
 9974    return C_mk_nbool(C_bignum_negativep(x));
 9975  } else {
 9976    C_word res = C_i_bignum_cmp(x, y);
 9977    return C_mk_bool(res == C_fix(0) || res == C_fix(1));
 9978  }
 9979}
 9980
 9981void C_ccall C_less_or_equal_p(C_word c, C_word *av)
 9982{
 9983  C_word x, y,
 9984    /* closure = av[ 0 ] */
 9985    k = av[ 1 ],
 9986    result = C_SCHEME_TRUE;
 9987
 9988  c -= 2; 
 9989  av += 2;
 9990  if (c == 0) C_kontinue(k, result);
 9991
 9992  x = *(av++);
 9993
 9994  if (c == 1 && !C_truep(C_i_numberp(x)))
 9995    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "<=", x);
 9996
 9997  while(--c) {
 9998    y = *(av++);
 9999    result = C_i_less_or_equalp(x, y);
10000    if (result == C_SCHEME_FALSE) break;
10001    x = y;
10002  }
10003
10004  C_kontinue(k, result);
10005}
10006
10007
10008C_regparm C_word C_fcall C_i_less_or_equalp(C_word x, C_word y)
10009{
10010   C_word res = basic_cmp(x, y, "<=", 0);
10011   return C_mk_bool(res == C_fix(0) || res == C_fix(-1));
10012}
10013
10014
10015C_regparm C_word C_fcall C_i_integer_less_or_equalp(C_word x, C_word y)
10016{
10017  if (x & C_FIXNUM_BIT) {
10018    if (y & C_FIXNUM_BIT) {
10019      return C_mk_bool(C_unfix(x) <= C_unfix(y));
10020    } else {
10021      return C_mk_nbool(C_bignum_negativep(y));
10022    }
10023  } else if (y & C_FIXNUM_BIT) {
10024    return C_mk_bool(C_bignum_negativep(x));
10025  } else {
10026    C_word res = C_i_bignum_cmp(x, y);
10027    return C_mk_bool(res == C_fix(0) || res == C_fix(-1));
10028  }
10029}
10030
10031
10032void C_ccall C_gc(C_word c, C_word *av)
10033{
10034  C_word
10035    /* closure = av[ 0 ] */
10036    k = av[ 1 ];
10037  int f;
10038  C_word 
10039    arg, *p,
10040    size = 0;
10041
10042  if(c == 3) {
10043    arg = av[ 2 ];
10044    f = C_truep(arg);
10045  }
10046  else if(c != 2) C_bad_min_argc(c, 2);
10047  else f = 1;
10048
10049  C_save(k);
10050  p = C_temporary_stack;
10051
10052  if(c == 3) {
10053    if((arg & C_FIXNUM_BIT) != 0) size = C_unfix(arg);
10054    else if(arg == C_SCHEME_END_OF_LIST) size = percentage(heap_size, C_heap_growth);
10055  }
10056
10057  if(size && !C_heap_size_is_fixed) {
10058    C_rereclaim2(size, 0);
10059    C_temporary_stack = C_temporary_stack_bottom;
10060    gc_2(0, p);
10061  }
10062  else if(f) C_fromspace_top = C_fromspace_limit;
10063
10064  C_reclaim((void *)gc_2, 1);
10065}
10066
10067
10068void C_ccall gc_2(C_word c, C_word *av)
10069{
10070  C_word k = av[ 0 ];
10071  C_kontinue(k, C_fix((C_uword)C_fromspace_limit - (C_uword)C_fromspace_top));
10072}
10073
10074
10075void C_ccall C_open_file_port(C_word c, C_word *av)
10076{
10077  C_word
10078    /* closure = av[ 0 ] */
10079    k = av[ 1 ], 
10080    port = av[ 2 ],
10081    channel = av[ 3 ],
10082    mode = av[ 4 ];
10083  C_FILEPTR fp = (C_FILEPTR)NULL;
10084  C_char fmode[ 4 ];
10085  C_word n;
10086  char *buf;
10087
10088  switch(channel) {
10089  case C_fix(0): fp = C_stdin; break;
10090  case C_fix(1): fp = C_stdout; break;
10091  case C_fix(2): fp = C_stderr; break;
10092  default:
10093    n = C_header_size(channel);
10094    buf = buffer;
10095
10096    if(n >= STRING_BUFFER_SIZE) {
10097      if((buf = (char *)C_malloc(n + 1)) == NULL)
10098	barf(C_OUT_OF_MEMORY_ERROR, "open");
10099    }
10100
10101    C_strncpy(buf, C_c_string(channel), n);
10102    buf[ n ] = '\0';
10103    if (n != strlen(buf))
10104      barf(C_ASCIIZ_REPRESENTATION_ERROR, "open", channel);
10105    n = C_header_size(mode);
10106    if (n >= sizeof(fmode)) n = sizeof(fmode) - 1;
10107    C_strncpy(fmode, C_c_string(mode), n);
10108    fmode[ n ] = '\0';
10109    if (n != strlen(fmode)) /* Shouldn't happen, but never hurts */
10110      barf(C_ASCIIZ_REPRESENTATION_ERROR, "open", mode);
10111    fp = C_fopen(buf, fmode);
10112
10113    if(buf != buffer) C_free(buf);
10114  }
10115  
10116  C_set_block_item(port, 0, (C_word)fp);
10117  C_kontinue(k, C_mk_bool(fp != NULL));
10118}
10119
10120
10121void C_ccall C_allocate_vector(C_word c, C_word *av)
10122{
10123  C_word 
10124    /* closure = av[ 0 ] */
10125    k = av[ 1 ],
10126    size, bvecf, init, align8,
10127    bytes,
10128    n, *p;
10129
10130  if(c != 6) C_bad_argc(c, 6);
10131
10132  size = av[ 2 ];
10133  bvecf = av[ 3 ];
10134  init = av[ 4 ];
10135  align8 = av[ 5 ];
10136  n = C_unfix(size);
10137
10138  if(n > C_HEADER_SIZE_MASK || n < 0)
10139    barf(C_OUT_OF_RANGE_ERROR, NULL, size, C_fix(C_HEADER_SIZE_MASK));
10140
10141  if(!C_truep(bvecf)) bytes = C_wordstobytes(n) + sizeof(C_word);
10142  else bytes = n + sizeof(C_word);
10143
10144  if(C_truep(align8)) bytes += sizeof(C_word);
10145
10146  C_save(k);
10147  C_save(size);
10148  C_save(init);
10149  C_save(bvecf);
10150  C_save(align8);
10151  C_save(C_fix(bytes));
10152
10153  if(!C_demand(C_bytestowords(bytes))) {
10154    /* Allocate on heap: */
10155    if((C_uword)(C_fromspace_limit - C_fromspace_top) < (bytes + stack_size * 2))
10156      C_fromspace_top = C_fromspace_limit; /* trigger major GC */
10157  
10158    C_save(C_SCHEME_TRUE);
10159    /* We explicitly pass 7 here, that's the number of things saved.
10160     * That's the arguments, plus one additional thing: the mode.
10161     */
10162    C_reclaim((void *)allocate_vector_2, 7);
10163  }
10164
10165  C_save(C_SCHEME_FALSE);
10166  p = C_temporary_stack;
10167  C_temporary_stack = C_temporary_stack_bottom;
10168  allocate_vector_2(0, p);
10169}
10170
10171
10172void C_ccall allocate_vector_2(C_word c, C_word *av)
10173{
10174  C_word 
10175    mode = av[ 0 ],
10176    bytes = C_unfix(av[ 1 ]),
10177    align8 = av[ 2 ],
10178    bvecf = av[ 3 ],
10179    init = av[ 4 ],
10180    size = C_unfix(av[ 5 ]),
10181    k = av[ 6 ],
10182    *v0, v;
10183
10184  if(C_truep(mode)) {
10185    while((C_uword)(C_fromspace_limit - C_fromspace_top) < (bytes + stack_size)) {
10186      if(C_heap_size_is_fixed)
10187	panic(C_text("out of memory - cannot allocate vector (heap resizing disabled)"));
10188
10189      C_save(init);
10190      C_save(k);
10191      C_rereclaim2(percentage(heap_size, C_heap_growth) + (C_uword)bytes, 0);
10192      k = C_restore;
10193      init = C_restore;
10194    }
10195
10196    v0 = (C_word *)C_align((C_word)C_fromspace_top);
10197    C_fromspace_top += C_align(bytes);
10198  }
10199  else v0 = C_alloc(C_bytestowords(bytes));
10200
10201#ifndef C_SIXTY_FOUR
10202  if(C_truep(align8) && C_aligned8(v0)) ++v0;
10203#endif
10204
10205  v = (C_word)v0;
10206
10207  if(!C_truep(bvecf)) {
10208    *(v0++) = C_VECTOR_TYPE | size | (C_truep(align8) ? C_8ALIGN_BIT : 0);
10209  
10210    while(size--) *(v0++) = init;
10211  }
10212  else {
10213    *(v0++) = C_STRING_TYPE | size;
10214
10215    if(C_truep(init))
10216      C_memset(v0, C_character_code(init), size);
10217  }
10218
10219  C_kontinue(k, v);
10220}
10221
10222static C_word allocate_tmp_bignum(C_word size, C_word negp, C_word initp)
10223{
10224  C_word *mem = C_malloc(C_wordstobytes(C_SIZEOF_BIGNUM(C_unfix(size)))),
10225          bigvec = (C_word)(mem + C_SIZEOF_BIGNUM_WRAPPER);
10226  if (mem == NULL) abort();     /* TODO: panic */
10227  
10228  C_block_header_init(bigvec, C_STRING_TYPE | C_wordstobytes(C_unfix(size)+1));
10229  C_set_block_item(bigvec, 0, C_truep(negp));
10230
10231  if (C_truep(initp)) {
10232    C_memset(((C_uword *)C_data_pointer(bigvec))+1,
10233             0, C_wordstobytes(C_unfix(size)));
10234  }
10235
10236  return C_a_i_bignum_wrapper(&mem, bigvec);
10237}
10238
10239C_regparm C_word C_fcall
10240C_allocate_scratch_bignum(C_word **ptr, C_word size, C_word negp, C_word initp)
10241{
10242  C_word big, bigvec = C_scratch_alloc(C_SIZEOF_INTERNAL_BIGNUM_VECTOR(C_unfix(size)));
10243  
10244  C_block_header_init(bigvec, C_STRING_TYPE | C_wordstobytes(C_unfix(size)+1));
10245  C_set_block_item(bigvec, 0, C_truep(negp));
10246
10247  if (C_truep(initp)) {
10248    C_memset(((C_uword *)C_data_pointer(bigvec))+1,
10249             0, C_wordstobytes(C_unfix(size)));
10250  }
10251
10252  big = C_a_i_bignum_wrapper(ptr, bigvec);
10253  C_mutate_scratch_slot(&C_internal_bignum_vector(big), bigvec);
10254  return big;
10255}
10256
10257/* Simplification: scan trailing zeroes, then return a fixnum if the
10258 * value fits, or trim the bignum's length.  If the bignum was stored
10259 * in scratch space, we mark it as reclaimable.  This means any
10260 * references to the original bignum are invalid after simplification!
10261 */
10262C_regparm C_word C_fcall C_bignum_simplify(C_word big)
10263{
10264  C_uword *start = C_bignum_digits(big),
10265          *last_digit = start + C_bignum_size(big) - 1,
10266          *scan = last_digit, tmp;
10267  int length;
10268
10269  while (scan >= start && *scan == 0)
10270    scan--;
10271  length = scan - start + 1;
10272
10273  switch(length) {
10274  case 0:
10275    if (C_in_scratchspacep(C_internal_bignum_vector(big)))
10276      C_mutate_scratch_slot(NULL, C_internal_bignum_vector(big));
10277    return C_fix(0);
10278  case 1:
10279    tmp = *start;
10280    if (C_bignum_negativep(big) ?
10281        !(tmp & C_INT_SIGN_BIT) && C_fitsinfixnump(-(C_word)tmp) :
10282        C_ufitsinfixnump(tmp)) {
10283      if (C_in_scratchspacep(C_internal_bignum_vector(big)))
10284        C_mutate_scratch_slot(NULL, C_internal_bignum_vector(big));
10285      return C_bignum_negativep(big) ? C_fix(-(C_word)tmp) : C_fix(tmp);
10286    }
10287    /* FALLTHROUGH */
10288  default:
10289    if (scan < last_digit) C_bignum_mutate_size(big, length);
10290    return big;
10291  }
10292}
10293
10294static void bignum_digits_destructive_negate(C_word result)
10295{
10296  C_uword *scan, *end, digit, sum;
10297
10298  scan = C_bignum_digits(result);
10299  end = scan + C_bignum_size(result);
10300
10301  do {
10302    digit = ~*scan;
10303    sum = digit + 1;
10304    *scan++ = sum;
10305  } while (sum == 0 && scan < end);
10306
10307  for (; scan < end; scan++) {
10308    *scan = ~*scan;
10309  }
10310}
10311
10312static C_uword
10313bignum_digits_destructive_scale_up_with_carry(C_uword *start, C_uword *end, C_uword factor, C_uword carry)
10314{
10315  C_uword digit, p;
10316
10317  assert(C_fitsinbignumhalfdigitp(carry));
10318  assert(C_fitsinbignumhalfdigitp(factor));
10319
10320  /* See fixnum_times.  Substitute xlo = factor, xhi = 0, y = digit
10321   * and simplify the result to reduce variable usage.
10322   */
10323  while (start < end) {
10324    digit = (*start);
10325
10326    p = factor * C_BIGNUM_DIGIT_LO_HALF(digit) + carry;
10327    carry = C_BIGNUM_DIGIT_LO_HALF(p);
10328
10329    p = factor * C_BIGNUM_DIGIT_HI_HALF(digit) + C_BIGNUM_DIGIT_HI_HALF(p);
10330    (*start++) = C_BIGNUM_DIGIT_COMBINE(C_BIGNUM_DIGIT_LO_HALF(p), carry);
10331    carry = C_BIGNUM_DIGIT_HI_HALF(p);
10332  }
10333  return carry;
10334}
10335
10336static C_uword
10337bignum_digits_destructive_scale_down(C_uword *start, C_uword *end, C_uword denominator)
10338{
10339  C_uword digit, k = 0;
10340  C_uhword q_j_hi, q_j_lo;
10341
10342  /* Single digit divisor case from Hacker's Delight, Figure 9-1,
10343   * adapted to modify u[] in-place instead of writing to q[].
10344   */
10345  while (start < end) {
10346    digit = (*--end);
10347
10348    k = C_BIGNUM_DIGIT_COMBINE(k, C_BIGNUM_DIGIT_HI_HALF(digit)); /* j */
10349    q_j_hi = k / denominator;
10350    k -= q_j_hi * denominator;
10351
10352    k = C_BIGNUM_DIGIT_COMBINE(k, C_BIGNUM_DIGIT_LO_HALF(digit)); /* j-1 */
10353    q_j_lo = k / denominator;
10354    k -= q_j_lo * denominator;
10355    
10356    *end = C_BIGNUM_DIGIT_COMBINE(q_j_hi, q_j_lo);
10357  }
10358  return k;
10359}
10360
10361static C_uword
10362bignum_digits_destructive_shift_right(C_uword *start, C_uword *end, int shift_right, int negp)
10363{
10364  int shift_left = C_BIGNUM_DIGIT_LENGTH - shift_right;
10365  C_uword digit, carry = negp ? ((~(C_uword)0) << shift_left) : 0;
10366
10367  assert(shift_right < C_BIGNUM_DIGIT_LENGTH);
10368
10369  while (start < end) {
10370    digit = *(--end);
10371    *end = (digit >> shift_right) | carry;
10372    carry = digit << shift_left;
10373  }
10374  return carry >> shift_left; /* The bits that were shifted out to the right */
10375}
10376
10377static C_uword
10378bignum_digits_destructive_shift_left(C_uword *start, C_uword *end, int shift_left)
10379{
10380  C_uword carry = 0, digit;
10381  int shift_right = C_BIGNUM_DIGIT_LENGTH - shift_left;
10382
10383  assert(shift_left < C_BIGNUM_DIGIT_LENGTH);
10384
10385  while (start < end) {
10386    digit = *start;
10387    (*start++) = (digit << shift_left) | carry;
10388    carry = digit >> shift_right;
10389  }
10390  return carry;	 /* This would end up as most significant digit if it fit */
10391}
10392
10393static C_regparm void
10394bignum_digits_multiply(C_word x, C_word y, C_word result)
10395{
10396  C_uword product,
10397          *xd = C_bignum_digits(x),
10398          *yd = C_bignum_digits(y),
10399          *rd = C_bignum_digits(result);
10400  C_uhword carry, yj;
10401  /* Lengths in halfwords */
10402  int i, j, length_x = C_bignum_size(x) * 2, length_y = C_bignum_size(y) * 2;
10403
10404  /* From Hacker's Delight, Figure 8-1 (top part) */
10405  for (j = 0; j < length_y; ++j) {
10406    yj = C_uhword_ref(yd, j);
10407    if (yj == 0) continue;
10408    carry = 0;
10409    for (i = 0; i < length_x; ++i) {
10410      product = (C_uword)C_uhword_ref(xd, i) * yj +
10411                (C_uword)C_uhword_ref(rd, i + j) + carry;
10412      C_uhword_set(rd, i + j, product);
10413      carry = C_BIGNUM_DIGIT_HI_HALF(product);
10414    }
10415    C_uhword_set(rd, j + length_x, carry);
10416  }
10417}
10418
10419
10420/* "small" is either a number that fits a halfdigit, or a power of two */
10421static C_regparm void
10422bignum_destructive_divide_unsigned_small(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r)
10423{
10424  C_word size, quotient, q_negp = C_mk_bool((y & C_INT_SIGN_BIT) ?
10425                                            !(C_bignum_negativep(x)) :
10426                                            C_bignum_negativep(x)),
10427         r_negp = C_mk_bool(C_bignum_negativep(x));
10428  C_uword *start, *end, remainder;
10429  int shift_amount;
10430
10431  size = C_fix(C_bignum_size(x));
10432  quotient = C_allocate_scratch_bignum(ptr, size, q_negp, C_SCHEME_FALSE);
10433  bignum_digits_destructive_copy(quotient, x);
10434
10435  start = C_bignum_digits(quotient);
10436  end = start + C_bignum_size(quotient);
10437  
10438  y = (y & C_INT_SIGN_BIT) ? -C_unfix(y) : C_unfix(y);
10439
10440  shift_amount = C_ilen(y) - 1;
10441  if (((C_uword)1 << shift_amount) == y) { /* Power of two?  Shift! */
10442    remainder = bignum_digits_destructive_shift_right(start,end,shift_amount,0);
10443    assert(C_ufitsinfixnump(remainder));
10444  } else {
10445    remainder = bignum_digits_destructive_scale_down(start, end, y);
10446    assert(C_fitsinbignumhalfdigitp(remainder));
10447  }
10448
10449  if (r != NULL) *r = C_truep(r_negp) ? C_fix(-remainder) : C_fix(remainder);
10450  /* Calling this function only makes sense if quotient is needed */
10451  *q = C_bignum_simplify(quotient);
10452}
10453
10454static C_regparm void
10455bignum_destructive_divide_full(C_word numerator, C_word denominator, C_word quotient, C_word remainder, C_word return_remainder)
10456{
10457  C_word length = C_bignum_size(denominator);
10458  C_uword d1 = *(C_bignum_digits(denominator) + length - 1),
10459          *startr = C_bignum_digits(remainder),
10460          *endr = startr + C_bignum_size(remainder);
10461  int shift;
10462
10463  shift = C_BIGNUM_DIGIT_LENGTH - C_ilen(d1); /* nlz */
10464
10465  /* We have to work on halfdigits, so we shift out only the necessary
10466   * amount in order fill out that halfdigit (base is halved).
10467   * This trick is shamelessly stolen from Gauche :)
10468   * See below for part 2 of the trick.
10469   */
10470  if (shift >= C_BIGNUM_HALF_DIGIT_LENGTH)
10471    shift -= C_BIGNUM_HALF_DIGIT_LENGTH;
10472
10473  /* Code below won't always set high halfdigit of quotient, so do it here. */
10474  if (quotient != C_SCHEME_UNDEFINED)
10475    C_bignum_digits(quotient)[C_bignum_size(quotient)-1] = 0;
10476
10477  bignum_digits_destructive_copy(remainder, numerator);
10478  *(endr-1) = 0;    /* Ensure most significant digit is initialised */
10479  if (shift == 0) { /* Already normalized */
10480    bignum_destructive_divide_normalized(remainder, denominator, quotient);
10481  } else { /* Requires normalisation; allocate scratch denominator for this */
10482    C_uword *startnd;
10483    C_word ndenom;
10484
10485    bignum_digits_destructive_shift_left(startr, endr, shift);
10486
10487    ndenom = allocate_tmp_bignum(C_fix(length), C_SCHEME_FALSE, C_SCHEME_FALSE);
10488    startnd = C_bignum_digits(ndenom);
10489    bignum_digits_destructive_copy(ndenom, denominator);
10490    bignum_digits_destructive_shift_left(startnd, startnd+length, shift);
10491
10492    bignum_destructive_divide_normalized(remainder, ndenom, quotient);
10493    if (C_truep(return_remainder)) /* Otherwise, don't bother shifting back */
10494      bignum_digits_destructive_shift_right(startr, endr, shift, 0);
10495
10496    free_tmp_bignum(ndenom);
10497  }
10498}
10499
10500static C_regparm void
10501bignum_destructive_divide_normalized(C_word big_u, C_word big_v, C_word big_q)
10502{
10503  C_uword *v = C_bignum_digits(big_v),
10504          *u = C_bignum_digits(big_u),
10505          *q = big_q == C_SCHEME_UNDEFINED ? NULL : C_bignum_digits(big_q),
10506           p,               /* product of estimated quotient & "denominator" */
10507           hat, qhat, rhat, /* estimated quotient and remainder digit */
10508           vn_1, vn_2;      /* "cached" values v[n-1], v[n-2] */
10509  C_word t, k;              /* Two helpers: temp/final remainder and "borrow" */
10510  /* We use plain ints here, which theoretically may not be enough on
10511   * 64-bit for an insanely huge number, but it is a _lot_ faster.
10512   */
10513  int n = C_bignum_size(big_v) * 2,       /* in halfwords */
10514      m = (C_bignum_size(big_u) * 2) - 2; /* Correct for extra digit */
10515  int i, j;		   /* loop  vars */
10516
10517  /* Part 2 of Gauche's aforementioned trick: */
10518  if (C_uhword_ref(v, n-1) == 0) n--;
10519
10520  /* These won't change during the loop, but are used in every step. */
10521  vn_1 = C_uhword_ref(v, n-1);
10522  vn_2 = C_uhword_ref(v, n-2);
10523
10524  /* See also Hacker's Delight, Figure 9-1.  This is almost exactly that. */
10525  for (j = m - n; j >= 0; j--) {
10526    hat = C_BIGNUM_DIGIT_COMBINE(C_uhword_ref(u, j+n), C_uhword_ref(u, j+n-1));
10527    if (hat == 0) {
10528      if (q != NULL) C_uhword_set(q, j, 0);
10529      continue;
10530    }
10531    qhat = hat / vn_1;
10532    rhat = hat % vn_1;
10533
10534    /* Two whiles is faster than one big check with an OR.  Thanks, Gauche! */
10535    while(qhat >= ((C_uword)1 << C_BIGNUM_HALF_DIGIT_LENGTH)) { qhat--; rhat += vn_1; }
10536    while(qhat * vn_2 > C_BIGNUM_DIGIT_COMBINE(rhat, C_uhword_ref(u, j+n-2))
10537	  && rhat < ((C_uword)1 << C_BIGNUM_HALF_DIGIT_LENGTH)) {
10538      qhat--;
10539      rhat += vn_1;
10540    }
10541
10542    /* Multiply and subtract */
10543    k = 0;
10544    for (i = 0; i < n; i++) {
10545      p = qhat * C_uhword_ref(v, i);
10546      t = C_uhword_ref(u, i+j) - k - C_BIGNUM_DIGIT_LO_HALF(p);
10547      C_uhword_set(u, i+j, t);
10548      k = C_BIGNUM_DIGIT_HI_HALF(p) - (t >> C_BIGNUM_HALF_DIGIT_LENGTH);
10549    }
10550    t = C_uhword_ref(u,j+n) - k;
10551    C_uhword_set(u, j+n, t);
10552
10553    if (t < 0) {		/* Subtracted too much? */
10554      qhat--;
10555      k = 0;
10556      for (i = 0; i < n; i++) {
10557        t = (C_uword)C_uhword_ref(u, i+j) + C_uhword_ref(v, i) + k;
10558        C_uhword_set(u, i+j, t);
10559	k = t >> C_BIGNUM_HALF_DIGIT_LENGTH;
10560      }
10561      C_uhword_set(u, j+n, (C_uhword_ref(u, j+n) + k));
10562    }
10563    if (q != NULL) C_uhword_set(q, j, qhat);
10564  } /* end j */
10565}
10566
10567
10568void C_ccall C_string_to_symbol(C_word c, C_word *av) 
10569{ 
10570  C_word
10571    /* closure = av[ 0 ] */
10572    k = av[ 1 ],
10573    string;
10574  int len, key;
10575  C_word s, *a = C_alloc(C_SIZEOF_SYMBOL + C_SIZEOF_PAIR);
10576  C_char *name;
10577
10578  if(c != 3) C_bad_argc(c, 3);
10579
10580  string = av[ 2 ];
10581
10582  if(C_immediatep(string) || C_header_bits(string) != C_STRING_TYPE)
10583    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string->symbol", string);
10584    
10585  len = C_header_size(string);
10586  name = (C_char *)C_data_pointer(string);
10587
10588  key = hash_string(len, name, symbol_table->size, symbol_table->rand, 0);
10589  if(!C_truep(s = lookup(key, len, name, symbol_table)))
10590    s = add_symbol(&a, key, string, symbol_table);
10591
10592  C_kontinue(k, s);
10593}
10594
10595void C_ccall C_string_to_keyword(C_word c, C_word *av) 
10596{ 
10597  C_word
10598    /* closure = av[ 0 ] */
10599    k = av[ 1 ],
10600    string;
10601  int len, key;
10602  C_word s, *a = C_alloc(C_SIZEOF_SYMBOL + C_SIZEOF_PAIR);
10603  C_char *name;
10604
10605  if(c != 3) C_bad_argc(c, 3);
10606
10607  string = av[ 2 ];
10608
10609  if(C_immediatep(string) || C_header_bits(string) != C_STRING_TYPE)
10610    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string->keyword", string);
10611    
10612  len = C_header_size(string);
10613  name = (C_char *)C_data_pointer(string);
10614  key = hash_string(len, name, keyword_table->size, keyword_table->rand, 0);
10615
10616  if(!C_truep(s = lookup(key, len, name, keyword_table))) {
10617    s = add_symbol(&a, key, string, keyword_table);
10618    C_set_block_item(s, 0, s); /* Keywords evaluate to themselves */
10619    C_set_block_item(s, 2, C_SCHEME_FALSE); /* Keywords have no plists */
10620  }
10621  C_kontinue(k, s);
10622}
10623
10624/* This will usually return a flonum, but it may also return a cplxnum
10625 * consisting of two flonums, making for a total of 11 words.
10626 */
10627C_regparm C_word C_fcall 
10628C_a_i_exact_to_inexact(C_word **ptr, int c, C_word n)
10629{
10630  if (n & C_FIXNUM_BIT) {
10631    return C_flonum(ptr, (double)C_unfix(n));
10632  } else if (C_immediatep(n)) {
10633    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "exact->inexact", n);
10634  } else if (C_block_header(n) == C_FLONUM_TAG) {
10635    return n;
10636  } else if (C_truep(C_bignump(n))) {
10637    return C_a_u_i_big_to_flo(ptr, c, n);
10638  } else if (C_block_header(n) == C_CPLXNUM_TAG) {
10639    return C_cplxnum(ptr, C_a_i_exact_to_inexact(ptr, 1, C_u_i_cplxnum_real(n)),
10640                     C_a_i_exact_to_inexact(ptr, 1, C_u_i_cplxnum_imag(n)));
10641  /* The horribly painful case: ratnums */
10642  } else if (C_block_header(n) == C_RATNUM_TAG) {
10643    /* This tries to keep the numbers within representable ranges and
10644     * tries to drop as few significant digits as possible by bringing
10645     * the two numbers to within the same powers of two.  See
10646     * algorithms M & N in Knuth, 4.2.1.
10647     */
10648     C_word num = C_u_i_ratnum_num(n), denom = C_u_i_ratnum_denom(n),
10649             /* e = approx. distance between the numbers in powers of 2.
10650              * ie, 2^e-1 < n/d < 2^e+1 (e is the *un*biased value of
10651              * e_w in M2.  TODO: What if b!=2 (ie, flonum-radix isn't 2)?
10652              */
10653             e = integer_length_abs(num) - integer_length_abs(denom),
10654             ab[C_SIZEOF_FIX_BIGNUM*5+C_SIZEOF_FLONUM], *a = ab, tmp, q, r, len,
10655             shift_amount, negp = C_i_integer_negativep(num);
10656     C_uword *d;
10657     double res, fraction;
10658
10659     /* Align by shifting the smaller to the size of the larger */
10660     if (e < 0)      num = C_s_a_i_arithmetic_shift(&a, 2, num, C_fix(-e));
10661     else if (e > 0) denom = C_s_a_i_arithmetic_shift(&a, 2, denom, C_fix(e));
10662
10663     /* Here, 1/2 <= n/d < 2 [N3] */
10664     if (C_truep(C_i_integer_lessp(num, denom))) { /* n/d < 1? */
10665       tmp = C_s_a_i_arithmetic_shift(&a, 2, num, C_fix(1));
10666       clear_buffer_object(ab, num); /* "knows" shift creates fresh numbers */
10667       num = tmp;
10668       e--;
10669     }
10670
10671     /* Here, 1 <= n/d < 2 (normalized) [N5] */
10672     shift_amount = nmin(DBL_MANT_DIG-1, e - (DBL_MIN_EXP - DBL_MANT_DIG));
10673
10674     tmp = C_s_a_i_arithmetic_shift(&a, 2, num, C_fix(shift_amount));
10675     clear_buffer_object(ab, num); /* "knows" shift creates fresh numbers */
10676     num = tmp;
10677
10678     /* Now, calculate round(num/denom).  We start with a quotient&remainder */
10679     integer_divrem(&a, num, denom, &q, &r);
10680
10681     /* We multiply the remainder by two to simulate adding 1/2 for
10682      * round.  However, we don't do it if num = denom (q=1,r=0) */
10683     if (!((q == C_fix(1) || q == C_fix(-1)) && r == C_fix(0))) {
10684       tmp = C_s_a_i_arithmetic_shift(&a, 2, r, C_fix(1));
10685       clear_buffer_object(ab, r); /* "knows" shift creates fresh numbers */
10686       r = tmp;
10687     }
10688
10689     /* Now q is the quotient, but to "round" result we need to
10690      * adjust.  This follows the semantics of the "round" procedure:
10691      * Round away from zero on positive numbers (ignoring sign).  In
10692      * case of exactly halfway, we round up if odd.
10693      */
10694     tmp = C_a_i_exact_to_inexact(&a, 1, q);
10695     fraction = fabs(C_flonum_magnitude(tmp));
10696     switch (basic_cmp(r, denom, "", 0)) {
10697     case C_fix(0):
10698       if (C_truep(C_i_oddp(q))) fraction += 1.0;
10699       break;
10700     case C_fix(1):
10701       fraction += 1.0;
10702       break;
10703     default: /* if r <= denom, we're done */ break;
10704     }
10705
10706     clear_buffer_object(ab, num);
10707     clear_buffer_object(ab, denom);
10708     clear_buffer_object(ab, q);
10709     clear_buffer_object(ab, r);
10710
10711     shift_amount = nmin(DBL_MANT_DIG-1, e - (DBL_MIN_EXP - DBL_MANT_DIG));
10712     res = ldexp(fraction, e - shift_amount);
10713     return C_flonum(ptr, C_truep(negp) ? -res : res);
10714  } else {
10715    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "exact->inexact", n);
10716  }
10717}
10718
10719
10720/* this is different from C_a_i_flonum_round, for R5RS compatibility */
10721C_regparm C_word C_fcall C_a_i_flonum_round_proper(C_word **ptr, int c, C_word n)
10722{
10723  double fn, i, f, i2, r;
10724
10725  fn = C_flonum_magnitude(n);
10726  if(fn < 0.0) {
10727    f = modf(-fn, &i);
10728    if(f < 0.5 || (f == 0.5 && modf(i * 0.5, &i2) == 0.0))
10729      r = -i;
10730    else
10731      r = -(i + 1.0);
10732  }
10733  else if(fn == 0.0/* || fn == -0.0*/)
10734    r = fn;
10735  else {
10736    f = modf(fn, &i);
10737    if(f < 0.5 || (f == 0.5 && modf(i * 0.5, &i2) == 0.0))
10738      r = i;
10739    else
10740      r = i + 1.0;
10741  }
10742
10743  return C_flonum(ptr, r);
10744}
10745
10746C_regparm C_word C_fcall
10747C_a_i_flonum_gcd(C_word **p, C_word n, C_word x, C_word y)
10748{
10749   double xub, yub, r;
10750
10751   if (!C_truep(C_u_i_fpintegerp(x)))
10752     barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "gcd", x);
10753   if (!C_truep(C_u_i_fpintegerp(y)))
10754     barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "gcd", y);
10755
10756   xub = C_flonum_magnitude(x);
10757   yub = C_flonum_magnitude(y);
10758
10759   if (xub < 0.0) xub = -xub;
10760   if (yub < 0.0) yub = -yub;
10761   
10762   while(yub != 0.0) {
10763     r = fmod(xub, yub);
10764     xub = yub;
10765     yub = r;
10766   }
10767   return C_flonum(p, xub);
10768}
10769
10770/* This is Lehmer's GCD algorithm with Jebelean's quotient test, as
10771 * it is presented in the paper "An Analysis of Lehmer’s Euclidean
10772 * GCD Algorithm", by J. Sorenson.  Fuck the ACM and their goddamn
10773 * paywall; you can currently find the paper here:
10774 * http://www.csie.nuk.edu.tw/~cychen/gcd/An%20analysis%20of%20Lehmer%27s%20Euclidean%20GCD%20algorithm.pdf
10775 * If that URI fails, it's also explained in [MpNT, 5.2]
10776 *
10777 * The basic idea is to avoid divisions which yield only small
10778 * quotients, in which the remainder won't reduce the numbers by
10779 * much.  This can be detected by dividing only the leading k bits.
10780 * In our case, k = C_WORD_SIZE - 2.
10781 */
10782inline static void lehmer_gcd(C_word **ptr, C_word u, C_word v, C_word *x, C_word *y)
10783{
10784  int i_even = 1, done = 0;
10785  C_word shift_amount = integer_length_abs(u) - (C_WORD_SIZE - 2),
10786         ab[C_SIZEOF_BIGNUM(2)*2+C_SIZEOF_FIX_BIGNUM*2], *a = ab,
10787         uhat, vhat, qhat, xnext, ynext,
10788         xprev = 1, yprev = 0, xcurr = 0, ycurr = 1;
10789
10790  uhat = C_s_a_i_arithmetic_shift(&a, 2, u, C_fix(-shift_amount));
10791  vhat = C_s_a_i_arithmetic_shift(&a, 2, v, C_fix(-shift_amount));
10792  assert(uhat & C_FIXNUM_BIT); uhat = C_unfix(uhat);
10793  assert(vhat & C_FIXNUM_BIT); vhat = C_unfix(vhat);
10794
10795  do {
10796    qhat = uhat / vhat;         /* Estimated quotient for this step */
10797    xnext = xprev - qhat * xcurr;
10798    ynext = yprev - qhat * ycurr;
10799
10800    /* Euclidean GCD swap on uhat and vhat (shift_amount is not needed): */
10801    shift_amount = vhat;
10802    vhat = uhat - qhat * vhat;
10803    uhat = shift_amount;
10804
10805    i_even = !i_even;
10806    if (i_even)
10807      done = (vhat < -xnext) || ((uhat - vhat) < (ynext - ycurr));
10808    else
10809      done = (vhat < -ynext) || ((uhat - vhat) < (xnext - xcurr));
10810
10811    if (!done) {
10812      xprev = xcurr; yprev = ycurr;
10813      xcurr = xnext; ycurr = ynext;
10814    }
10815  } while (!done);
10816
10817  /* x = xprev * u + yprev * v */
10818  uhat = C_s_a_u_i_integer_times(&a, 2, C_fix(xprev), u);
10819  vhat = C_s_a_u_i_integer_times(&a, 2, C_fix(yprev), v);
10820  *x = C_s_a_u_i_integer_plus(ptr, 2, uhat, vhat);
10821  *x = move_buffer_object(ptr, ab, *x);
10822  clear_buffer_object(ab, uhat);
10823  clear_buffer_object(ab, vhat);
10824
10825  /* y = xcurr * u + ycurr * v */
10826  uhat = C_s_a_u_i_integer_times(&a, 2, C_fix(xcurr), u);
10827  vhat = C_s_a_u_i_integer_times(&a, 2, C_fix(ycurr), v);
10828  *y = C_s_a_u_i_integer_plus(ptr, 2, uhat, vhat);
10829  *y = move_buffer_object(ptr, ab, *y);
10830  clear_buffer_object(ab, uhat);
10831  clear_buffer_object(ab, vhat);
10832}
10833
10834/* Because this must be inlineable (due to + and - using this for
10835 * ratnums), we can't use burnikel-ziegler division here, until we
10836 * have a C implementation that doesn't consume stack.  However,
10837 * we *can* use Lehmer's GCD.
10838 */
10839C_regparm C_word C_fcall
10840C_s_a_u_i_integer_gcd(C_word **ptr, C_word n, C_word x, C_word y)
10841{
10842   C_word ab[2][C_SIZEOF_BIGNUM(2) * 2], *a, newx, newy, size, i = 0;
10843
10844   if (x & C_FIXNUM_BIT && y & C_FIXNUM_BIT) return C_i_fixnum_gcd(x, y);
10845
10846   a = ab[i++];
10847   x = C_s_a_u_i_integer_abs(&a, 1, x);
10848   y = C_s_a_u_i_integer_abs(&a, 1, y);
10849
10850   if (!C_truep(C_i_integer_greaterp(x, y))) {
10851     newx = y; y = x; x = newx; /* Ensure loop invariant: abs(x) >= abs(y) */
10852   }
10853
10854   while(y != C_fix(0)) {
10855     assert(integer_length_abs(x) >= integer_length_abs(y));
10856     /* x and y are stored in the same buffer, as well as a result */
10857     a = ab[i++];
10858     if (i == 2) i = 0;
10859
10860     if (x & C_FIXNUM_BIT) return C_i_fixnum_gcd(x, y);
10861
10862     /* First, see if we should run a Lehmer step */
10863     if ((integer_length_abs(x) - integer_length_abs(y)) < C_HALF_WORD_SIZE) {
10864       lehmer_gcd(&a, x, y, &newx, &newy);
10865       newx = move_buffer_object(&a, ab[i], newx);
10866       newy = move_buffer_object(&a, ab[i], newy);
10867       clear_buffer_object(ab[i], x);
10868       clear_buffer_object(ab[i], y);
10869       x = newx;
10870       y = newy;
10871       a = ab[i++]; /* Ensure x and y get cleared correctly below */
10872       if (i == 2) i = 0;
10873     }
10874
10875     newy = C_s_a_u_i_integer_remainder(&a, 2, x, y);
10876     newy = move_buffer_object(&a, ab[i], newy);
10877     newx = move_buffer_object(&a, ab[i], y);
10878     clear_buffer_object(ab[i], x);
10879     clear_buffer_object(ab[i], y);
10880     x = newx;
10881     y = newy;
10882   }
10883
10884   newx = C_s_a_u_i_integer_abs(ptr, 1, x);
10885   newx = move_buffer_object(ptr, ab, newx);
10886   clear_buffer_object(ab, x);
10887   clear_buffer_object(ab, y);
10888   return newx;
10889}
10890
10891
10892C_regparm C_word C_fcall
10893C_s_a_i_digits_to_integer(C_word **ptr, C_word n, C_word str, C_word start, C_word end, C_word radix, C_word negp)
10894{
10895  if (start == end) {
10896    return C_SCHEME_FALSE;
10897  } else {
10898    size_t nbits;
10899    char *s = C_c_string(str);
10900    C_word result, size;
10901    end = C_unfix(end);
10902    start = C_unfix(start);
10903    radix = C_unfix(radix);
10904
10905    assert((radix > 1) && C_fitsinbignumhalfdigitp(radix));
10906
10907    nbits = (end - start) * C_ilen(radix - 1);
10908    size = C_BIGNUM_BITS_TO_DIGITS(nbits);
10909    if (size == 1) {
10910      result = C_bignum1(ptr, C_truep(negp), 0);
10911    } else if (size == 2) {
10912      result = C_bignum2(ptr, C_truep(negp), 0, 0);
10913    } else {
10914      size = C_fix(size);
10915      result = C_allocate_scratch_bignum(ptr, size, negp, C_SCHEME_FALSE);
10916    }
10917
10918    return str_to_bignum(result, s + start, s + end, radix);
10919  }
10920}
10921
10922inline static int hex_char_to_digit(int ch)
10923{
10924  if (ch == (int)'#') return 0; /* Hash characters in numbers are mapped to 0 */
10925  else if (ch >= (int)'a') return ch - (int)'a' + 10; /* lower hex */
10926  else if (ch >= (int)'A') return ch - (int)'A' + 10; /* upper hex */
10927  else return ch - (int)'0'; /* decimal (OR INVALID; handled elsewhere) */
10928}
10929
10930/* Write from digit character stream to bignum.  Bignum does not need
10931 * to be initialised.  Returns the bignum, or a fixnum.  Assumes the
10932 * string contains only digits that fit within radix (checked by
10933 * string->number).
10934 */
10935static C_regparm C_word
10936str_to_bignum(C_word bignum, char *str, char *str_end, int radix)
10937{
10938  int radix_shift, str_digit;
10939  C_uword *digits = C_bignum_digits(bignum),
10940          *end_digits = digits + C_bignum_size(bignum), big_digit = 0;
10941
10942  /* Below, we try to save up as much as possible in big_digit, and
10943   * only when it exceeds what we would be able to multiply easily, we
10944   * scale up the bignum and add what we saved up.
10945   */
10946  radix_shift = C_ilen(radix) - 1;
10947  if (((C_uword)1 << radix_shift) == radix) { /* Power of two? */
10948    int n = 0; /* Number of bits read so far into current big digit */
10949
10950    /* Read from least to most significant digit to avoid shifting or scaling */
10951    while (str_end > str) {
10952      str_digit = hex_char_to_digit((int)*--str_end);
10953
10954      big_digit |= (C_uword)str_digit << n;
10955      n += radix_shift;
10956
10957      if (n >= C_BIGNUM_DIGIT_LENGTH) {
10958	n -= C_BIGNUM_DIGIT_LENGTH;
10959	*digits++ = big_digit;
10960	big_digit = str_digit >> (radix_shift - n);
10961      }
10962    }
10963    assert(n < C_BIGNUM_DIGIT_LENGTH);
10964    /* If radix isn't an exact divisor of digit length, write final digit */
10965    if (n > 0) *digits++ = big_digit;
10966    assert(digits == end_digits);
10967  } else {			  /* Not a power of two */
10968    C_uword *last_digit = digits, factor;  /* bignum starts as zero */
10969
10970    do {
10971      factor = radix;
10972      while (str < str_end && C_fitsinbignumhalfdigitp(factor)) {
10973        str_digit = hex_char_to_digit((int)*str++);
10974	factor *= radix;
10975	big_digit = radix * big_digit + str_digit;
10976      }
10977
10978      big_digit = bignum_digits_destructive_scale_up_with_carry(
10979                   digits, last_digit, factor / radix, big_digit);
10980
10981      if (big_digit) {
10982	(*last_digit++) = big_digit; /* Move end */
10983        big_digit = 0;
10984      }
10985    } while (str < str_end);
10986
10987    /* Set remaining digits to zero so bignum_simplify can do its work */
10988    assert(last_digit <= end_digits);
10989    while (last_digit < end_digits) *last_digit++ = 0;
10990  }
10991
10992  return C_bignum_simplify(bignum);
10993}
10994
10995
10996static C_regparm double C_fcall decode_flonum_literal(C_char *str)
10997{
10998  C_char *eptr;
10999  double flo;
11000  int len = C_strlen(str);
11001
11002  /* We only need to be able to parse what C_flonum_to_string() emits,
11003   * so we avoid too much error checking.
11004   */
11005  if (len == 6) { /* Only perform comparisons when necessary */
11006    if (!C_strcmp(str, "-inf.0")) return -1.0 / 0.0;
11007    if (!C_strcmp(str, "+inf.0")) return 1.0 / 0.0;
11008    if (!C_strcmp(str, "+nan.0")) return 0.0 / 0.0;
11009  }
11010
11011  errno = 0;
11012  flo = C_strtod(str, &eptr);
11013
11014  if((flo == HUGE_VAL && errno != 0) ||
11015     (flo == -HUGE_VAL && errno != 0) ||
11016     (*eptr != '\0' && C_strcmp(eptr, ".0") != 0)) {
11017    panic(C_text("could not decode flonum literal"));
11018  }
11019
11020  return flo;
11021}
11022
11023
11024static char *to_n_nary(C_uword num, C_uword base, int negp, int as_flonum)
11025{
11026  static char *digits = "0123456789abcdef";
11027  char *p;
11028  C_uword shift = C_ilen(base) - 1;
11029  int mask = (1 << shift) - 1;
11030  if (as_flonum) {
11031    buffer[68] = '\0';
11032    buffer[67] = '0';
11033    buffer[66] = '.';
11034  } else {
11035    buffer[66] = '\0';
11036  }
11037  p = buffer + 66;
11038  if (mask == base - 1) {
11039    do {
11040      *(--p) = digits [ num & mask ];
11041      num >>= shift;
11042    } while (num);
11043  } else {
11044    do {
11045      *(--p) = digits [ num % base ];
11046      num /= base;
11047    } while (num);
11048  }
11049  if (negp) *(--p) = '-';
11050  return p;
11051}
11052
11053
11054void C_ccall C_number_to_string(C_word c, C_word *av)
11055{
11056  C_word radix, num;
11057
11058  if(c == 3) {
11059    radix = C_fix(10);
11060  } else if(c == 4) {
11061    radix = av[ 3 ];
11062    if(!(radix & C_FIXNUM_BIT))
11063      barf(C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR, "number->string", radix);
11064  } else {
11065    C_bad_argc(c, 3);
11066  }
11067
11068  num = av[ 2 ];
11069
11070  if(num & C_FIXNUM_BIT) {
11071    C_fixnum_to_string(c, av); /* reuse av */
11072  } else if (C_immediatep(num)) {
11073    barf(C_BAD_ARGUMENT_TYPE_ERROR, "number->string", num);
11074  } else if(C_block_header(num) == C_FLONUM_TAG) {
11075    C_flonum_to_string(c, av); /* reuse av */
11076  } else if (C_truep(C_bignump(num))) {
11077    C_integer_to_string(c, av); /* reuse av */
11078  } else {
11079    C_word k = av[ 1 ];
11080    try_extended_number("##sys#extended-number->string", 3, k, num, radix);
11081  }
11082}
11083
11084void C_ccall C_fixnum_to_string(C_word c, C_word *av)
11085{
11086  C_char *p;
11087  C_word *a,
11088    /* self = av[ 0 ] */
11089    k = av[ 1 ],
11090    num = av[ 2 ],
11091    radix = ((c == 3) ? 10 : C_unfix(av[ 3 ])),
11092    neg = ((num & C_INT_SIGN_BIT) ? 1 : 0);
11093
11094  if (radix < 2 || radix > 16) {
11095    barf(C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR, "number->string", C_fix(radix));
11096  }
11097
11098  num = neg ? -C_unfix(num) : C_unfix(num);
11099  p = to_n_nary(num, radix, neg, 0);
11100
11101  num = C_strlen(p);
11102  a = C_alloc((C_bytestowords(num) + 1));
11103  C_kontinue(k, C_string(&a, num, p));
11104}
11105
11106void C_ccall C_flonum_to_string(C_word c, C_word *av)
11107{
11108  C_char *p;
11109  double f, fa, m;
11110  C_word *a,
11111    /* self = av[ 0 ] */
11112    k = av[ 1 ],
11113    num = av[ 2 ],
11114    radix = ((c == 3) ? 10 : C_unfix(av[ 3 ]));
11115
11116  f = C_flonum_magnitude(num);
11117  fa = fabs(f);
11118
11119  /* XXX TODO: Should inexacts be printable in other bases than 10?
11120   * Perhaps output a string starting with #i?
11121   * Right now something like (number->string 1e40 16) results in
11122   * a string that can't be read back using string->number.
11123   */
11124  if((radix < 2) || (radix > 16)){
11125    barf(C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR, "number->string", C_fix(radix));
11126  }
11127
11128  if(f == 0.0 || (C_modf(f, &m) == 0.0 && log2(fa) < C_WORD_SIZE)) { /* Use fast int code */
11129    if(signbit(f)) {
11130      p = to_n_nary((C_uword)-f, radix, 1, 1);
11131    } else {
11132      p = to_n_nary((C_uword)f, radix, 0, 1);
11133    }
11134  } else if(C_isnan(f)) {
11135    p = "+nan.0";
11136  } else if(C_isinf(f)) {
11137    p = f > 0 ? "+inf.0" : "-inf.0";
11138  } else { /* Doesn't fit an unsigned int and not "special"; use system libc */
11139    C_snprintf(buffer, STRING_BUFFER_SIZE, C_text("%.*g"),
11140               /* XXX: flonum_print_precision */
11141               (int)C_unfix(C_get_print_precision()), f);
11142    buffer[STRING_BUFFER_SIZE-1] = '\0';
11143
11144    if((p = C_strpbrk(buffer, C_text(".eE"))) == NULL) {
11145      /* Already checked for these, so shouldn't happen */
11146      assert(*buffer != 'i'); /* "inf" */
11147      assert(*buffer != 'n'); /* "nan" */
11148      /* Ensure integral flonums w/o expt are always terminated by .0 */
11149#if defined(HAVE_STRLCAT) || !defined(C_strcat)
11150      C_strlcat(buffer, C_text(".0"), sizeof(buffer));
11151#else
11152      C_strcat(buffer, C_text(".0"));
11153#endif
11154    }
11155    p = buffer;
11156  }
11157
11158  radix = C_strlen(p);
11159  a = C_alloc((C_bytestowords(radix) + 1));
11160  radix = C_string(&a, radix, p);
11161  C_kontinue(k, radix);
11162}
11163
11164void C_ccall C_integer_to_string(C_word c, C_word *av)
11165{
11166  C_word
11167    /* self = av[ 0 ] */
11168    k = av[ 1 ],
11169    num = av[ 2 ],
11170    radix = ((c == 3) ? 10 : C_unfix(av[ 3 ]));
11171
11172  if (num & C_FIXNUM_BIT) {
11173    C_fixnum_to_string(4, av); /* reuse av */
11174  } else {
11175    int len, radix_shift;
11176    size_t nbits;
11177
11178    if ((radix < 2) || (radix > 16)) {
11179      barf(C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR, "number->string", C_fix(radix));
11180    }
11181
11182    /* Approximation of the number of radix digits we'll need.  We try
11183     * to be as precise as possible to avoid memmove overhead at the end
11184     * of the non-powers of two part of the conversion procedure, which
11185     * we may need to do because we write strings back-to-front, and
11186     * pointers must be aligned (even for byte blocks).
11187     */
11188    len = C_bignum_size(num)-1;
11189
11190    nbits  = (size_t)len * C_BIGNUM_DIGIT_LENGTH;
11191    nbits += C_ilen(C_bignum_digits(num)[len]);
11192
11193    len = C_ilen(radix)-1;
11194    len = (nbits + len - 1) / len;
11195    len += C_bignum_negativep(num) ? 1 : 0; /* Add space for negative sign */
11196    
11197    radix_shift = C_ilen(radix) - 1;
11198    if (len > C_RECURSIVE_TO_STRING_THRESHOLD &&
11199        /* The power of two fast path is much faster than recursion */
11200        ((C_uword)1 << radix_shift) != radix) {
11201      try_extended_number("##sys#integer->string/recursive",
11202                          4, k, num, C_fix(radix), C_fix(len));
11203    } else {
11204      C_word kab[C_SIZEOF_CLOSURE(4)], *ka = kab, kav[6];
11205
11206      kav[ 0 ] = (C_word)NULL;   /* No "self" closure */
11207      kav[ 1 ] = C_closure(&ka, 4, (C_word)bignum_to_str_2,
11208                           k, num, C_fix(radix));
11209      kav[ 2 ] = C_fix(len);
11210      kav[ 3 ] = C_SCHEME_TRUE; /* Byte vector */
11211      kav[ 4 ] = C_SCHEME_FALSE; /* No initialization */
11212      kav[ 5 ] = C_SCHEME_FALSE; /* Don't align at 8 bytes */
11213      C_allocate_vector(6, kav);
11214    }
11215  }
11216}
11217
11218static void bignum_to_str_2(C_word c, C_word *av)
11219{
11220  static char *characters = "0123456789abcdef";
11221  C_word
11222    self = av[ 0 ],
11223    string = av[ 1 ],
11224    k = C_block_item(self, 1),
11225    bignum = C_block_item(self, 2),
11226    radix = C_unfix(C_block_item(self, 3));
11227  char
11228    *buf = C_c_string(string),
11229    *index = buf + C_header_size(string) - 1;
11230  int radix_shift,
11231    negp = (C_bignum_negativep(bignum) ? 1 : 0);
11232
11233  radix_shift = C_ilen(radix) - 1;
11234  if (((C_uword)1 << radix_shift) == radix) { /* Power of two? */
11235    int radix_mask = radix - 1, big_digit_len = 0, radix_digit;
11236    C_uword *scan, *end, big_digit = 0;
11237
11238    scan = C_bignum_digits(bignum);
11239    end = scan + C_bignum_size(bignum);
11240
11241    while (scan < end) {
11242      /* If radix isn't an exact divisor of digit length, handle overlap */
11243      if (big_digit_len == 0) {
11244        big_digit = *scan++;
11245        big_digit_len = C_BIGNUM_DIGIT_LENGTH;
11246      } else {
11247        assert(index >= buf);
11248	radix_digit = big_digit;
11249        big_digit = *scan++;
11250	radix_digit |= ((unsigned int)big_digit << big_digit_len) & radix_mask;
11251        *index-- = characters[radix_digit];
11252	big_digit >>= (radix_shift - big_digit_len);
11253        big_digit_len = C_BIGNUM_DIGIT_LENGTH - (radix_shift - big_digit_len);
11254      }
11255
11256      while(big_digit_len >= radix_shift && index >= buf) {
11257	radix_digit = big_digit & radix_mask;
11258        *index-- = characters[radix_digit];
11259	big_digit >>= radix_shift;
11260	big_digit_len -= radix_shift;
11261      }
11262    }
11263
11264    assert(big_digit < radix);
11265
11266    /* Final digit (like overlap at start of while loop) */
11267    if (big_digit) *index-- = characters[big_digit];
11268
11269    if (negp) {
11270      /* Loop above might've overwritten sign position with a zero */
11271      if (*(index+1) == '0') *(index+1) = '-';
11272      else *index-- = '-';
11273    }
11274
11275    /* Length calculation is always precise for radix powers of two. */
11276    assert(index == buf-1);
11277  } else {
11278    C_uword base, *start, *scan, big_digit;
11279    C_word working_copy;
11280    int steps, i;
11281
11282    working_copy = allocate_tmp_bignum(C_fix(C_bignum_size(bignum)),
11283                                       C_mk_bool(negp), C_SCHEME_FALSE);
11284    bignum_digits_destructive_copy(working_copy, bignum);
11285
11286    start = C_bignum_digits(working_copy);
11287
11288    scan = start + C_bignum_size(bignum);
11289    /* Calculate the largest power of radix that fits a halfdigit:
11290     * steps = log10(2^halfdigit_bits), base = 10^steps
11291     */
11292    for(steps = 0, base = radix; C_fitsinbignumhalfdigitp(base); base *= radix)
11293      steps++;
11294
11295    base /= radix; /* Back down: we overshot in the loop */
11296
11297    while (scan > start) {
11298      big_digit = bignum_digits_destructive_scale_down(start, scan, base);
11299
11300      if (*(scan-1) == 0) scan--; /* Adjust if we exhausted the highest digit */
11301
11302      for(i = 0; i < steps && index >= buf; ++i) {
11303	C_word tmp = big_digit / radix;
11304        *index-- = characters[big_digit - (tmp*radix)]; /* big_digit % radix */
11305        big_digit = tmp;
11306      }
11307    }
11308    assert(index >= buf-1);
11309    free_tmp_bignum(working_copy);
11310
11311    /* Move index onto first nonzero digit.  We're writing a bignum
11312       here: it can't consist of only zeroes. */
11313    while(*++index == '0');
11314  
11315    if (negp) *--index = '-';
11316  
11317    /* Shorten with distance between start and index. */
11318    if (buf != index) {
11319      i = C_header_size(string) - (index - buf);
11320      C_memmove(buf, index, i); /* Move start of number to beginning. */
11321      C_block_header(string) = C_STRING_TYPE | i; /* Mutate strlength. */
11322    }
11323  }
11324
11325  C_kontinue(k, string);
11326}
11327
11328
11329void C_ccall C_make_structure(C_word c, C_word *av)
11330{
11331  C_word
11332    /* closure = av[ 0 ] */
11333    k = av[ 1 ],
11334    type = av[ 2 ],
11335    size = c - 3,
11336    *s, s0;
11337
11338  if(!C_demand(size + 2))
11339    C_save_and_reclaim((void *)C_make_structure, c, av);
11340
11341  s = C_alloc(C_SIZEOF_STRUCTURE(size + 1)),
11342  s0 = (C_word)s;
11343  *(s++) = C_STRUCTURE_TYPE | (size + 1);
11344  *(s++) = type;
11345  av += 3;
11346
11347  while(size--)
11348    *(s++) = *(av++);
11349
11350  C_kontinue(k, s0);
11351}
11352
11353
11354void C_ccall C_make_symbol(C_word c, C_word *av)
11355{
11356  C_word
11357    /* closure = av[ 0 ] */
11358    k = av[ 1 ],
11359    name = av[ 2 ],
11360    ab[ C_SIZEOF_SYMBOL ], 
11361    *a = ab,
11362    s0 = (C_word)a;
11363
11364  *(a++) = C_SYMBOL_TYPE | (C_SIZEOF_SYMBOL - 1);
11365  *(a++) = C_SCHEME_UNBOUND;
11366  *(a++) = name;
11367  *a = C_SCHEME_END_OF_LIST;
11368  C_kontinue(k, s0);
11369}
11370
11371
11372void C_ccall C_make_pointer(C_word c, C_word *av)
11373{
11374  C_word
11375    /* closure = av[ 0 ] */
11376    k = av[ 1 ],
11377    ab[ 2 ], 
11378    *a = ab,
11379    p;
11380
11381  p = C_mpointer(&a, NULL);
11382  C_kontinue(k, p);
11383}
11384
11385
11386void C_ccall C_make_tagged_pointer(C_word c, C_word *av)
11387{
11388  C_word
11389    /* closure = av[ 0 ] */
11390    k = av[ 1 ],
11391    tag = av[ 2 ],
11392    ab[ 3 ],
11393    *a = ab,
11394    p;
11395
11396  p = C_taggedmpointer(&a, tag, NULL);
11397  C_kontinue(k, p);
11398}
11399
11400
11401void C_ccall C_ensure_heap_reserve(C_word c, C_word *av) 
11402{
11403  C_word
11404    /* closure = av[ 0 ] */
11405    k = av[ 1 ],
11406    n = av[ 2 ],
11407    *p;
11408  
11409  C_save(k);
11410
11411  if(!C_demand(C_bytestowords(C_unfix(n))))
11412    C_reclaim((void *)generic_trampoline, 1);
11413
11414  p = C_temporary_stack;
11415  C_temporary_stack = C_temporary_stack_bottom;
11416  generic_trampoline(0, p);
11417}
11418
11419
11420void C_ccall generic_trampoline(C_word c, C_word *av)
11421{
11422  C_word k = av[ 0 ];
11423
11424  C_kontinue(k, C_SCHEME_UNDEFINED);
11425}
11426
11427
11428void C_ccall C_return_to_host(C_word c, C_word *av)
11429{
11430  C_word
11431    /* closure = av[ 0 ] */
11432    k = av[ 1 ];
11433
11434  return_to_host = 1;
11435  C_save(k);
11436  C_reclaim((void *)generic_trampoline, 1);
11437}
11438
11439
11440void C_ccall C_get_symbol_table_info(C_word c, C_word *av)
11441{
11442  C_word
11443    /* closure = av[ 0 ] */
11444    k = av[ 1 ];
11445  double d1, d2;
11446  int n = 0, total;
11447  C_SYMBOL_TABLE *stp;
11448  C_word
11449    x, y,
11450    ab[ WORDS_PER_FLONUM * 2 + C_SIZEOF_VECTOR(4) ],
11451    *a = ab;
11452
11453  for(stp = symbol_table_list; stp != NULL; stp = stp->next)
11454    ++n;
11455  
11456  d1 = compute_symbol_table_load(&d2, &total);
11457  x = C_flonum(&a, d1);		/* load */
11458  y = C_flonum(&a, d2);		/* avg bucket length */
11459  C_kontinue(k, C_vector(&a, 4, x, y, C_fix(total), C_fix(n)));
11460}
11461
11462
11463void C_ccall C_get_memory_info(C_word c, C_word *av)
11464{
11465  C_word
11466    /* closure = av[ 0 ] */
11467    k = av[ 1 ],
11468    ab[ C_SIZEOF_VECTOR(2) ],
11469    *a = ab;
11470
11471  C_kontinue(k, C_vector(&a, 2, C_fix(heap_size), C_fix(stack_size)));
11472}
11473
11474
11475void C_ccall C_context_switch(C_word c, C_word *av)
11476{
11477  C_word
11478    /* closure = av[ 0 ] */
11479    state = av[ 2 ],
11480    n = C_header_size(state) - 1,
11481    adrs = C_block_item(state, 0),
11482    *av2;
11483  C_proc tp = (C_proc)C_block_item(adrs,0);
11484
11485  /* Copy argvector because it may be mutated in-place.  The state
11486   * vector should not be re-invoked(?), but it can be kept alive
11487   * during GC, so the mutated argvector/state slots may turn stale.
11488   */
11489  av2 = C_alloc(n);
11490  C_memcpy(av2, (C_word *)state + 2, n * sizeof(C_word));
11491  tp(n, av2);
11492}
11493
11494
11495void C_ccall C_peek_signed_integer(C_word c, C_word *av)
11496{
11497  C_word
11498    /* closure = av[ 0 ] */
11499    k = av[ 1 ],
11500    v = av[ 2 ],
11501    index = av[ 3 ],
11502    x = C_block_item(v, C_unfix(index)),
11503    ab[C_SIZEOF_BIGNUM(1)], *a = ab;
11504
11505  C_uword num = ((C_word *)C_data_pointer(v))[ C_unfix(index) ];
11506
11507  C_kontinue(k, C_int_to_num(&a, num));
11508}
11509
11510
11511void C_ccall C_peek_unsigned_integer(C_word c, C_word *av)
11512{
11513  C_word
11514    /* closure = av[ 0 ] */
11515    k = av[ 1 ],
11516    v = av[ 2 ],
11517    index = av[ 3 ],
11518    x = C_block_item(v, C_unfix(index)),
11519    ab[C_SIZEOF_BIGNUM(1)], *a = ab;
11520
11521  C_uword num = ((C_word *)C_data_pointer(v))[ C_unfix(index) ];
11522
11523  C_kontinue(k, C_unsigned_int_to_num(&a, num));
11524}
11525
11526void C_ccall C_peek_int64(C_word c, C_word *av)
11527{
11528  C_word
11529    /* closure = av[ 0 ] */
11530    k = av[ 1 ],
11531    v = av[ 2 ],
11532    index = av[ 3 ],
11533    x = C_block_item(v, C_unfix(index)),
11534    ab[C_SIZEOF_BIGNUM(2)], *a = ab;
11535
11536  C_s64 num = ((C_s64 *)C_data_pointer(v))[ C_unfix(index) ];
11537
11538  C_kontinue(k, C_int64_to_num(&a, num));
11539}
11540
11541
11542void C_ccall C_peek_uint64(C_word c, C_word *av)
11543{
11544  C_word
11545    /* closure = av[ 0 ] */
11546    k = av[ 1 ],
11547    v = av[ 2 ],
11548    index = av[ 3 ],
11549    x = C_block_item(v, C_unfix(index)),
11550    ab[C_SIZEOF_BIGNUM(2)], *a = ab;
11551
11552  C_u64 num = ((C_u64 *)C_data_pointer(v))[ C_unfix(index) ];
11553
11554  C_kontinue(k, C_uint64_to_num(&a, num));
11555}
11556
11557
11558void C_ccall C_decode_seconds(C_word c, C_word *av)
11559{
11560  C_word
11561    /* closure = av[ 0 ] */
11562    k = av[ 1 ],
11563    secs = av[ 2 ],
11564    mode = av[ 3 ];
11565  time_t tsecs;
11566  struct tm *tmt;
11567  C_word
11568    ab[ C_SIZEOF_VECTOR(10) ], 
11569    *a = ab,
11570    info;
11571
11572  tsecs = (time_t)C_num_to_int64(secs);
11573  
11574  if(mode == C_SCHEME_FALSE) tmt = C_localtime(&tsecs);
11575  else tmt = C_gmtime(&tsecs);
11576
11577  if(tmt  == NULL)
11578    C_kontinue(k, C_SCHEME_FALSE);
11579  
11580  info = C_vector(&a, 10, C_fix(tmt->tm_sec), C_fix(tmt->tm_min), C_fix(tmt->tm_hour),
11581		  C_fix(tmt->tm_mday), C_fix(tmt->tm_mon), C_fix(tmt->tm_year),
11582		  C_fix(tmt->tm_wday), C_fix(tmt->tm_yday),
11583		  tmt->tm_isdst > 0 ? C_SCHEME_TRUE : C_SCHEME_FALSE,
11584#ifdef C_GNU_ENV
11585                  /* negative for west of UTC, but we want positive */
11586		  C_fix(-tmt->tm_gmtoff)
11587#elif defined(__CYGWIN__) || defined(__MINGW32__) || defined(_WIN32) || defined(__WINNT__)
11588                  C_fix(mode == C_SCHEME_FALSE ? _timezone : 0) /* does not account for DST */
11589#else
11590                  C_fix(mode == C_SCHEME_FALSE ? timezone : 0)  /* does not account for DST */
11591#endif
11592		  );
11593  C_kontinue(k, info);
11594}
11595
11596
11597void C_ccall C_machine_byte_order(C_word c, C_word *av)
11598{
11599  C_word
11600    /* closure = av[ 0 ] */
11601    k = av[ 1 ];
11602  char *str;
11603  C_word *a, s;
11604
11605  if(c != 2) C_bad_argc(c, 2);
11606
11607#if defined(C_MACHINE_BYTE_ORDER)
11608  str = C_MACHINE_BYTE_ORDER;
11609#else
11610  C_cblock
11611    static C_word one_two_three = 123;
11612    str = (*((C_char *)&one_two_three) != 123) ? "big-endian" : "little-endian";
11613  C_cblockend;
11614#endif
11615
11616  a = C_alloc(2 + C_bytestowords(strlen(str)));
11617  s = C_string2(&a, str);
11618
11619  C_kontinue(k, s);
11620}
11621
11622
11623void C_ccall C_machine_type(C_word c, C_word *av)
11624{
11625  C_word 
11626    /* closure = av[ 0 ] */
11627    k = av[ 1 ],
11628    *a, s;
11629
11630  if(c != 2) C_bad_argc(c, 2);
11631
11632  a = C_alloc(2 + C_bytestowords(strlen(C_MACHINE_TYPE)));
11633  s = C_string2(&a, C_MACHINE_TYPE);
11634  
11635  C_kontinue(k, s);
11636}
11637
11638
11639void C_ccall C_software_type(C_word c, C_word *av)
11640{
11641  C_word
11642    /* closure = av[ 0 ] */
11643    k = av[ 1 ],
11644    *a, s;
11645
11646  if(c != 2) C_bad_argc(c, 2);
11647
11648  a = C_alloc(2 + C_bytestowords(strlen(C_SOFTWARE_TYPE)));
11649  s = C_string2(&a, C_SOFTWARE_TYPE);
11650
11651 C_kontinue(k, s);
11652}
11653
11654
11655void C_ccall C_build_platform(C_word c, C_word *av)
11656{
11657  C_word
11658    /* closure = av[ 0 ] */
11659    k = av[ 1 ],
11660    *a, s;
11661
11662  if(c != 2) C_bad_argc(c, 2);
11663
11664  a = C_alloc(2 + C_bytestowords(strlen(C_BUILD_PLATFORM)));
11665  s = C_string2(&a, C_BUILD_PLATFORM);
11666
11667 C_kontinue(k, s);
11668}
11669
11670
11671void C_ccall C_software_version(C_word c, C_word *av)
11672{
11673  C_word
11674    /* closure = av[ 0 ] */
11675    k = av[ 1 ],
11676    *a, s;
11677
11678  if(c != 2) C_bad_argc(c, 2);
11679
11680  a = C_alloc(2 + C_bytestowords(strlen(C_SOFTWARE_VERSION)));
11681  s = C_string2(&a, C_SOFTWARE_VERSION);
11682
11683 C_kontinue(k, s);
11684}
11685
11686
11687/* Register finalizer: */
11688
11689void C_ccall C_register_finalizer(C_word c, C_word *av)
11690{
11691  C_word
11692    /* closure = av[ 0 ]) */
11693    k = av[ 1 ],
11694    x = av[ 2 ],
11695    proc = av[ 3 ];
11696
11697  if(C_immediatep(x) ||
11698     (!C_in_stackp(x) && !C_in_heapp(x) && !C_in_scratchspacep(x)))
11699    C_kontinue(k, x); /* not GCable */
11700
11701  C_do_register_finalizer(x, proc);
11702  C_kontinue(k, x);
11703}
11704
11705
11706/*XXX could this be made static? is it used in eggs somewhere? 
11707  if not, declare as fcall/regparm (and static, remove from chicken.h)
11708 */
11709void C_ccall C_do_register_finalizer(C_word x, C_word proc)
11710{
11711  C_word *ptr;
11712  int n, i;
11713  FINALIZER_NODE *flist;
11714
11715  if(finalizer_free_list == NULL) {
11716    if((flist = (FINALIZER_NODE *)C_malloc(sizeof(FINALIZER_NODE))) == NULL)
11717      panic(C_text("out of memory - cannot allocate finalizer node"));
11718
11719    ++allocated_finalizer_count;
11720  }
11721  else {
11722    flist = finalizer_free_list;
11723    finalizer_free_list = flist->next;
11724  }
11725
11726  if(finalizer_list != NULL) finalizer_list->previous = flist;
11727
11728  flist->previous = NULL;
11729  flist->next = finalizer_list;
11730  finalizer_list = flist;
11731
11732  if(C_in_stackp(x)) C_mutate_slot(&flist->item, x);
11733  else flist->item = x;
11734
11735  if(C_in_stackp(proc)) C_mutate_slot(&flist->finalizer, proc);
11736  else flist->finalizer = proc;
11737
11738  ++live_finalizer_count;
11739}
11740
11741
11742/*XXX same here */
11743int C_do_unregister_finalizer(C_word x)
11744{
11745  int n;
11746  FINALIZER_NODE *flist;
11747
11748  for(flist = finalizer_list; flist != NULL; flist = flist->next) {
11749    if(flist->item == x) {
11750      if(flist->previous == NULL) finalizer_list = flist->next;
11751      else flist->previous->next = flist->next;
11752
11753      return 1;
11754    }
11755  }
11756
11757  return 0;
11758}
11759
11760
11761/* Dynamic loading of shared objects: */
11762
11763void C_ccall C_set_dlopen_flags(C_word c, C_word *av)
11764{
11765  C_word
11766    /* closure = av[ 0 ] */
11767    k = av[ 1 ],
11768    now = av[ 2 ],
11769    global = av[ 3 ];
11770
11771#if !defined(NO_DLOAD2) && defined(HAVE_DLFCN_H)
11772  dlopen_flags = (C_truep(now) ? RTLD_NOW : RTLD_LAZY) | (C_truep(global) ? RTLD_GLOBAL : RTLD_LOCAL);
11773#endif
11774  C_kontinue(k, C_SCHEME_UNDEFINED);
11775}
11776
11777
11778void C_ccall C_dload(C_word c, C_word *av)
11779{
11780  C_word
11781    /* closure = av[ 0 ] */
11782    k = av[ 1 ],
11783    name = av[ 2 ],
11784    entry = av[ 3 ];
11785
11786#if !defined(NO_DLOAD2) && (defined(HAVE_DLFCN_H) || defined(HAVE_DL_H) || (defined(HAVE_LOADLIBRARY) && defined(HAVE_GETPROCADDRESS)))
11787  /* Force minor GC: otherwise the lf may contain pointers to stack-data
11788     (stack allocated interned symbols, for example) */
11789  C_save_and_reclaim_args((void *)dload_2, 3, k, name, entry);
11790#endif
11791
11792  C_kontinue(k, C_SCHEME_FALSE);
11793}
11794
11795
11796#ifdef DLOAD_2_DEFINED
11797# undef DLOAD_2_DEFINED
11798#endif
11799
11800#if !defined(NO_DLOAD2) && defined(HAVE_DL_H) && !defined(DLOAD_2_DEFINED)
11801# ifdef __hpux__
11802#  define DLOAD_2_DEFINED
11803void C_ccall dload_2(C_word c, C_word *av0)
11804{
11805  void *handle, *p;
11806  C_word
11807    entry = av0[ 0 ],
11808    name = av0[ 1 ],
11809    k = av0[ 2 ],,
11810    av[ 2 ];
11811  C_char *mname = (C_char *)C_data_pointer(name);
11812
11813  /*
11814   * C_fprintf(C_stderr,
11815   *   "shl_loading %s : %s\n",
11816   *   (char *) C_data_pointer(name),
11817   *   (char *) C_data_pointer(entry));
11818   */
11819
11820  if ((handle = (void *) shl_load(mname,
11821				  BIND_IMMEDIATE | DYNAMIC_PATH,
11822				  0L)) != NULL) {
11823    shl_t shl_handle = (shl_t) handle;
11824
11825    /*** This version does not check for C_dynamic_and_unsafe. Fix it. */
11826    if (shl_findsym(&shl_handle, (char *) C_data_pointer(entry), TYPE_PROCEDURE, &p) == 0) {
11827      current_module_name = C_strdup(mname);
11828      current_module_handle = handle;
11829
11830      if(debug_mode) {
11831	C_dbg(C_text("debug"), C_text("loading compiled library %s (" UWORD_FORMAT_STRING ")\n"),
11832	      current_module_name, (C_uword)current_module_handle);
11833      }
11834
11835      av[ 0 ] = C_SCHEME_UNDEFINED;
11836      av[ 1 ] = k;
11837      ((C_proc)p)(2, av);       /* doesn't return */
11838    } else {
11839      C_dlerror = (char *) C_strerror(errno);
11840      shl_unload(shl_handle);
11841    }
11842  } else {
11843    C_dlerror = (char *) C_strerror(errno);
11844  }
11845
11846  C_kontinue(k, C_SCHEME_FALSE);
11847}
11848# endif
11849#endif
11850
11851
11852#if !defined(NO_DLOAD2) && defined(HAVE_DLFCN_H) && !defined(DLOAD_2_DEFINED)
11853# ifndef __hpux__
11854#  define DLOAD_2_DEFINED
11855void C_ccall dload_2(C_word c, C_word *av0)
11856{
11857  void *handle, *p, *p2;
11858  C_word 
11859    entry = av0[ 0 ],
11860    name = av0[ 1 ],
11861    k = av0[ 2 ],
11862    av[ 2 ];
11863  C_char *topname = (C_char *)C_data_pointer(entry);
11864  C_char *mname = (C_char *)C_data_pointer(name);
11865  C_char *tmp;
11866  int tmp_len = 0;
11867
11868  if((handle = C_dlopen(mname, dlopen_flags)) != NULL) {
11869    if((p = C_dlsym(handle, topname)) == NULL) {
11870      tmp_len = C_strlen(topname) + 2;
11871      tmp = (C_char *)C_malloc(tmp_len);
11872
11873      if(tmp == NULL)
11874	panic(C_text("out of memory - cannot allocate toplevel name string"));
11875
11876      C_strlcpy(tmp, C_text("_"), tmp_len);
11877      C_strlcat(tmp, topname, tmp_len);
11878      p = C_dlsym(handle, tmp);
11879      C_free(tmp);
11880    }
11881
11882    if(p != NULL) {
11883      current_module_name = C_strdup(mname);
11884      current_module_handle = handle;
11885
11886      if(debug_mode) {
11887	C_dbg(C_text("debug"), C_text("loading compiled library %s (" UWORD_FORMAT_STRING ")\n"),
11888	      current_module_name, (C_uword)current_module_handle);
11889      }
11890
11891      av[ 0 ] = C_SCHEME_UNDEFINED;
11892      av[ 1 ] = k;
11893      ((C_proc)p)(2, av); /* doesn't return */
11894    }
11895
11896    C_dlclose(handle);
11897  }
11898  
11899  C_dlerror = (char *)dlerror();
11900  C_kontinue(k, C_SCHEME_FALSE);
11901}
11902# endif
11903#endif
11904
11905
11906#if !defined(NO_DLOAD2) && (defined(HAVE_LOADLIBRARY) && defined(HAVE_GETPROCADDRESS)) && !defined(DLOAD_2_DEFINED)
11907# define DLOAD_2_DEFINED
11908void C_ccall dload_2(C_word c, C_word *av0)
11909{
11910  HINSTANCE handle;
11911  FARPROC p = NULL, p2;
11912  C_word
11913    entry = av0[ 0 ],
11914    name = av0[ 1 ],
11915    k = av0[ 2 ],
11916    av[ 2 ];
11917  C_char *topname = (C_char *)C_data_pointer(entry);
11918  C_char *mname = (C_char *)C_data_pointer(name);
11919
11920  /* cannot use LoadLibrary on non-DLLs, so we use extension checking */
11921  if (C_header_size(name) >= 5) {
11922    char *n = (char*) C_data_pointer(name);
11923    int l = C_header_size(name);
11924    if (C_strncasecmp(".dll", n+l-5, 4) && 
11925	C_strncasecmp(".so", n+l-4, 3))
11926      C_kontinue(k, C_SCHEME_FALSE);
11927  }
11928
11929  if((handle = LoadLibrary(mname)) != NULL) {
11930    if ((p = GetProcAddress(handle, topname)) != NULL) {
11931      current_module_name = C_strdup(mname);
11932      current_module_handle = handle;
11933
11934      if(debug_mode) {
11935	C_dbg(C_text("debug"), C_text("loading compiled library %s (" UWORD_FORMAT_STRING ")\n"),
11936	      current_module_name, (C_uword)current_module_handle);
11937      }
11938
11939      av[ 0 ] = C_SCHEME_UNDEFINED;
11940      av[ 1 ] = k;
11941      ((C_proc)p)(2, av);       /* doesn't return */
11942    }
11943    else FreeLibrary(handle);
11944  }
11945
11946  C_dlerror = (char *) C_strerror(errno);
11947  C_kontinue(k, C_SCHEME_FALSE);
11948}
11949#endif
11950
11951
11952void C_ccall C_become(C_word c, C_word *av) 
11953{
11954  C_word
11955    /* closure = av[ 0 ] */
11956    k = av[ 1 ],
11957    table = av[ 2 ],
11958    tp, x, old, neu, i, *p;
11959
11960  i = forwarding_table_size;
11961  p = forwarding_table;
11962
11963  for(tp = table; tp != C_SCHEME_END_OF_LIST; tp = C_u_i_cdr(tp)) {
11964    x = C_u_i_car(tp);
11965    old = C_u_i_car(x);
11966    neu = C_u_i_cdr(x);
11967
11968    if(i == 0) {
11969      if((forwarding_table = (C_word *)realloc(forwarding_table, (forwarding_table_size + 1) * 4 * sizeof(C_word))) == NULL)
11970	panic(C_text("out of memory - cannot re-allocate forwarding table"));
11971	
11972      i = forwarding_table_size;
11973      p = forwarding_table + forwarding_table_size * 2;
11974      forwarding_table_size *= 2;
11975    }
11976
11977    *(p++) = old;
11978    *(p++) = neu;
11979    --i;
11980  }
11981
11982  *p = 0;
11983  C_fromspace_top = C_fromspace_limit;
11984  C_save_and_reclaim_args((void *)become_2, 1, k);
11985}
11986
11987
11988void C_ccall become_2(C_word c, C_word *av)
11989{
11990  C_word k = av[ 0 ];
11991
11992  *forwarding_table = 0;
11993  C_kontinue(k, C_SCHEME_UNDEFINED);
11994}
11995
11996
11997C_regparm C_word C_fcall
11998C_a_i_cpu_time(C_word **a, int c, C_word buf)
11999{
12000  C_word u, s = C_fix(0);
12001
12002#if defined(C_NONUNIX) || defined(__CYGWIN__)
12003  if(CLOCKS_PER_SEC == 1000) u = clock();
12004  else u = C_uint64_to_num(a, ((C_u64)clock() / CLOCKS_PER_SEC) * 1000);
12005#else
12006  struct rusage ru;
12007
12008  if(C_getrusage(RUSAGE_SELF, &ru) == -1) u = 0;
12009  else {
12010    u = C_uint64_to_num(a, (C_u64)ru.ru_utime.tv_sec * 1000 + ru.ru_utime.tv_usec / 1000);
12011    s = C_uint64_to_num(a, (C_u64)ru.ru_stime.tv_sec * 1000 + ru.ru_stime.tv_usec / 1000);
12012  }
12013#endif
12014
12015  /* buf must not be in nursery */
12016  C_set_block_item(buf, 0, u);
12017  C_set_block_item(buf, 1, s);
12018  return buf;
12019}
12020
12021
12022C_regparm C_word C_fcall C_a_i_make_locative(C_word **a, int c, C_word type, C_word object, C_word index, C_word weak)
12023{
12024  C_word *loc = *a;
12025  int offset, i, in = C_unfix(index);
12026  *a = loc + C_SIZEOF_LOCATIVE;
12027
12028  loc[ 0 ] = C_LOCATIVE_TAG;
12029
12030  switch(C_unfix(type)) {
12031  case C_SLOT_LOCATIVE: in *= sizeof(C_word); break;
12032  case C_U16_LOCATIVE:
12033  case C_S16_LOCATIVE: in *= 2; break;
12034  case C_U32_LOCATIVE:
12035  case C_F32_LOCATIVE:
12036  case C_S32_LOCATIVE: in *= 4; break;
12037  case C_U64_LOCATIVE:
12038  case C_S64_LOCATIVE:
12039  case C_F64_LOCATIVE: in *= 8; break;
12040  }
12041
12042  offset = in + sizeof(C_header);
12043  loc[ 1 ] = object + offset;
12044  loc[ 2 ] = C_fix(offset);
12045  loc[ 3 ] = type;
12046  loc[ 4 ] = C_truep(weak) ? C_SCHEME_FALSE : object;
12047
12048  return (C_word)loc;
12049}
12050
12051C_regparm C_word C_fcall C_a_i_locative_ref(C_word **a, int c, C_word loc)
12052{
12053  C_word *ptr;
12054
12055  if(C_immediatep(loc) || C_block_header(loc) != C_LOCATIVE_TAG)
12056    barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-ref", loc);
12057
12058  ptr = (C_word *)C_block_item(loc, 0);
12059
12060  if(ptr == NULL) barf(C_LOST_LOCATIVE_ERROR, "locative-ref", loc);
12061
12062  switch(C_unfix(C_block_item(loc, 2))) {
12063  case C_SLOT_LOCATIVE: return *ptr;
12064  case C_CHAR_LOCATIVE: return C_make_character(*((char *)ptr));
12065  case C_U8_LOCATIVE: return C_fix(*((unsigned char *)ptr));
12066  case C_S8_LOCATIVE: return C_fix(*((char *)ptr));
12067  case C_U16_LOCATIVE: return C_fix(*((unsigned short *)ptr));
12068  case C_S16_LOCATIVE: return C_fix(*((short *)ptr));
12069  case C_U32_LOCATIVE: return C_unsigned_int_to_num(a, *((C_u32 *)ptr));
12070  case C_S32_LOCATIVE: return C_int_to_num(a, *((C_s32 *)ptr));
12071  case C_U64_LOCATIVE: return C_uint64_to_num(a, *((C_u64 *)ptr));
12072  case C_S64_LOCATIVE: return C_int64_to_num(a, *((C_s64 *)ptr));
12073  case C_F32_LOCATIVE: return C_flonum(a, *((float *)ptr));
12074  case C_F64_LOCATIVE: return C_flonum(a, *((double *)ptr));
12075  default: panic(C_text("bad locative type"));
12076  }
12077}
12078
12079C_regparm C_word C_fcall C_i_locative_set(C_word loc, C_word x)
12080{
12081  C_word *ptr, val;
12082
12083  if(C_immediatep(loc) || C_block_header(loc) != C_LOCATIVE_TAG)
12084    barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", loc);
12085
12086  ptr = (C_word *)C_block_item(loc, 0);
12087
12088  if(ptr == NULL)
12089    barf(C_LOST_LOCATIVE_ERROR, "locative-set!", loc);
12090
12091  switch(C_unfix(C_block_item(loc, 2))) {
12092  case C_SLOT_LOCATIVE: C_mutate(ptr, x); break;
12093
12094  case C_CHAR_LOCATIVE:
12095    if((x & C_IMMEDIATE_TYPE_BITS) != C_CHARACTER_BITS)
12096      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12097      
12098    *((char *)ptr) = C_character_code(x); 
12099    break;
12100
12101  case C_U8_LOCATIVE: 
12102    if((x & C_FIXNUM_BIT) == 0)
12103      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12104
12105    *((unsigned char *)ptr) = C_unfix(x); 
12106    break;
12107
12108  case C_S8_LOCATIVE: 
12109    if((x & C_FIXNUM_BIT) == 0)
12110      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12111    
12112    *((char *)ptr) = C_unfix(x); 
12113    break;
12114
12115  case C_U16_LOCATIVE: 
12116    if((x & C_FIXNUM_BIT) == 0)
12117      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12118
12119    *((unsigned short *)ptr) = C_unfix(x); 
12120    break;
12121
12122  case C_S16_LOCATIVE: 
12123    if((x & C_FIXNUM_BIT) == 0)
12124      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12125
12126    *((short *)ptr) = C_unfix(x); 
12127    break;
12128
12129  case C_U32_LOCATIVE: 
12130    if(!C_truep(C_i_exact_integerp(x)))
12131      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12132
12133    *((C_u32 *)ptr) = C_num_to_unsigned_int(x); 
12134    break;
12135
12136  case C_S32_LOCATIVE: 
12137    if(!C_truep(C_i_exact_integerp(x)))
12138      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12139    
12140    *((C_s32 *)ptr) = C_num_to_int(x); 
12141    break;
12142
12143  case C_U64_LOCATIVE: 
12144    if(!C_truep(C_i_exact_integerp(x)))
12145      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12146
12147    *((C_u64 *)ptr) = C_num_to_uint64(x); 
12148    break;
12149
12150  case C_S64_LOCATIVE: 
12151    if(!C_truep(C_i_exact_integerp(x)))
12152      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12153    
12154    *((C_s64 *)ptr) = C_num_to_int64(x); 
12155    break;
12156
12157  case C_F32_LOCATIVE: 
12158    if(C_immediatep(x) || C_block_header(x) != C_FLONUM_TAG)
12159      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12160    
12161    *((float *)ptr) = C_flonum_magnitude(x); 
12162    break;
12163
12164  case C_F64_LOCATIVE: 
12165    if(C_immediatep(x) || C_block_header(x) != C_FLONUM_TAG)
12166      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12167    
12168    *((double *)ptr) = C_flonum_magnitude(x); 
12169    break;
12170
12171  default: panic(C_text("bad locative type"));
12172  }
12173
12174  return C_SCHEME_UNDEFINED;
12175}
12176
12177
12178C_regparm C_word C_fcall C_i_locative_to_object(C_word loc)
12179{
12180  C_word *ptr;
12181
12182  if(C_immediatep(loc) || C_block_header(loc) != C_LOCATIVE_TAG)
12183    barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative->object", loc);
12184
12185  ptr = (C_word *)C_block_item(loc, 0);
12186
12187  if(ptr == NULL) return C_SCHEME_FALSE;
12188  else return (C_word)ptr - C_unfix(C_block_item(loc, 1));
12189}
12190
12191
12192C_regparm C_word C_fcall C_i_locative_index(C_word loc)
12193{
12194  int bytes;
12195
12196  if(C_immediatep(loc) || C_block_header(loc) != C_LOCATIVE_TAG)
12197    barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-index", loc);
12198
12199  bytes = C_unfix(C_block_item(loc, 1)) - sizeof(C_header);
12200
12201  switch(C_unfix(C_block_item(loc, 2))) {
12202  case C_SLOT_LOCATIVE: return C_fix(bytes/sizeof(C_word)); break;
12203
12204  case C_CHAR_LOCATIVE:
12205  case C_U8_LOCATIVE:
12206  case C_S8_LOCATIVE: return C_fix(bytes); break;
12207
12208  case C_U16_LOCATIVE:
12209  case C_S16_LOCATIVE: return C_fix(bytes/2); break;
12210
12211  case C_U32_LOCATIVE:
12212  case C_S32_LOCATIVE:
12213  case C_F32_LOCATIVE: return C_fix(bytes/4); break;
12214
12215  case C_U64_LOCATIVE:
12216  case C_S64_LOCATIVE:
12217  case C_F64_LOCATIVE: return C_fix(bytes/8); break;
12218
12219  default: panic(C_text("bad locative type"));
12220  }
12221}
12222
12223
12224/* GC protection of user-variables: */
12225
12226C_regparm void C_fcall C_gc_protect(C_word **addr, int n)
12227{
12228  int k;
12229
12230  if(collectibles_top + n >= collectibles_limit) {
12231    k = collectibles_limit - collectibles;
12232    collectibles = (C_word **)C_realloc(collectibles, sizeof(C_word *) * k * 2);
12233
12234    if(collectibles == NULL)
12235      panic(C_text("out of memory - cannot allocate GC protection vector"));
12236    
12237    collectibles_top = collectibles + k;
12238    collectibles_limit = collectibles + k * 2;
12239  }
12240
12241  C_memcpy(collectibles_top, addr, n * sizeof(C_word *));
12242  collectibles_top += n;
12243}
12244
12245
12246C_regparm void C_fcall C_gc_unprotect(int n)
12247{
12248  collectibles_top -= n;
12249}
12250
12251
12252/* Map procedure-ptr to id or id to ptr: */
12253
12254C_char *C_lookup_procedure_id(void *ptr)
12255{
12256  LF_LIST *lfl;
12257  C_PTABLE_ENTRY *pt;
12258
12259  for(lfl = lf_list; lfl != NULL; lfl = lfl->next) {
12260    pt = lfl->ptable;
12261
12262    if(pt != NULL) {
12263      while(pt->id != NULL) {
12264	if(pt->ptr == ptr) return pt->id;
12265	else ++pt;
12266      }
12267    }
12268  }
12269
12270  return NULL;
12271}
12272
12273
12274void *C_lookup_procedure_ptr(C_char *id)
12275{
12276  LF_LIST *lfl;
12277  C_PTABLE_ENTRY *pt;
12278
12279  for(lfl = lf_list; lfl != NULL; lfl = lfl->next) {
12280    pt = lfl->ptable;
12281
12282    if(pt != NULL) {
12283      while(pt->id != NULL) {
12284	if(!C_strcmp(id, pt->id)) return pt->ptr;
12285	else ++pt;
12286      }
12287    }
12288  }
12289
12290  return NULL;
12291}
12292
12293
12294void C_ccall C_copy_closure(C_word c, C_word *av)
12295{
12296  C_word
12297    /* closure = av[ 0 ] */
12298    k = av[ 1 ],
12299    proc = av[ 2 ],
12300    *p;
12301  int n = C_header_size(proc);
12302
12303  if(!C_demand(n + 1)) 
12304    C_save_and_reclaim_args((void *)copy_closure_2, 2, proc, k);
12305  else {
12306    C_save(proc);
12307    C_save(k);
12308    p = C_temporary_stack;
12309    C_temporary_stack = C_temporary_stack_bottom;
12310    copy_closure_2(0, p);
12311  }
12312}
12313
12314
12315static void C_ccall copy_closure_2(C_word c, C_word *av)
12316{
12317  C_word 
12318    k = av[ 0 ],
12319    proc = av[ 1 ];
12320  int cells = C_header_size(proc);
12321  C_word
12322    *ptr = C_alloc(C_SIZEOF_CLOSURE(cells)),
12323    *p = ptr;
12324
12325  *(p++) = C_CLOSURE_TYPE | cells;
12326  /* this is only allowed because the storage is freshly allocated: */
12327  C_memcpy_slots(p, C_data_pointer(proc), cells);
12328  C_kontinue(k, (C_word)ptr);
12329}
12330
12331
12332/* Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn */
12333
12334void C_ccall C_call_with_cthulhu(C_word c, C_word *av)
12335{
12336  C_word
12337    proc = av[ 2 ],
12338    *a = C_alloc(C_SIZEOF_CLOSURE(1)),
12339    av2[ 2 ];
12340
12341  av2[ 0 ] = proc;
12342  av2[ 1 ] = C_closure(&a, 1, (C_word)termination_continuation); /* k */
12343  C_do_apply(2, av2);
12344}
12345
12346
12347/* fixnum arithmetic with overflow detection (from "Hacker's Delight" by Hank Warren) 
12348   These routines return #f if the operation failed due to overflow. 
12349 */
12350
12351C_regparm C_word C_fcall C_i_o_fixnum_plus(C_word n1, C_word n2)
12352{
12353  C_word x1, x2, s;
12354  
12355  if((n1 & C_FIXNUM_BIT) == 0 || (n2 & C_FIXNUM_BIT) == 0) return C_SCHEME_FALSE;
12356
12357  x1 = C_unfix(n1);
12358  x2 = C_unfix(n2);
12359  s = x1 + x2;
12360
12361#ifdef C_SIXTY_FOUR
12362  if((((s ^ x1) & (s ^ x2)) >> 62) != 0) return C_SCHEME_FALSE;
12363#else
12364  if((((s ^ x1) & (s ^ x2)) >> 30) != 0) return C_SCHEME_FALSE;
12365#endif
12366  else return C_fix(s);
12367}
12368
12369
12370C_regparm C_word C_fcall C_i_o_fixnum_difference(C_word n1, C_word n2)
12371{
12372  C_word x1, x2, s;
12373
12374  if((n1 & C_FIXNUM_BIT) == 0 || (n2 & C_FIXNUM_BIT) == 0) return C_SCHEME_FALSE;
12375
12376  x1 = C_unfix(n1);
12377  x2 = C_unfix(n2);
12378  s = x1 - x2;
12379  
12380#ifdef C_SIXTY_FOUR
12381  if((((s ^ x1) & ~(s ^ x2)) >> 62) != 0) return C_SCHEME_FALSE;
12382#else
12383  if((((s ^ x1) & ~(s ^ x2)) >> 30) != 0) return C_SCHEME_FALSE;
12384#endif
12385  else return C_fix(s);
12386}
12387
12388
12389C_regparm C_word C_fcall C_i_o_fixnum_times(C_word n1, C_word n2)
12390{
12391  C_word x1, x2;
12392  C_uword x1u, x2u;
12393#ifdef C_SIXTY_FOUR
12394# ifdef C_LLP
12395  C_uword c = 1ULL<<63ULL;
12396# else
12397  C_uword c = 1UL<<63UL;
12398# endif
12399#else
12400  C_uword c = 1UL<<31UL;
12401#endif
12402
12403  if((n1 & C_FIXNUM_BIT) == 0 || (n2 & C_FIXNUM_BIT) == 0) return C_SCHEME_FALSE;
12404
12405  if((n1 & C_INT_SIGN_BIT) == (n2 & C_INT_SIGN_BIT)) --c;
12406
12407  x1 = C_unfix(n1);
12408  x2 = C_unfix(n2);
12409  x1u = x1 < 0 ? -x1 : x1;
12410  x2u = x2 < 0 ? -x2 : x2;
12411
12412  if(x2u != 0 && x1u > (c / x2u)) return C_SCHEME_FALSE;
12413  
12414  x1 = x1 * x2;
12415
12416  if(C_fitsinfixnump(x1)) return C_fix(x1);
12417  else return C_SCHEME_FALSE;
12418}
12419
12420
12421C_regparm C_word C_fcall C_i_o_fixnum_quotient(C_word n1, C_word n2)
12422{
12423  C_word x1, x2;
12424
12425  if((n1 & C_FIXNUM_BIT) == 0 || (n2 & C_FIXNUM_BIT) == 0) return C_SCHEME_FALSE;
12426
12427  x1 = C_unfix(n1);
12428  x2 = C_unfix(n2);
12429
12430  if(x2 == 0)
12431    barf(C_DIVISION_BY_ZERO_ERROR, "fx/?");
12432
12433#ifdef C_SIXTY_FOUR
12434  if(x1 == 0x8000000000000000L && x2 == -1) return C_SCHEME_FALSE;
12435#else
12436  if(x1 == 0x80000000L && x2 == -1) return C_SCHEME_FALSE;
12437#endif
12438
12439  x1 = x1 / x2;
12440
12441  if(C_fitsinfixnump(x1)) return C_fix(x1);
12442  else return C_SCHEME_FALSE;
12443}
12444
12445
12446C_regparm C_word C_fcall C_i_o_fixnum_and(C_word n1, C_word n2)
12447{
12448  C_uword x1, x2, r;
12449
12450  if((n1 & C_FIXNUM_BIT) == 0 || (n2 & C_FIXNUM_BIT) == 0) return C_SCHEME_FALSE;
12451
12452  x1 = C_unfix(n1);
12453  x2 = C_unfix(n2);
12454  r = x1 & x2;
12455  
12456  if(((r & C_INT_SIGN_BIT) >> 1) != (r & C_INT_TOP_BIT)) return C_SCHEME_FALSE;
12457  else return C_fix(r);
12458}
12459
12460
12461C_regparm C_word C_fcall C_i_o_fixnum_ior(C_word n1, C_word n2)
12462{
12463  C_uword x1, x2, r;
12464
12465  if((n1 & C_FIXNUM_BIT) == 0 || (n2 & C_FIXNUM_BIT) == 0) return C_SCHEME_FALSE;
12466
12467  x1 = C_unfix(n1);
12468  x2 = C_unfix(n2);
12469  r = x1 | x2;
12470  
12471  if(((r & C_INT_SIGN_BIT) >> 1) != (r & C_INT_TOP_BIT)) return C_SCHEME_FALSE;
12472  else return C_fix(r);
12473}
12474
12475
12476C_regparm C_word C_fcall C_i_o_fixnum_xor(C_word n1, C_word n2)
12477{
12478  C_uword x1, x2, r;
12479
12480  if((n1 & C_FIXNUM_BIT) == 0 || (n2 & C_FIXNUM_BIT) == 0) return C_SCHEME_FALSE;
12481
12482  x1 = C_unfix(n1);
12483  x2 = C_unfix(n2);
12484  r = x1 ^ x2;
12485  
12486  if(((r & C_INT_SIGN_BIT) >> 1) != (r & C_INT_TOP_BIT)) return C_SCHEME_FALSE;
12487  else return C_fix(r);
12488}
12489
12490
12491/* decoding of literals in compressed format */
12492
12493static C_regparm C_uword C_fcall decode_size(C_char **str)
12494{
12495  C_uchar **ustr = (C_uchar **)str;
12496  C_uword size = (*((*ustr)++) & 0xff) << 16; /* always big endian */
12497
12498  size |= (*((*ustr)++) & 0xff) << 8;
12499  size |= (*((*ustr)++) & 0xff);
12500  return size;
12501}
12502
12503
12504static C_regparm C_word C_fcall decode_literal2(C_word **ptr, C_char **str,
12505						C_word *dest)
12506{
12507  C_ulong bits = *((*str)++) & 0xff;
12508  C_word *data, *dptr, val;
12509  C_uword size;
12510
12511  /* vvv this can be taken out at a later stage (once it works reliably) vvv */
12512  if(bits != 0xfe)
12513    panic(C_text("invalid encoded literal format"));
12514
12515  bits = *((*str)++) & 0xff;
12516  /* ^^^ */
12517
12518#ifdef C_SIXTY_FOUR
12519  bits <<= 24 + 32;
12520#else
12521  bits <<= 24;
12522#endif
12523
12524  if(bits == C_HEADER_BITS_MASK) {		/* special/immediate */
12525    switch(0xff & *((*str)++)) {
12526    case C_BOOLEAN_BITS: 
12527      return C_mk_bool(*((*str)++));
12528
12529    case C_CHARACTER_BITS: 
12530      return C_make_character(decode_size(str));
12531
12532    case C_SCHEME_END_OF_LIST:
12533    case C_SCHEME_UNDEFINED:
12534    case C_SCHEME_END_OF_FILE:
12535    case C_SCHEME_BROKEN_WEAK_PTR:
12536      return (C_word)(*(*str - 1));
12537
12538    case C_FIXNUM_BIT:
12539      val = (C_uword)(signed char)*((*str)++) << 24; /* always big endian */
12540      val |= ((C_uword)*((*str)++) & 0xff) << 16;
12541      val |= ((C_uword)*((*str)++) & 0xff) << 8;
12542      val |= ((C_uword)*((*str)++) & 0xff);
12543      return C_fix(val); 
12544
12545#ifdef C_SIXTY_FOUR
12546    case ((C_STRING_TYPE | C_GC_FORWARDING_BIT) >> (24 + 32)) & 0xff:
12547#else
12548    case ((C_STRING_TYPE | C_GC_FORWARDING_BIT) >> 24) & 0xff:
12549#endif
12550      bits = (C_STRING_TYPE | C_GC_FORWARDING_BIT);
12551      break;
12552
12553    default: 
12554      panic(C_text("invalid encoded special literal"));
12555    }
12556  }
12557
12558#ifndef C_SIXTY_FOUR
12559  if((bits & C_8ALIGN_BIT) != 0) {
12560    /* Align _data_ on 8-byte boundary: */
12561    if(C_aligned8(*ptr)) ++(*ptr);
12562  }
12563#endif
12564
12565  val = (C_word)(*ptr);
12566
12567  if((bits & C_SPECIALBLOCK_BIT) != 0)
12568    panic(C_text("literals with special bit cannot be decoded"));
12569
12570  if(bits == C_FLONUM_TYPE) {
12571    val = C_flonum(ptr, decode_flonum_literal(*str));
12572    while(*((*str)++) != '\0');      /* skip terminating '\0' */
12573    return val;
12574  }
12575
12576  size = decode_size(str);
12577
12578  switch(bits) {
12579  /* This cannot be encoded as a blob due to endianness differences */
12580  case (C_STRING_TYPE | C_GC_FORWARDING_BIT): /* This represents "exact int" */
12581    /* bignums are also allocated statically */
12582    val = C_static_bignum(ptr, size, *str);
12583    *str += size;
12584    break;
12585
12586  case C_STRING_TYPE:
12587    /* strings are always allocated statically */
12588    val = C_static_string(ptr, size, *str);
12589    *str += size;
12590    break;
12591    
12592  case C_BYTEVECTOR_TYPE:
12593    /* ... as are bytevectors (blobs) */
12594    val = C_static_bytevector(ptr, size, *str);
12595    *str += size;
12596    break;
12597    
12598  case C_SYMBOL_TYPE:
12599    if(dest == NULL) 
12600      panic(C_text("invalid literal symbol destination"));
12601
12602    if (**str == '\1') {
12603      val = C_h_intern(dest, size, ++*str);
12604    } else if (**str == '\2') {
12605      val = C_h_intern_kw(dest, size, ++*str);
12606    } else {
12607      C_snprintf(buffer, sizeof(buffer), C_text("Unknown symbol subtype: %d"), (int)**str);
12608      panic(buffer);
12609    }
12610    *str += size;
12611    break;
12612
12613  case C_LAMBDA_INFO_TYPE:
12614    /* lambda infos are always allocated statically */
12615    val = C_static_lambda_info(ptr, size, *str);
12616    *str += size;
12617    break;
12618
12619  default:
12620    *((*ptr)++) = C_make_header(bits, size);
12621    data = *ptr;
12622
12623    if((bits & C_BYTEBLOCK_BIT) != 0) {
12624      C_memcpy(data, *str, size);
12625      size = C_align(size);
12626      *str += size;
12627      *ptr = (C_word *)C_align((C_word)(*ptr) + size);
12628    }
12629    else {
12630      C_word *dptr = *ptr;
12631      *ptr += size;
12632
12633      while(size--) {
12634	*dptr = decode_literal2(ptr, str, dptr);
12635	++dptr;
12636      }
12637    }
12638  }
12639
12640  return val;
12641}
12642
12643
12644C_regparm C_word C_fcall
12645C_decode_literal(C_word **ptr, C_char *str)
12646{
12647  return decode_literal2(ptr, &str, NULL);
12648}
12649
12650
12651void
12652C_use_private_repository(C_char *path)
12653{
12654  private_repository = path;
12655}
12656
12657
12658C_char *
12659C_private_repository_path()
12660{
12661  return private_repository;
12662}
12663
12664C_char *
12665C_executable_pathname() {
12666#ifdef SEARCH_EXE_PATH
12667  return C_main_exe == NULL ? NULL : C_strdup(C_main_exe);
12668#else
12669  return C_resolve_executable_pathname(NULL);
12670#endif
12671}
12672
12673C_char *
12674C_executable_dirname() {
12675  int len;
12676  C_char *path;
12677
12678  if((path = C_executable_pathname()) == NULL)
12679    return NULL;
12680
12681#if defined(_WIN32) && !defined(__CYGWIN__)
12682  for(len = C_strlen(path); len >= 0 && path[len] != '\\'; len--);
12683#else
12684  for(len = C_strlen(path); len >= 0 && path[len] != '/'; len--);
12685#endif
12686
12687  path[len] = '\0';
12688  return path;
12689}
12690
12691C_char *
12692C_resolve_executable_pathname(C_char *fname)
12693{
12694  int n;
12695  C_char *buffer = (C_char *) C_malloc(C_MAX_PATH);
12696
12697  if(buffer == NULL) return NULL;
12698
12699#if defined(__linux__) || defined(__sun)
12700  C_char linkname[64]; /* /proc/<pid>/exe */
12701  pid_t pid = C_getpid();
12702
12703# ifdef __linux__
12704  C_snprintf(linkname, sizeof(linkname), "/proc/%i/exe", pid);
12705# else
12706  C_snprintf(linkname, sizeof(linkname), "/proc/%i/path/a.out", pid); /* SunOS / Solaris */
12707# endif
12708
12709  n = C_readlink(linkname, buffer, C_MAX_PATH);
12710  if(n < 0 || n >= C_MAX_PATH)
12711    goto error;
12712
12713  buffer[n] = '\0';
12714  return buffer;
12715#elif defined(_WIN32) && !defined(__CYGWIN__)
12716  n = GetModuleFileName(NULL, buffer, C_MAX_PATH);
12717  if(n == 0 || n >= C_MAX_PATH)
12718    goto error;
12719
12720  return buffer;
12721#elif defined(C_MACOSX)
12722  C_char buf[C_MAX_PATH];
12723  C_u32 size = C_MAX_PATH;
12724
12725  if(_NSGetExecutablePath(buf, &size) != 0)
12726    goto error;
12727
12728  if(C_realpath(buf, buffer) == NULL)
12729    goto error;
12730
12731  return buffer;
12732#elif defined(__HAIKU__)
12733{
12734  image_info info;
12735  int32 cookie = 0;
12736
12737  while (get_next_image_info(0, &cookie, &info) == B_OK) {
12738    if (info.type == B_APP_IMAGE) {
12739      C_strlcpy(buffer, info.name, C_MAX_PATH);
12740      return buffer;
12741    }
12742  }
12743}
12744#elif defined(SEARCH_EXE_PATH)
12745  int len;
12746  C_char *path, buf[C_MAX_PATH];
12747
12748  /* no name given (execve) */
12749  if(fname == NULL)
12750    goto error;
12751
12752  /* absolute pathname */
12753  if(fname[0] == '/') {
12754    if(C_realpath(fname, buffer) == NULL)
12755      goto error;
12756    else
12757      return buffer;
12758  }
12759
12760  /* current directory */
12761  if(C_strchr(fname, '/') != NULL) {
12762    if(C_getcwd(buffer, C_MAX_PATH) == NULL)
12763      goto error;
12764
12765    n = C_snprintf(buf, C_MAX_PATH, "%s/%s", buffer, fname);
12766    if(n < 0 || n >= C_MAX_PATH)
12767      goto error;
12768
12769    if(C_access(buf, X_OK) == 0) {
12770      if(C_realpath(buf, buffer) == NULL)
12771        goto error;
12772      else
12773        return buffer;
12774    }
12775  }
12776
12777  /* walk PATH */
12778  if((path = C_getenv("PATH")) == NULL)
12779    goto error;
12780
12781  do {
12782    /* check PATH entry length */
12783    len = C_strcspn(path, ":");
12784    if(len == 0 || len >= C_MAX_PATH)
12785      continue;
12786
12787    /* "<path>/<fname>" to buf */
12788    C_strncpy(buf, path, len);
12789    n = C_snprintf(buf + len, C_MAX_PATH - len, "/%s", fname);
12790    if(n < 0 || n + len >= C_MAX_PATH)
12791      continue;
12792
12793    if(C_access(buf, X_OK) != 0)
12794      continue;
12795
12796    /* fname found, resolve links */
12797    if(C_realpath(buf, buffer) != NULL)
12798      return buffer;
12799
12800  /* seek next entry, skip colon */
12801  } while (path += len, *path++);
12802#else
12803# error "Please either define SEARCH_EXE_PATH in Makefile.<platform> or implement C_resolve_executable_pathname for your platform!"
12804#endif
12805
12806error:
12807  C_free(buffer);
12808  return NULL;
12809}
12810
12811C_regparm C_word C_fcall
12812C_i_getprop(C_word sym, C_word prop, C_word def)
12813{
12814  C_word pl = C_symbol_plist(sym);
12815
12816  while(pl != C_SCHEME_END_OF_LIST) {
12817    if(C_block_item(pl, 0) == prop)
12818      return C_u_i_car(C_u_i_cdr(pl));
12819    else pl = C_u_i_cdr(C_u_i_cdr(pl));
12820  }
12821
12822  return def;
12823}
12824
12825
12826C_regparm C_word C_fcall
12827C_putprop(C_word **ptr, C_word sym, C_word prop, C_word val)
12828{
12829  C_word pl = C_symbol_plist(sym);
12830
12831  /* Newly added plist?  Ensure the symbol stays! */
12832  if (pl == C_SCHEME_END_OF_LIST) C_i_persist_symbol(sym);
12833
12834  while(pl != C_SCHEME_END_OF_LIST) {
12835    if(C_block_item(pl, 0) == prop) {
12836      C_mutate(&C_u_i_car(C_u_i_cdr(pl)), val);
12837      return val;
12838    }
12839    else pl = C_u_i_cdr(C_u_i_cdr(pl));
12840  }
12841
12842  pl = C_a_pair(ptr, val, C_symbol_plist(sym));
12843  pl = C_a_pair(ptr, prop, pl);
12844  C_mutate_slot(&C_symbol_plist(sym), pl);
12845  return val;
12846}
12847
12848
12849C_regparm C_word C_fcall
12850C_i_get_keyword(C_word kw, C_word args, C_word def)
12851{
12852  while(!C_immediatep(args)) {
12853    if(C_header_type(args) == C_PAIR_TYPE) {
12854      if(kw == C_u_i_car(args)) {
12855	args = C_u_i_cdr(args);
12856
12857	if(C_immediatep(args) || C_header_type(args) != C_PAIR_TYPE)
12858	  return def;
12859	else return C_u_i_car(args);
12860      }
12861      else {
12862	args = C_u_i_cdr(args);
12863
12864	if(C_immediatep(args) || C_header_type(args) != C_PAIR_TYPE)
12865	  return def;
12866	else args = C_u_i_cdr(args);
12867      }
12868    }
12869  }
12870
12871  return def;
12872}
12873
12874C_word C_i_dump_statistical_profile()
12875{
12876  PROFILE_BUCKET *b, *b2, **bp;
12877  FILE *fp;
12878  C_char *k1, *k2 = NULL;
12879  int n;
12880  double ms;
12881
12882  assert(profiling);
12883  assert(profile_table != NULL);
12884
12885  set_profile_timer(0);
12886
12887  profiling = 0; /* In case a SIGPROF is delivered late */
12888  bp = profile_table;
12889
12890  C_snprintf(buffer, STRING_BUFFER_SIZE, C_text("PROFILE.%d"), C_getpid());
12891
12892  if(debug_mode)
12893    C_dbg(C_text("debug"), C_text("dumping statistical profile to `%s'...\n"), buffer);
12894
12895  fp = C_fopen(buffer, "w");
12896  if (fp == NULL)
12897    panic(C_text("could not write profile!"));
12898
12899  C_fputs(C_text("statistical\n"), fp);
12900  for(n = 0; n < PROFILE_TABLE_SIZE; ++n) {
12901    for(b = bp[ n ]; b != NULL; b = b2) {
12902      b2 = b->next;
12903
12904      k1 = b->key;
12905      C_fputs(C_text("(|"), fp);
12906      /* Dump raw C string as if it were a symbol */
12907      while((k2 = C_strpbrk(k1, C_text("\\|"))) != NULL) {
12908        C_fwrite(k1, 1, k2-k1, fp);
12909        C_fputc('\\', fp);
12910        C_fputc(*k2, fp);
12911        k1 = k2+1;
12912      }
12913      C_fputs(k1, fp);
12914      ms = (double)b->sample_count * (double)profile_frequency / 1000.0;
12915      C_fprintf(fp, C_text("| " UWORD_COUNT_FORMAT_STRING " %lf)\n"),
12916                b->call_count, ms);
12917      C_free(b);
12918    }
12919  }
12920
12921  C_fclose(fp);
12922  C_free(profile_table);
12923  profile_table = NULL;
12924
12925  return C_SCHEME_UNDEFINED;
12926}
12927
12928void C_ccall C_dump_heap_state(C_word c, C_word *av)
12929{
12930  C_word
12931    /* closure = av[ 0 ] */
12932    k = av[ 1 ];
12933
12934  /* make sure heap is compacted */
12935  C_save(k);
12936  C_fromspace_top = C_fromspace_limit; /* force major GC */
12937  C_reclaim((void *)dump_heap_state_2, 1);
12938}
12939
12940
12941static C_ulong
12942hdump_hash(C_word key)
12943{
12944  return (C_ulong)key % HDUMP_TABLE_SIZE;
12945}
12946
12947
12948static void
12949hdump_count(C_word key, int n, int t)
12950{
12951  HDUMP_BUCKET **bp = hdump_table + hdump_hash(key);
12952  HDUMP_BUCKET *b = *bp;
12953
12954  while(b != NULL) {
12955    if(b->key == key) {
12956      b->count += n;
12957      b->total += t;
12958      return;
12959    }
12960    else b = b->next;
12961  }
12962
12963  b = (HDUMP_BUCKET *)C_malloc(sizeof(HDUMP_BUCKET));
12964  
12965  if(b == 0)
12966    panic(C_text("out of memory - can not allocate heap-dump table-bucket"));
12967
12968  b->next = *bp;
12969  b->key = key;
12970  *bp = b;
12971  b->count = n;
12972  b->total = t;
12973}
12974
12975
12976static void C_ccall dump_heap_state_2(C_word c, C_word *av)
12977{
12978  C_word k = av[ 0 ];
12979  HDUMP_BUCKET *b, *b2, **bp;
12980  int n, bytes;
12981  C_byte *scan;
12982  C_SCHEME_BLOCK *sbp;
12983  C_header h;
12984  C_word x, key, *p;
12985  int imm = 0, blk = 0;
12986  
12987  hdump_table = (HDUMP_BUCKET **)C_malloc(HDUMP_TABLE_SIZE * sizeof(HDUMP_BUCKET *));
12988
12989  if(hdump_table == NULL)
12990    panic(C_text("out of memory - can not allocate heap-dump table"));
12991
12992  C_memset(hdump_table, 0, sizeof(HDUMP_BUCKET *) * HDUMP_TABLE_SIZE);
12993
12994  scan = fromspace_start;
12995
12996  while(scan < C_fromspace_top) {
12997    ++blk;
12998    sbp = (C_SCHEME_BLOCK *)scan;
12999
13000    if(*((C_word *)sbp) == ALIGNMENT_HOLE_MARKER) 
13001      sbp = (C_SCHEME_BLOCK *)((C_word *)sbp + 1);
13002
13003    n = C_header_size(sbp);
13004    h = sbp->header;
13005    bytes = (h & C_BYTEBLOCK_BIT) ? n : n * sizeof(C_word);
13006    key = (C_word)(h & C_HEADER_BITS_MASK);
13007    p = sbp->data;
13008
13009    if(key == C_STRUCTURE_TYPE) key = *p;
13010
13011    hdump_count(key, 1, bytes);
13012
13013    if(n > 0 && (h & C_BYTEBLOCK_BIT) == 0) {
13014      if((h & C_SPECIALBLOCK_BIT) != 0) {
13015	--n;
13016	++p;
13017      }
13018
13019      while(n--) {
13020	x = *(p++);
13021
13022	if(C_immediatep(x)) {
13023	  ++imm;
13024
13025	  if((x & C_FIXNUM_BIT) != 0) key = C_fix(1);
13026	  else {
13027	    switch(x & C_IMMEDIATE_TYPE_BITS) {
13028	    case C_BOOLEAN_BITS: key = C_SCHEME_TRUE; break;
13029	    case C_CHARACTER_BITS: key = C_make_character('A'); break;
13030	    default: key = x;
13031	    }
13032	  }
13033
13034	  hdump_count(key, 1, 0);
13035	}
13036      }
13037    }
13038
13039    scan = (C_byte *)sbp + C_align(bytes) + sizeof(C_word);
13040  }
13041
13042  bp = hdump_table;
13043  /* HACK */
13044#define C_WEAK_PAIR_TYPE (C_PAIR_TYPE | C_SPECIALBLOCK_BIT)
13045  
13046  for(n = 0; n < HDUMP_TABLE_SIZE; ++n) {
13047    for(b = bp[ n ]; b != NULL; b = b2) {
13048      b2 = b->next;
13049
13050      switch(b->key) {
13051      case C_fix(1): C_fprintf(C_stderr,                 C_text("fixnum         ")); break;
13052      case C_SCHEME_TRUE: C_fprintf(C_stderr,            C_text("boolean        ")); break;
13053      case C_SCHEME_END_OF_LIST: C_fprintf(C_stderr,     C_text("null           ")); break;
13054      case C_SCHEME_UNDEFINED  : C_fprintf(C_stderr,     C_text("void           ")); break;
13055      case C_SCHEME_BROKEN_WEAK_PTR: C_fprintf(C_stderr, C_text("broken weak ptr")); break;
13056      case C_make_character('A'): C_fprintf(C_stderr,    C_text("character      ")); break;
13057      case C_SCHEME_END_OF_FILE: C_fprintf(C_stderr,     C_text("eof            ")); break;
13058      case C_SCHEME_UNBOUND: C_fprintf(C_stderr,         C_text("unbound        ")); break;
13059      case C_SYMBOL_TYPE: C_fprintf(C_stderr,            C_text("symbol         ")); break;
13060      case C_STRING_TYPE: C_fprintf(C_stderr,            C_text("string         ")); break;
13061      case C_PAIR_TYPE: C_fprintf(C_stderr,              C_text("pair           ")); break;
13062      case C_CLOSURE_TYPE: C_fprintf(C_stderr,           C_text("closure        ")); break;
13063      case C_FLONUM_TYPE: C_fprintf(C_stderr,            C_text("flonum         ")); break;
13064      case C_PORT_TYPE: C_fprintf(C_stderr,              C_text("port           ")); break;
13065      case C_POINTER_TYPE: C_fprintf(C_stderr,           C_text("pointer        ")); break;
13066      case C_LOCATIVE_TYPE: C_fprintf(C_stderr,          C_text("locative       ")); break;
13067      case C_TAGGED_POINTER_TYPE: C_fprintf(C_stderr,    C_text("tagged pointer ")); break;
13068      case C_LAMBDA_INFO_TYPE: C_fprintf(C_stderr,       C_text("lambda info    ")); break;
13069      case C_WEAK_PAIR_TYPE: C_fprintf(C_stderr,         C_text("weak pair      ")); break;
13070      case C_VECTOR_TYPE: C_fprintf(C_stderr,            C_text("vector         ")); break;
13071      case C_BYTEVECTOR_TYPE: C_fprintf(C_stderr,        C_text("bytevector     ")); break;
13072      case C_BIGNUM_TYPE: C_fprintf(C_stderr,            C_text("bignum         ")); break;
13073      case C_CPLXNUM_TYPE: C_fprintf(C_stderr,           C_text("cplxnum        ")); break;
13074      case C_RATNUM_TYPE: C_fprintf(C_stderr,            C_text("ratnum         ")); break;
13075	/* XXX this is sort of funny: */
13076      case C_BYTEBLOCK_BIT: C_fprintf(C_stderr,          C_text("blob           ")); break;
13077      default:
13078	x = b->key;
13079
13080	if(!C_immediatep(x) && C_header_bits(x) == C_SYMBOL_TYPE) {
13081	  x = C_block_item(x, 1);
13082	  C_fprintf(C_stderr, C_text("`%.*s'"), (int)C_header_size(x), C_c_string(x));
13083	}
13084	else C_fprintf(C_stderr, C_text("unknown key " UWORD_FORMAT_STRING), (C_uword)b->key);
13085      }
13086
13087      C_fprintf(C_stderr, C_text("\t%d"), b->count);
13088
13089      if(b->total > 0) 
13090	C_fprintf(C_stderr, C_text("\t%d bytes"), b->total);
13091
13092      C_fputc('\n', C_stderr);
13093      C_free(b);
13094    }
13095  }
13096
13097  C_fprintf(C_stderr, C_text("\ntotal number of blocks: %d, immediates: %d\n"),
13098	    blk, imm);
13099  C_free(hdump_table);
13100  C_kontinue(k, C_SCHEME_UNDEFINED);
13101}
13102
13103
13104static void C_ccall filter_heap_objects_2(C_word c, C_word *av)
13105{
13106  void *func = C_pointer_address(av[ 0 ]);
13107  C_word 
13108    userarg = av[ 1 ],
13109    vector = av[ 2 ],
13110    k = av[ 3 ];
13111  int n, bytes;
13112  C_byte *scan;
13113  C_SCHEME_BLOCK *sbp;
13114  C_header h;
13115  C_word *p;
13116  int vecsize = C_header_size(vector);
13117  typedef int (*filterfunc)(C_word x, C_word userarg);
13118  filterfunc ff = (filterfunc)func;
13119  int vcount = 0;
13120
13121  scan = fromspace_start;
13122
13123  while(scan < C_fromspace_top) {
13124    sbp = (C_SCHEME_BLOCK *)scan;
13125
13126    if(*((C_word *)sbp) == ALIGNMENT_HOLE_MARKER) 
13127      sbp = (C_SCHEME_BLOCK *)((C_word *)sbp + 1);
13128
13129    n = C_header_size(sbp);
13130    h = sbp->header;
13131    bytes = (h & C_BYTEBLOCK_BIT) ? n : n * sizeof(C_word);
13132    p = sbp->data;
13133
13134    if(ff((C_word)sbp, userarg)) {
13135      if(vcount < vecsize) {
13136	C_set_block_item(vector, vcount, (C_word)sbp);
13137	++vcount;
13138      }
13139      else {
13140	C_kontinue(k, C_fix(-1));
13141      }
13142    }
13143
13144    scan = (C_byte *)sbp + C_align(bytes) + sizeof(C_word);
13145  }
13146
13147  C_kontinue(k, C_fix(vcount));
13148}
13149
13150
13151void C_ccall C_filter_heap_objects(C_word c, C_word *av)
13152{
13153  C_word
13154    /* closure = av[ 0 ] */
13155    k = av[ 1 ],
13156    func = av[ 2 ],
13157    vector = av[ 3 ],
13158    userarg = av[ 4 ];
13159
13160  /* make sure heap is compacted */
13161  C_save(k);
13162  C_save(vector);
13163  C_save(userarg);
13164  C_save(func);
13165  C_fromspace_top = C_fromspace_limit; /* force major GC */
13166  C_reclaim((void *)filter_heap_objects_2, 4);
13167}
13168
13169C_regparm C_word C_fcall C_i_process_sleep(C_word n)
13170{
13171#if defined(_WIN32) && !defined(__CYGWIN__)
13172  Sleep(C_unfix(n) * 1000);
13173  return C_fix(0);
13174#else
13175  return C_fix(sleep(C_unfix(n)));
13176#endif
13177}
13178
13179C_regparm C_word C_fcall 
13180C_i_file_exists_p(C_word name, C_word file, C_word dir)
13181{
13182  struct stat buf;
13183  int res;
13184
13185  res = C_stat(C_c_string(name), &buf);
13186
13187  if(res != 0) {
13188    switch(errno) {
13189    case ENOENT: return C_SCHEME_FALSE;
13190    case EOVERFLOW: return C_truep(dir) ? C_SCHEME_FALSE : C_SCHEME_TRUE;
13191    case ENOTDIR: return C_SCHEME_FALSE;
13192    default: return C_fix(res);
13193    }
13194  }
13195
13196  switch(buf.st_mode & S_IFMT) {
13197  case S_IFDIR: return C_truep(file) ? C_SCHEME_FALSE : C_SCHEME_TRUE;
13198  default: return C_truep(dir) ? C_SCHEME_FALSE : C_SCHEME_TRUE;
13199  }
13200}
13201
13202
13203C_regparm C_word C_fcall
13204C_i_pending_interrupt(C_word dummy)
13205{
13206  if(pending_interrupts_count > 0) {
13207    handling_interrupts = 1; /* Lock out further forced GCs until we're done */
13208    return C_fix(pending_interrupts[ --pending_interrupts_count ]);
13209  } else {
13210    handling_interrupts = 0; /* OK, can go on */
13211    return C_SCHEME_FALSE;
13212  }
13213}
13214
13215
13216/* random numbers, mostly lifted from 
13217  https://github.com/jedisct1/libsodium/blob/master/src/libsodium/randombytes/sysrandom/randombytes_sysrandom.c
13218*/
13219
13220#ifdef __linux__
13221# include <sys/syscall.h>
13222#endif
13223
13224
13225#if !defined(_WIN32) 
13226static C_word random_urandom(C_word buf, int count)
13227{
13228  static int fd = -1;
13229  int off = 0, r;
13230
13231  if(fd == -1) {
13232    fd = open("/dev/urandom", O_RDONLY);
13233
13234    if(fd == -1) return C_SCHEME_FALSE;
13235  }
13236
13237  while(count > 0) {
13238    r = read(fd, C_data_pointer(buf) + off, count);
13239
13240    if(r == -1) {
13241      if(errno != EINTR && errno != EAGAIN) return C_SCHEME_FALSE;
13242      else r = 0;
13243    }
13244
13245    count -= r;
13246    off += r;
13247   }
13248
13249  return C_SCHEME_TRUE;
13250}
13251#endif
13252
13253
13254C_word C_random_bytes(C_word buf, C_word size)
13255{
13256  int count = C_unfix(size);
13257  int r = 0;
13258  int off = 0;
13259
13260#if defined(__OpenBSD__) || defined(__FreeBSD__)
13261  arc4random_buf(C_data_pointer(buf), count);
13262#elif defined(SYS_getrandom) && defined(__NR_getrandom)
13263  static int use_urandom = 0;
13264
13265  if(use_urandom) return random_urandom(buf, count);
13266
13267  while(count > 0) {
13268    /* GRND_NONBLOCK = 0x0001 */
13269    r = syscall(SYS_getrandom, C_data_pointer(buf) + off, count, 1);
13270
13271    if(r == -1) {
13272      if(errno == ENOSYS) {
13273        use_urandom = 1;
13274        return random_urandom(buf, count);
13275      }
13276      else if(errno != EINTR) return C_SCHEME_FALSE;
13277      else r = 0;
13278    }
13279
13280    count -= r;
13281    off += r;
13282  }
13283#elif defined(_WIN32) && !defined(__CYGWIN__)
13284  typedef BOOLEAN (*func)(PVOID, ULONG);
13285  static func RtlGenRandom = NULL;
13286  
13287  if(RtlGenRandom == NULL) {
13288     HMODULE mod = LoadLibrary("advapi32.dll");
13289	 
13290     if(mod == NULL) return C_SCHEME_FALSE;
13291	 
13292     if((RtlGenRandom = (func)GetProcAddress(mod, "SystemFunction036")) == NULL)
13293       return C_SCHEME_FALSE;
13294  }
13295  
13296  if(!RtlGenRandom((PVOID)C_data_pointer(buf), (LONG)count)) 
13297    return C_SCHEME_FALSE;
13298#else 
13299  return random_urandom(buf, count);
13300#endif
13301
13302  return C_SCHEME_TRUE;
13303}
13304
13305
13306/* WELL512 pseudo random number generator, see also:
13307   https://en.wikipedia.org/wiki/Well_equidistributed_long-period_linear
13308   http://lomont.org/Math/Papers/2008/Lomont_PRNG_2008.pdf
13309*/
13310
13311static C_uword random_word(void)
13312{ 
13313  C_uword a, b, c, d, r; 
13314  a  = random_state[random_state_index]; 
13315  c  = random_state[(random_state_index+13)&15]; 
13316  b  = a^c^(a<<16)^(c<<15); 
13317  c  = random_state[(random_state_index+9)&15]; 
13318  c ^= (c>>11); 
13319  a  = random_state[random_state_index] = b^c;  
13320  d  = a^((a<<5)&0xDA442D24UL);  
13321  random_state_index = (random_state_index + 15)&15; 
13322  a  = random_state[random_state_index]; 
13323  random_state[random_state_index] = a^b^d^(a<<2)^(b<<18)^(c<<28); 
13324  r = random_state[random_state_index];
13325  return r;
13326} 
13327
13328
13329static C_uword random_uniform(C_uword bound)
13330{
13331  C_uword r, min;
13332
13333  if (bound < 2) return 0;
13334
13335  min = (1U + ~bound) % bound; /* = 2**<wordsize> mod bound */
13336
13337  do r = random_word(); while (r < min);
13338
13339  /* r is now clamped to a set whose size mod upper_bound == 0
13340   * the worst case (2**<wordsize-1>+1) requires ~ 2 attempts */
13341
13342  return r % bound;
13343}
13344                 
13345
13346C_regparm C_word C_random_fixnum(C_word n)
13347{ 
13348  C_word nf;
13349
13350  if (!(n & C_FIXNUM_BIT))
13351    barf(C_BAD_ARGUMENT_TYPE_NO_FIXNUM_ERROR, "pseudo-random-integer", n);
13352
13353  nf = C_unfix(n);
13354
13355  if(nf < 0)
13356    barf(C_OUT_OF_RANGE_ERROR, "pseudo-random-integer", n, C_fix(0));
13357
13358  return C_fix(random_uniform(nf));
13359} 
13360
13361
13362C_regparm C_word C_fcall
13363C_s_a_u_i_random_int(C_word **ptr, C_word n, C_word rn)
13364{
13365  C_uword *start, *end;
13366
13367  if(C_bignum_negativep(rn))
13368    barf(C_OUT_OF_RANGE_ERROR, "pseudo-random-integer", rn, C_fix(0));
13369
13370  int len = integer_length_abs(rn);
13371  C_word size = C_fix(C_BIGNUM_BITS_TO_DIGITS(len));
13372  C_word result = C_allocate_scratch_bignum(ptr, size, C_SCHEME_FALSE, C_SCHEME_FALSE);
13373  C_uword *p;
13374  C_uword highest_word = C_bignum_digits(rn)[C_bignum_size(rn)-1];
13375  start = C_bignum_digits(result);
13376  end = start + C_bignum_size(result);
13377
13378  for(p = start; p < (end - 1); ++p) {
13379    *p = random_word();
13380    len -= sizeof(C_uword);
13381  }
13382
13383  *p = random_uniform(highest_word);
13384  return C_bignum_simplify(result);
13385}
13386
13387/*
13388 * C_a_i_random_real: Generate a stream of bits uniformly at random and
13389 * interpret it as the fractional part of the binary expansion of a
13390 * number in [0, 1], 0.00001010011111010100...; then round it.
13391 * More information on https://mumble.net/~campbell/2014/04/28/uniform-random-float
13392 */
13393
13394static inline C_u64 random64() {
13395#ifdef C_SIXTY_FOUR
13396    return random_word();
13397#else
13398    C_u64 v = 0;
13399    v |= ((C_u64) random_word()) << 32;
13400    v |= (C_u64) random_word();
13401    return v;
13402#endif
13403}
13404
13405#if defined(__GNUC__) && !defined(__TINYC__)
13406# define	clz64	__builtin_clzll		
13407#else
13408/* https://en.wikipedia.org/wiki/Find_first_set#CLZ */
13409static const C_uchar clz_table_4bit[16] = { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
13410
13411int clz32(C_u32 x)
13412{
13413  int n;
13414  if ((x & 0xFFFF0000) == 0) {n  = 16; x <<= 16;} else {n = 0;}
13415  if ((x & 0xFF000000) == 0) {n +=  8; x <<=  8;}
13416  if ((x & 0xF0000000) == 0) {n +=  4; x <<=  4;}
13417  n += (int)clz_table_4bit[x >> (32-4)];
13418  return n;
13419}
13420
13421int clz64(C_u64 x) 
13422{
13423    int y = clz32(x >> 32);
13424
13425    if(y == 32) return y + clz32(x);
13426
13427    return y;
13428}
13429#endif
13430
13431C_regparm C_word C_fcall
13432C_a_i_random_real(C_word **ptr, C_word n) {
13433  int exponent = -64;
13434  uint64_t significand;
13435  unsigned shift;
13436
13437  while (C_unlikely((significand = random64()) == 0)) {
13438    exponent -= 64;
13439    if (C_unlikely(exponent < -1074))
13440      return 0;
13441  }
13442
13443  shift = clz64(significand);
13444  if (shift != 0) {
13445    exponent -= shift;
13446    significand <<= shift;
13447    significand |= (random64() >> (64 - shift));
13448  }
13449
13450  significand |= 1;
13451  return C_flonum(ptr, ldexp((double)significand, exponent));
13452}
13453
13454C_word C_set_random_seed(C_word buf, C_word n)
13455{
13456  int i, nsu = C_unfix(n) / sizeof(C_uword);
13457  int off = 0;
13458
13459  for(i = 0; i < (C_RANDOM_STATE_SIZE / sizeof(C_uword)); ++i) {
13460    if(off >= nsu) off = 0;
13461
13462    random_state[ i ] = *((C_uword *)C_data_pointer(buf) + off);
13463    ++off;
13464  }
13465
13466  random_state_index = 0;
13467  return C_SCHEME_FALSE;
13468}
Trap