~ chicken-core (master) /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 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 (*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_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_long
  318  C_timer_interrupt_counter,
  319  C_initial_timer_interrupt_period;
  320C_byte
  321  *C_fromspace_top,
  322  *C_fromspace_limit;
  323#ifdef HAVE_SIGSETJMP
  324sigjmp_buf C_restart;
  325#else
  326jmp_buf C_restart;
  327#endif
  328void *C_restart_trampoline;
  329C_word C_restart_c;
  330int C_entry_point_status;
  331int (*C_gc_mutation_hook)(C_word *slot, C_word val);
  332void (*C_gc_trace_hook)(C_word *var, int mode);
  333void (*C_panic_hook)(C_char *msg) = NULL;
  334void (*C_pre_gc_hook)(int mode) = NULL;
  335void (*C_post_gc_hook)(int mode, C_long ms) = NULL;
  336C_word (*C_debugger_hook)(C_DEBUG_INFO *cell, C_word c, C_word *av, C_char *cloc) = NULL;
  337
  338int
  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_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;
  355time_t
  356  C_startup_time_sec,
  357  C_startup_time_msec,
  358  profile_frequency = 10000;
  359char
  360  **C_main_argv,
  361#ifdef SEARCH_EXE_PATH
  362  *C_main_exe = NULL,
  363#endif
  364  *C_dlerror;
  365
  366static TRACE_INFO
  367  *trace_buffer,
  368  *trace_buffer_limit,
  369  *trace_buffer_top;
  370
  371static 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_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_char
  390  buffer[ STRING_BUFFER_SIZE ],
  391  *private_repository = NULL,
  392  *current_module_name,
  393  *save_string;
  394static C_SYMBOL_TABLE
  395  *symbol_table,
  396  *symbol_table_list,
  397  *keyword_table;
  398static 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  s8vector_symbol,
  416  u16vector_symbol,
  417  s16vector_symbol,
  418  u32vector_symbol,
  419  s32vector_symbol,
  420  u64vector_symbol,
  421  s64vector_symbol,
  422  f32vector_symbol,
  423  f64vector_symbol,
  424  *forwarding_table;
  425static int
  426  trace_buffer_full,
  427  forwarding_table_size,
  428  return_to_host,
  429  page_size,
  430  show_trace,
  431  fake_tty_flag,
  432  debug_mode,
  433  dump_heap_on_exit,
  434  gc_bell,
  435  gc_report_flag = 0,
  436  gc_mode,
  437  gc_count_1,
  438  gc_count_1_total,
  439  gc_count_2,
  440  stack_size_changed,
  441  dlopen_flags,
  442  heap_size_changed,
  443  random_state_initialized = 0,
  444  chicken_is_running,
  445  chicken_ran_once,
  446  pass_serious_signals = 1,
  447  callback_continuation_level;
  448static volatile int
  449  serious_signal_occurred = 0,
  450  profiling = 0;
  451static unsigned int
  452  mutation_count,
  453  tracked_mutation_count,
  454  stack_check_demand,
  455  stack_size;
  456static int chicken_is_initialized;
  457#ifdef HAVE_SIGSETJMP
  458static sigjmp_buf gc_restart;
  459#else
  460static jmp_buf gc_restart;
  461#endif
  462static double
  463  timer_start_ms,
  464  gc_ms,
  465  timer_accumulated_gc_ms,
  466  interrupt_time,
  467  last_interrupt_latency;
  468static LF_LIST *lf_list;
  469static int signal_mapping_table[ NSIG ];
  470static int
  471  live_finalizer_count,
  472  allocated_finalizer_count,
  473  pending_finalizer_count,
  474  callback_returned_flag;
  475static C_GC_ROOT *gc_root_list = NULL;
  476static FINALIZER_NODE
  477  *finalizer_list,
  478  *finalizer_free_list,
  479  **pending_finalizer_indices;
  480static void *current_module_handle;
  481static int flonum_print_precision = FLONUM_PRINT_PRECISION;
  482static HDUMP_BUCKET **hdump_table;
  483static PROFILE_BUCKET
  484  *next_profile_bucket = NULL,
  485  **profile_table = NULL;
  486static int
  487  pending_interrupts[ MAX_PENDING_INTERRUPTS ],
  488  pending_interrupts_count,
  489  handling_interrupts;
  490static C_uword random_state[ C_RANDOM_STATE_SIZE / sizeof(C_uword) ];
  491static int random_state_index = 0;
  492
  493
  494/* Prototypes: */
  495
  496static void parse_argv(C_char *cmds);
  497static void initialize_symbol_table(void);
  498static void global_signal_handler(int signum);
  499static C_word arg_val(C_char *arg);
  500static void barf(int code, char *loc, ...) C_noret;
  501static void try_extended_number(char *ext_proc_name, C_word c, C_word k, ...) C_noret;
  502static void panic(C_char *msg) C_noret;
  503static void usual_panic(C_char *msg) C_noret;
  504static void horror(C_char *msg) C_noret;
  505static void really_mark(C_word *x, C_byte *tgt_space_start, C_byte **tgt_space_top, C_byte *tgt_space_limit) C_regparm;
  506static C_cpsproc(values_continuation) C_noret;
  507static C_word add_symbol(C_word **ptr, C_word key, C_word string, C_SYMBOL_TABLE *stable);
  508static C_regparm int C_in_new_heapp(C_word x);
  509static C_regparm C_word bignum_times_bignum_unsigned(C_word **ptr, C_word x, C_word y, C_word negp);
  510static C_regparm C_word bignum_extract_digits(C_word **ptr, C_word n, C_word x, C_word start, C_word end);
  511
  512static C_regparm C_word bignum_times_bignum_karatsuba(C_word **ptr, C_word x, C_word y, C_word negp);
  513static C_word bignum_plus_unsigned(C_word **ptr, C_word x, C_word y, C_word negp);
  514static C_word rat_plusmin_integer(C_word **ptr, C_word rat, C_word i, integer_plusmin_op plusmin_op);
  515static C_word integer_minus_rat(C_word **ptr, C_word i, C_word rat);
  516static C_word rat_plusmin_rat(C_word **ptr, C_word x, C_word y, integer_plusmin_op plusmin_op);
  517static C_word rat_times_integer(C_word **ptr, C_word x, C_word y);
  518static C_word rat_times_rat(C_word **ptr, C_word x, C_word y);
  519static C_word cplx_times(C_word **ptr, C_word rx, C_word ix, C_word ry, C_word iy);
  520static C_word bignum_minus_unsigned(C_word **ptr, C_word x, C_word y);
  521static C_regparm void integer_divrem(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r);
  522static C_regparm C_word bignum_remainder_unsigned_halfdigit(C_word x, C_word y);
  523static C_regparm void bignum_divrem(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r);
  524static C_regparm C_word bignum_divide_burnikel_ziegler(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r);
  525static 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);
  526static 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);
  527static C_word rat_cmp(C_word x, C_word y);
  528static void fabs_frexp_to_digits(C_uword exp, double sign, C_uword *start, C_uword *scan);
  529static C_word int_flo_cmp(C_word intnum, C_word flonum);
  530static C_word flo_int_cmp(C_word flonum, C_word intnum);
  531static C_word rat_flo_cmp(C_word ratnum, C_word flonum);
  532static C_word flo_rat_cmp(C_word flonum, C_word ratnum);
  533static C_word basic_cmp(C_word x, C_word y, char *loc, int eqp);
  534static int bignum_cmp_unsigned(C_word x, C_word y);
  535static C_word hash_string(int len, C_char *str, C_word m, C_word r) C_regparm;
  536static C_word lookup(C_word key, int len, C_char *str, C_SYMBOL_TABLE *stable) C_regparm;
  537static C_word lookup_bucket(C_word sym, C_SYMBOL_TABLE *stable) C_regparm;
  538static double compute_symbol_table_load(double *avg_bucket_len, int *total);
  539static double decode_flonum_literal(C_char *str) C_regparm;
  540static C_regparm C_word str_to_bignum(C_word bignum, char *str, char *str_end, int radix);
  541static void 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;
  542static void mark_live_objects(C_byte *tgt_space_start, C_byte **tgt_space_top, C_byte *tgt_space_limit) C_regparm;
  543static void mark_live_heap_only_objects(C_byte *tgt_space_start, C_byte **tgt_space_top, C_byte *tgt_space_limit) C_regparm;
  544static C_word intern0(C_char *name) C_regparm;
  545static void update_weak_pairs(int mode, C_byte *undead_start, C_byte *undead_end) C_regparm;
  546static void update_locatives(int mode, C_byte *undead_start, C_byte *undead_end) C_regparm;
  547static LF_LIST *find_module_handle(C_char *name);
  548static void set_profile_timer(C_uword freq);
  549static void take_profile_sample();
  550
  551static C_cpsproc(call_cc_wrapper) C_noret;
  552static C_cpsproc(call_cc_values_wrapper) C_noret;
  553static C_cpsproc(gc_2) C_noret;
  554static C_cpsproc(allocate_vector_2) C_noret;
  555static C_cpsproc(allocate_bytevector_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, C_WCHAR *argv[], void *toplevel)
  608{
  609  C_word h, s, n;
  610
  611  if(C_gui_mode) {
  612#ifdef _WIN32
  613    parse_argv(C_utf8(GetCommandLineW()));
  614    argc = C_main_argc;
  615    argv = C_main_argv;
  616#else
  617    /* ??? */
  618#endif
  619  }
  620#if defined(_WIN32) && !defined(__CYGWIN__)
  621  else {
  622    int i, n;
  623    C_char *aptr, *arg;
  624    C_main_argv = (C_char **)malloc((MAXIMAL_NUMBER_OF_COMMAND_LINE_ARGUMENTS + 1) * sizeof(C_char *));
  625
  626    if(C_main_argv == NULL)
  627      panic(C_text("cannot allocate argument-list buffer"));
  628
  629    for(i = 0; i < argc; ++i) {
  630    	arg = C_utf8(argv[ i ]);
  631    	n = strlen(arg);
  632       aptr = (C_char *)malloc(n + 1);
  633
  634       if(!aptr) panic(C_text("cannot allocate argument buffer"));
  635
  636       C_strlcpy(aptr, arg, n + 1);
  637       C_main_argv[ i ] = aptr;
  638    }
  639
  640    C_main_argc = argc;
  641    C_main_argv[ argc ] = NULL;
  642    argv = C_main_argv;
  643  }
  644#endif
  645
  646  pass_serious_signals = 0;
  647  CHICKEN_parse_command_line(argc, argv, &h, &s, &n);
  648
  649  if(!CHICKEN_initialize(h, s, n, toplevel))
  650    panic(C_text("cannot initialize - out of memory"));
  651
  652  CHICKEN_run(NULL);
  653  return 0;
  654}
  655
  656
  657/* Custom argv parser for Windowz: */
  658
  659void parse_argv(C_char *cmds)
  660{
  661  C_char *ptr = cmds, *bptr0, *bptr, *aptr;
  662  int n = 0;
  663  C_main_argv = (C_char **)malloc((MAXIMAL_NUMBER_OF_COMMAND_LINE_ARGUMENTS + 1) * sizeof(C_char *));
  664
  665  if(C_main_argv == NULL)
  666    panic(C_text("cannot allocate argument-list buffer"));
  667
  668  C_main_argc = 0;
  669
  670  while(C_main_argc < MAXIMAL_NUMBER_OF_COMMAND_LINE_ARGUMENTS) {
  671    while(C_utf_isspace((int)(*ptr))) ++ptr;
  672
  673    if(*ptr == '\0') break;
  674
  675    for(bptr0 = bptr = buffer; !C_utf_isspace((int)(*ptr)) && *ptr != '\0'; *(bptr++) = *(ptr++))
  676      ++n;
  677
  678    *bptr = '\0';
  679    aptr = (C_char*)malloc(n + 1);
  680
  681    if(!aptr) panic(C_text("cannot allocate argument buffer"));
  682
  683    C_strlcpy(aptr, bptr0, n + 1);
  684    C_main_argv[ C_main_argc++ ] = aptr;
  685  }
  686
  687  C_main_argv[ C_main_argc ] = NULL;
  688}
  689
  690/* simple linear congruential PRNG, to avoid OpenBSD warnings.
  691    https://stackoverflow.com/questions/26237419/faster-than-rand
  692*/
  693
  694static int g_seed;
  695
  696void C_fast_srand(int seed) { g_seed = seed; }
  697
  698/* Output value in range [0, 32767] */
  699int C_fast_rand(void)
  700{
  701	g_seed = (214013*g_seed+2531011);
  702	return (g_seed>>16)&0x7FFF;
  703}
  704
  705
  706/* Initialize runtime system: */
  707
  708int CHICKEN_initialize(int heap, int stack, int symbols, void *toplevel)
  709{
  710  C_SCHEME_BLOCK *k0;
  711  int i;
  712#ifdef HAVE_SIGACTION
  713  struct sigaction sa;
  714#endif
  715
  716  /* FIXME Should have C_tzset in chicken.h? */
  717#if defined(__MINGW32__)
  718# if defined(__MINGW64_VERSION_MAJOR)
  719    ULONGLONG tick_count = GetTickCount64();
  720# else
  721    /* mingw doesn't yet have GetTickCount64 support */
  722    ULONGLONG tick_count = GetTickCount();
  723# endif
  724  C_startup_time_sec = tick_count / 1000;
  725  C_startup_time_msec = tick_count % 1000;
  726  /* Make sure _tzname, _timezone, and _daylight are set */
  727  _tzset();
  728#else
  729  struct timeval tv;
  730  C_gettimeofday(&tv, NULL);
  731  C_startup_time_sec = tv.tv_sec;
  732  C_startup_time_msec = tv.tv_usec / 1000;
  733  /* Make sure tzname, timezone, and daylight are set */
  734  tzset();
  735#endif
  736
  737  if(chicken_is_initialized) return 1;
  738  else chicken_is_initialized = 1;
  739
  740#if defined(__ANDROID__) && defined(DEBUGBUILD)
  741  debug_mode = 2;
  742#endif
  743
  744  if(debug_mode)
  745    C_dbg(C_text("debug"), C_text("application startup...\n"));
  746
  747  C_panic_hook = usual_panic;
  748  symbol_table_list = NULL;
  749
  750  symbol_table = C_new_symbol_table(".", symbols ? symbols : DEFAULT_SYMBOL_TABLE_SIZE);
  751
  752  if(symbol_table == NULL)
  753    return 0;
  754
  755  keyword_table = C_new_symbol_table("kw", symbols ? symbols / 4 : DEFAULT_KEYWORD_TABLE_SIZE);
  756
  757  if(keyword_table == NULL)
  758    return 0;
  759
  760  page_size = 0;
  761  stack_size = stack ? stack : DEFAULT_STACK_SIZE;
  762  C_set_or_change_heap_size(heap ? heap : DEFAULT_HEAP_SIZE, 0);
  763
  764  /* Allocate temporary stack: */
  765  temporary_stack_size = fixed_temporary_stack_size ? fixed_temporary_stack_size : DEFAULT_TEMPORARY_STACK_SIZE;
  766  if((C_temporary_stack_limit = (C_word *)C_malloc(temporary_stack_size * sizeof(C_word))) == NULL)
  767    return 0;
  768
  769  C_temporary_stack_bottom = C_temporary_stack_limit + temporary_stack_size;
  770  C_temporary_stack = C_temporary_stack_bottom;
  771
  772  /* Allocate mutation stack: */
  773  mutation_stack_bottom = (C_word **)C_malloc(DEFAULT_MUTATION_STACK_SIZE * sizeof(C_word *));
  774
  775  if(mutation_stack_bottom == NULL) return 0;
  776
  777  mutation_stack_top = mutation_stack_bottom;
  778  mutation_stack_limit = mutation_stack_bottom + DEFAULT_MUTATION_STACK_SIZE;
  779  C_gc_mutation_hook = NULL;
  780  C_gc_trace_hook = NULL;
  781
  782  /* Initialize finalizer lists: */
  783  finalizer_list = NULL;
  784  finalizer_free_list = NULL;
  785  pending_finalizer_indices =
  786      (FINALIZER_NODE **)C_malloc(C_max_pending_finalizers * sizeof(FINALIZER_NODE *));
  787
  788  if(pending_finalizer_indices == NULL) return 0;
  789
  790  /* Initialize forwarding table: */
  791  forwarding_table =
  792      (C_word *)C_malloc((DEFAULT_FORWARDING_TABLE_SIZE + 1) * 2 * sizeof(C_word));
  793
  794  if(forwarding_table == NULL) return 0;
  795
  796  *forwarding_table = 0;
  797  forwarding_table_size = DEFAULT_FORWARDING_TABLE_SIZE;
  798
  799  /* Setup collectibles: */
  800  collectibles = (C_word **)C_malloc(sizeof(C_word *) * DEFAULT_COLLECTIBLES_SIZE);
  801
  802  if(collectibles == NULL) return 0;
  803
  804  collectibles_top = collectibles;
  805  collectibles_limit = collectibles + DEFAULT_COLLECTIBLES_SIZE;
  806  gc_root_list = NULL;
  807
  808#if !defined(NO_DLOAD2) && defined(HAVE_DLFCN_H)
  809  dlopen_flags = RTLD_LAZY | RTLD_GLOBAL;
  810#else
  811  dlopen_flags = 0;
  812#endif
  813
  814#ifdef HAVE_SIGACTION
  815    sa.sa_flags = 0;
  816    sigfillset(&sa.sa_mask); /* See note in C_establish_signal_handler() */
  817    sa.sa_handler = global_signal_handler;
  818#endif
  819
  820  /* setup signal handlers */
  821  if(!pass_serious_signals) {
  822#ifdef HAVE_SIGACTION
  823    C_sigaction(SIGBUS, &sa, NULL);
  824    C_sigaction(SIGFPE, &sa, NULL);
  825    C_sigaction(SIGILL, &sa, NULL);
  826    C_sigaction(SIGSEGV, &sa, NULL);
  827#else
  828    C_signal(SIGBUS, global_signal_handler);
  829    C_signal(SIGILL, global_signal_handler);
  830    C_signal(SIGFPE, global_signal_handler);
  831    C_signal(SIGSEGV, global_signal_handler);
  832#endif
  833  }
  834
  835  tracked_mutation_count = mutation_count = gc_count_1 = gc_count_1_total = gc_count_2 = maximum_heap_usage = 0;
  836  lf_list = NULL;
  837  C_register_lf2(NULL, 0, create_initial_ptable());
  838  C_restart_trampoline = (void *)toplevel;
  839  trace_buffer = NULL;
  840  C_clear_trace_buffer();
  841  chicken_is_running = chicken_ran_once = 0;
  842  pending_interrupts_count = 0;
  843  handling_interrupts = 0;
  844  last_interrupt_latency = 0;
  845  C_interrupts_enabled = 1;
  846  C_initial_timer_interrupt_period = INITIAL_TIMER_INTERRUPT_PERIOD;
  847  C_timer_interrupt_counter = INITIAL_TIMER_INTERRUPT_PERIOD;
  848  memset(signal_mapping_table, 0, sizeof(int) * NSIG);
  849  C_dlerror = "cannot load compiled code dynamically - this is a statically linked executable";
  850  error_location = C_SCHEME_FALSE;
  851  C_pre_gc_hook = NULL;
  852  C_post_gc_hook = NULL;
  853  C_scratchspace_start = NULL;
  854  C_scratchspace_top = NULL;
  855  C_scratchspace_limit = NULL;
  856  C_scratch_usage = 0;
  857  scratchspace_size = 0;
  858  live_finalizer_count = 0;
  859  allocated_finalizer_count = 0;
  860  current_module_name = NULL;
  861  current_module_handle = NULL;
  862  callback_continuation_level = 0;
  863  weak_pair_chain = (C_word)NULL;
  864  locative_chain = (C_word)NULL;
  865  gc_ms = 0;
  866  if (!random_state_initialized) {
  867    C_fast_srand(time(NULL));
  868    random_state_initialized = 1;
  869  }
  870
  871  for(i = 0; i < C_RANDOM_STATE_SIZE / sizeof(C_uword); ++i)
  872    random_state[ i ] = C_fast_rand();
  873
  874  initialize_symbol_table();
  875
  876  if (profiling) {
  877#ifndef C_NONUNIX
  878# ifdef HAVE_SIGACTION
  879    C_sigaction(C_PROFILE_SIGNAL, &sa, NULL);
  880# else
  881    C_signal(C_PROFILE_SIGNAL, global_signal_handler);
  882# endif
  883#endif
  884
  885    profile_table = (PROFILE_BUCKET **)C_malloc(PROFILE_TABLE_SIZE * sizeof(PROFILE_BUCKET *));
  886
  887    if(profile_table == NULL)
  888      panic(C_text("out of memory - can not allocate profile table"));
  889
  890    C_memset(profile_table, 0, sizeof(PROFILE_BUCKET *) * PROFILE_TABLE_SIZE);
  891  }
  892
  893  /* create k to invoke code for system-startup: */
  894  k0 = (C_SCHEME_BLOCK *)C_align((C_word)C_fromspace_top);
  895  C_fromspace_top += C_align(2 * sizeof(C_word));
  896  k0->header = C_CLOSURE_TYPE | 1;
  897  C_set_block_item(k0, 0, (C_word)termination_continuation);
  898  C_save(k0);
  899  C_save(C_SCHEME_UNDEFINED);
  900  C_restart_c = 2;
  901  return 1;
  902}
  903
  904
  905void *C_get_statistics(void) {
  906  static void *stats[ 8 ];
  907
  908  stats[ 0 ] = fromspace_start;
  909  stats[ 1 ] = C_fromspace_limit;
  910  stats[ 2 ] = C_scratchspace_start;
  911  stats[ 3 ] = C_scratchspace_limit;
  912  stats[ 4 ] = C_stack_limit;
  913  stats[ 5 ] = stack_bottom;
  914  stats[ 6 ] = C_fromspace_top;
  915  stats[ 7 ] = C_scratchspace_top;
  916  return stats;
  917}
  918
  919
  920static C_PTABLE_ENTRY *create_initial_ptable()
  921{
  922  /* IMPORTANT: hardcoded table size -
  923     this must match the number of C_pte calls + 1 (NULL terminator)! */
  924  C_PTABLE_ENTRY *pt = (C_PTABLE_ENTRY *)C_malloc(sizeof(C_PTABLE_ENTRY) * 64);
  925  int i = 0;
  926
  927  if(pt == NULL)
  928    panic(C_text("out of memory - cannot create initial ptable"));
  929
  930  C_pte(termination_continuation);
  931  C_pte(callback_return_continuation);
  932  C_pte(values_continuation);
  933  C_pte(call_cc_values_wrapper);
  934  C_pte(call_cc_wrapper);
  935  C_pte(C_gc);
  936  C_pte(C_allocate_vector);
  937  C_pte(C_allocate_bytevector);
  938  C_pte(C_make_structure);
  939  C_pte(C_ensure_heap_reserve);
  940  C_pte(C_return_to_host);
  941  C_pte(C_get_symbol_table_info);
  942  C_pte(C_get_memory_info);
  943  C_pte(C_decode_seconds);
  944  C_pte(C_stop_timer);
  945  C_pte(C_dload);
  946  C_pte(C_set_dlopen_flags);
  947  C_pte(C_become);
  948  C_pte(C_apply_values);
  949  C_pte(C_times);
  950  C_pte(C_minus);
  951  C_pte(C_plus);
  952  C_pte(C_nequalp);
  953  C_pte(C_greaterp);
  954  /* IMPORTANT: have you read the comments at the start and the end of this function? */
  955  C_pte(C_lessp);
  956  C_pte(C_greater_or_equal_p);
  957  C_pte(C_less_or_equal_p);
  958  C_pte(C_number_to_string);
  959  C_pte(C_make_symbol);
  960  C_pte(C_string_to_symbol);
  961  C_pte(C_string_to_keyword);
  962  C_pte(C_apply);
  963  C_pte(C_call_cc);
  964  C_pte(C_values);
  965  C_pte(C_call_with_values);
  966  C_pte(C_continuation_graft);
  967  C_pte(C_open_file_port);
  968  C_pte(C_software_type);
  969  C_pte(C_machine_type);
  970  C_pte(C_machine_byte_order);
  971  C_pte(C_software_version);
  972  C_pte(C_build_platform);
  973  C_pte(C_make_pointer);
  974  /* IMPORTANT: have you read the comments at the start and the end of this function? */
  975  C_pte(C_make_tagged_pointer);
  976  C_pte(C_peek_signed_integer);
  977  C_pte(C_peek_unsigned_integer);
  978  C_pte(C_peek_int64);
  979  C_pte(C_peek_uint64);
  980  C_pte(C_context_switch);
  981  C_pte(C_register_finalizer);
  982  C_pte(C_copy_closure);
  983  C_pte(C_dump_heap_state);
  984  C_pte(C_filter_heap_objects);
  985  C_pte(C_fixnum_to_string);
  986  C_pte(C_integer_to_string);
  987  C_pte(C_flonum_to_string);
  988  C_pte(C_signum);
  989  C_pte(C_quotient_and_remainder);
  990  C_pte(C_u_integer_quotient_and_remainder);
  991  C_pte(C_bitwise_and);
  992  C_pte(C_bitwise_ior);
  993  C_pte(C_bitwise_xor);
  994
  995  /* IMPORTANT: did you remember the hardcoded pte table size? */
  996  pt[ i ].id = NULL;
  997  return pt;
  998}
  999
  1000
 1001void *CHICKEN_new_gc_root_2(int finalizable)
 1002{
 1003  C_GC_ROOT *r = (C_GC_ROOT *)C_malloc(sizeof(C_GC_ROOT));
 1004
 1005  if(r == NULL)
 1006    panic(C_text("out of memory - cannot allocate GC root"));
 1007
 1008  r->value = C_SCHEME_UNDEFINED;
 1009  r->next = gc_root_list;
 1010  r->prev = NULL;
 1011  r->finalizable = finalizable;
 1012
 1013  if(gc_root_list != NULL) gc_root_list->prev = r;
 1014
 1015  gc_root_list = r;
 1016  return (void *)r;
 1017}
 1018
 1019
 1020void *CHICKEN_new_gc_root()
 1021{
 1022  return CHICKEN_new_gc_root_2(0);
 1023}
 1024
 1025
 1026void *CHICKEN_new_finalizable_gc_root()
 1027{
 1028  return CHICKEN_new_gc_root_2(1);
 1029}
 1030
 1031
 1032void CHICKEN_delete_gc_root(void *root)
 1033{
 1034  C_GC_ROOT *r = (C_GC_ROOT *)root;
 1035
 1036  if(r->prev == NULL) gc_root_list = r->next;
 1037  else r->prev->next = r->next;
 1038
 1039  if(r->next != NULL) r->next->prev = r->prev;
 1040
 1041  C_free(root);
 1042}
 1043
 1044
 1045void *CHICKEN_global_lookup(char *name)
 1046{
 1047  int
 1048    len = C_strlen(name),
 1049    key = hash_string(len, name, symbol_table->size, symbol_table->rand);
 1050  C_word s;
 1051  void *root = CHICKEN_new_gc_root();
 1052
 1053  if(C_truep(s = lookup(key, len, name, symbol_table))) {
 1054    if(C_block_item(s, 0) != C_SCHEME_UNBOUND) {
 1055      CHICKEN_gc_root_set(root, s);
 1056      return root;
 1057    }
 1058  }
 1059
 1060  return NULL;
 1061}
 1062
 1063
 1064int CHICKEN_is_running()
 1065{
 1066  return chicken_is_running;
 1067}
 1068
 1069
 1070void CHICKEN_interrupt()
 1071{
 1072  C_timer_interrupt_counter = 0;
 1073}
 1074
 1075
 1076C_regparm C_SYMBOL_TABLE *C_new_symbol_table(char *name, unsigned int size)
 1077{
 1078  C_SYMBOL_TABLE *stp;
 1079  int i;
 1080
 1081  if((stp = C_find_symbol_table(name)) != NULL) return stp;
 1082
 1083  if((stp = (C_SYMBOL_TABLE *)C_malloc(sizeof(C_SYMBOL_TABLE))) == NULL)
 1084    return NULL;
 1085
 1086  stp->name = name;
 1087  stp->size = size;
 1088  stp->next = symbol_table_list;
 1089  stp->rand = C_fast_rand();
 1090
 1091  if((stp->table = (C_word *)C_malloc(size * sizeof(C_word))) == NULL)
 1092    return NULL;
 1093
 1094  for(i = 0; i < stp->size; stp->table[ i++ ] = C_SCHEME_END_OF_LIST);
 1095
 1096  symbol_table_list = stp;
 1097  return stp;
 1098}
 1099
 1100
 1101C_regparm C_SYMBOL_TABLE *C_find_symbol_table(char *name)
 1102{
 1103  C_SYMBOL_TABLE *stp;
 1104
 1105  for(stp = symbol_table_list; stp != NULL; stp = stp->next)
 1106    if(!C_strcmp(name, stp->name)) return stp;
 1107
 1108  return NULL;
 1109}
 1110
 1111
 1112C_regparm C_word C_find_symbol(C_word bv, C_SYMBOL_TABLE *stable)
 1113{
 1114  C_char *sptr = C_c_string(bv);
 1115  int len = C_header_size(bv) - 1;
 1116  int key;
 1117  C_word s;
 1118
 1119  if(stable == NULL) stable = symbol_table;
 1120
 1121  key = hash_string(len, sptr, stable->size, stable->rand);
 1122
 1123  if(C_truep(s = lookup(key, len, sptr, stable))) return s;
 1124  else return C_SCHEME_FALSE;
 1125}
 1126
 1127
 1128/* Setup symbol-table with internally used symbols; */
 1129
 1130void initialize_symbol_table(void)
 1131{
 1132  int i;
 1133
 1134  for(i = 0; i < symbol_table->size; symbol_table->table[ i++ ] = C_SCHEME_END_OF_LIST);
 1135
 1136  /* Obtain reference to hooks for later: */
 1137  core_provided_symbol = C_intern2(C_heaptop, C_text("##core#provided"));
 1138  interrupt_hook_symbol = C_intern2(C_heaptop, C_text("##sys#interrupt-hook"));
 1139  error_hook_symbol = C_intern2(C_heaptop, C_text("##sys#error-hook"));
 1140  callback_continuation_stack_symbol = C_intern3(C_heaptop, C_text("##sys#callback-continuation-stack"), C_SCHEME_END_OF_LIST);
 1141  pending_finalizers_symbol = C_intern2(C_heaptop, C_text("##sys#pending-finalizers"));
 1142  current_thread_symbol = C_intern3(C_heaptop, C_text("##sys#current-thread"), C_SCHEME_FALSE);
 1143
 1144  /* SRFI-4 tags */
 1145  s8vector_symbol = C_intern2(C_heaptop, C_text("s8vector"));
 1146  u16vector_symbol = C_intern2(C_heaptop, C_text("u16vector"));
 1147  s16vector_symbol = C_intern2(C_heaptop, C_text("s16vector"));
 1148  u32vector_symbol = C_intern2(C_heaptop, C_text("u32vector"));
 1149  s32vector_symbol = C_intern2(C_heaptop, C_text("s32vector"));
 1150  u64vector_symbol = C_intern2(C_heaptop, C_text("u64vector"));
 1151  s64vector_symbol = C_intern2(C_heaptop, C_text("s64vector"));
 1152  f32vector_symbol = C_intern2(C_heaptop, C_text("f32vector"));
 1153  f64vector_symbol = C_intern2(C_heaptop, C_text("f64vector"));
 1154}
 1155
 1156
 1157C_regparm C_word C_find_keyword(C_word str, C_SYMBOL_TABLE *kwtable)
 1158{
 1159  C_char *sptr = C_c_string(str);
 1160  int len = C_header_size(str) - 1;
 1161  int key;
 1162  C_word s;
 1163
 1164  if(kwtable == NULL) kwtable = keyword_table;
 1165
 1166  key = hash_string(len, sptr, kwtable->size, kwtable->rand);
 1167
 1168  if(C_truep(s = lookup(key, len, sptr, kwtable))) return s;
 1169  else return C_SCHEME_FALSE;
 1170}
 1171
 1172
 1173void C_ccall sigsegv_trampoline(C_word c, C_word *av)
 1174{
 1175  barf(C_MEMORY_VIOLATION_ERROR, NULL);
 1176}
 1177
 1178
 1179void C_ccall sigbus_trampoline(C_word c, C_word *av)
 1180{
 1181  barf(C_BUS_ERROR, NULL);
 1182}
 1183
 1184
 1185void C_ccall sigfpe_trampoline(C_word c, C_word *av)
 1186{
 1187  barf(C_FLOATING_POINT_EXCEPTION_ERROR, NULL);
 1188}
 1189
 1190
 1191void C_ccall sigill_trampoline(C_word c, C_word *av)
 1192{
 1193  barf(C_ILLEGAL_INSTRUCTION_ERROR, NULL);
 1194}
 1195
 1196
 1197/* This is called from POSIX signals: */
 1198
 1199void global_signal_handler(int signum)
 1200{
 1201#if defined(HAVE_SIGPROCMASK)
 1202  if(signum == SIGSEGV || signum == SIGFPE || signum == SIGILL || signum == SIGBUS) {
 1203    sigset_t sset;
 1204
 1205    if(serious_signal_occurred || !chicken_is_running) {
 1206      switch(signum) {
 1207      case SIGSEGV: panic(C_text("unrecoverable segmentation violation"));
 1208      case SIGFPE: panic(C_text("unrecoverable floating-point exception"));
 1209      case SIGILL: panic(C_text("unrecoverable illegal instruction error"));
 1210      case SIGBUS: panic(C_text("unrecoverable bus error"));
 1211      default: panic(C_text("unrecoverable serious condition"));
 1212      }
 1213    }
 1214    else serious_signal_occurred = 1;
 1215
 1216    /* unblock signal to avoid nested invocation of the handler */
 1217    sigemptyset(&sset);
 1218    sigaddset(&sset, signum);
 1219    C_sigprocmask(SIG_UNBLOCK, &sset, NULL);
 1220
 1221    switch(signum) {
 1222    case SIGSEGV: C_reclaim(sigsegv_trampoline, 0);
 1223    case SIGFPE: C_reclaim(sigfpe_trampoline, 0);
 1224    case SIGILL: C_reclaim(sigill_trampoline, 0);
 1225    case SIGBUS: C_reclaim(sigbus_trampoline, 0);
 1226    default: panic(C_text("invalid serious signal"));
 1227    }
 1228  }
 1229#endif
 1230
 1231  /* TODO: Make full use of sigaction: check that /our/ timer expired */
 1232  if (signum == C_PROFILE_SIGNAL && profiling) take_profile_sample();
 1233  else C_raise_interrupt(signal_mapping_table[ signum ]);
 1234
 1235#ifndef HAVE_SIGACTION
 1236  /* not necessarily needed, but older UNIXen may not leave the handler installed: */
 1237  C_signal(signum, global_signal_handler);
 1238#endif
 1239}
 1240
 1241
 1242/* Align memory to page boundary */
 1243
 1244static void *align_to_page(void *mem)
 1245{
 1246  return (void *)C_align((C_uword)mem);
 1247}
 1248
 1249
 1250static C_byte *
 1251heap_alloc (size_t size, C_byte **page_aligned)
 1252{
 1253  C_byte *p;
 1254  p = (C_byte *)C_malloc (size + page_size);
 1255
 1256  if (p != NULL && page_aligned) *page_aligned = align_to_page (p);
 1257
 1258  return p;
 1259}
 1260
 1261
 1262static void
 1263heap_free (C_byte *ptr, size_t size)
 1264{
 1265  C_free (ptr);
 1266}
 1267
 1268
 1269static C_byte *
 1270heap_realloc (C_byte *ptr, size_t old_size,
 1271	      size_t new_size, C_byte **page_aligned)
 1272{
 1273  C_byte *p;
 1274  p = (C_byte *)C_realloc (ptr, new_size + page_size);
 1275
 1276  if (p != NULL && page_aligned) *page_aligned = align_to_page (p);
 1277
 1278  return p;
 1279}
 1280
 1281
 1282/* Modify heap size at runtime: */
 1283
 1284void C_set_or_change_heap_size(C_word heap, int reintern)
 1285{
 1286  C_byte *ptr1, *ptr2, *ptr1a, *ptr2a;
 1287  C_word size = heap / 2;
 1288
 1289  if(heap_size_changed && fromspace_start) return;
 1290
 1291  if(fromspace_start && heap_size >= heap) return;
 1292
 1293  if(debug_mode)
 1294    C_dbg(C_text("debug"), C_text("heap resized to " UWORD_COUNT_FORMAT_STRING " bytes\n"), heap);
 1295
 1296  heap_size = heap;
 1297
 1298  if((ptr1 = heap_realloc (fromspace_start,
 1299			   C_fromspace_limit - fromspace_start,
 1300			   size, &ptr1a)) == NULL ||
 1301     (ptr2 = heap_realloc (tospace_start,
 1302			   tospace_limit - tospace_start,
 1303			   size, &ptr2a)) == NULL)
 1304    panic(C_text("out of memory - cannot allocate heap"));
 1305
 1306  heapspace1 = ptr1;
 1307  heapspace1_size = size;
 1308  heapspace2 = ptr2;
 1309  heapspace2_size = size;
 1310  fromspace_start = ptr1a;
 1311  C_fromspace_top = fromspace_start;
 1312  C_fromspace_limit = fromspace_start + size;
 1313  tospace_start = ptr2a;
 1314  tospace_top = tospace_start;
 1315  tospace_limit = tospace_start + size;
 1316  mutation_stack_top = mutation_stack_bottom;
 1317
 1318  if(reintern) initialize_symbol_table();
 1319}
 1320
 1321
 1322/* Modify stack-size at runtime: */
 1323
 1324void C_do_resize_stack(C_word stack)
 1325{
 1326  C_uword old = stack_size,
 1327          diff = stack - old;
 1328
 1329  if(diff != 0 && !stack_size_changed) {
 1330    if(debug_mode)
 1331      C_dbg(C_text("debug"), C_text("stack resized to " UWORD_COUNT_FORMAT_STRING " bytes\n"), stack);
 1332
 1333    stack_size = stack;
 1334
 1335#if C_STACK_GROWS_DOWNWARD
 1336    C_stack_hard_limit = (C_word *)((C_byte *)C_stack_hard_limit - diff);
 1337#else
 1338    C_stack_hard_limit = (C_word *)((C_byte *)C_stack_hard_limit + diff);
 1339#endif
 1340    C_stack_limit = C_stack_hard_limit;
 1341  }
 1342}
 1343
 1344
 1345/* Check whether nursery is sufficiently big: */
 1346
 1347void C_check_nursery_minimum(C_word words)
 1348{
 1349  if(words >= C_bytestowords(stack_size))
 1350    panic(C_text("nursery is too small - try higher setting using the `-:s' option"));
 1351}
 1352
 1353C_word C_resize_pending_finalizers(C_word size) {
 1354  int sz = C_num_to_int(size);
 1355
 1356  FINALIZER_NODE **newmem =
 1357    (FINALIZER_NODE **)C_realloc(pending_finalizer_indices, sz * sizeof(FINALIZER_NODE *));
 1358
 1359  if (newmem == NULL)
 1360    return C_SCHEME_FALSE;
 1361
 1362  pending_finalizer_indices = newmem;
 1363  C_max_pending_finalizers = sz;
 1364  return C_SCHEME_TRUE;
 1365}
 1366
 1367
 1368/* Parse runtime options from command-line: */
 1369
 1370void CHICKEN_parse_command_line(int argc, char *argv[], C_word *heap, C_word *stack, C_word *symbols)
 1371{
 1372  int i;
 1373  char *ptr;
 1374  C_word x;
 1375
 1376  C_main_argc = argc;
 1377  C_main_argv = argv;
 1378
 1379  *heap = DEFAULT_HEAP_SIZE;
 1380  *stack = DEFAULT_STACK_SIZE;
 1381  *symbols = DEFAULT_SYMBOL_TABLE_SIZE;
 1382
 1383  for(i = 1; i < C_main_argc; ++i) {
 1384    if (strncmp(C_main_argv[ i ], C_text("-:"), 2))
 1385      break; /* Stop parsing on first non-runtime option */
 1386
 1387    ptr = &C_main_argv[ i ][ 2 ];
 1388    if (*ptr == '\0')
 1389      break; /* Also stop parsing on first "empty" option (i.e. "-:") */
 1390
 1391    do {
 1392      switch(*(ptr++)) {
 1393      case '?':
 1394        C_dbg("Runtime options", "\n\n"
 1395              " -:?              display this text\n"
 1396              " -:c              always treat stdin as console\n"
 1397              " -:d              enable debug output\n"
 1398              " -:D              enable more debug output\n"
 1399              " -:g              show GC information\n"
 1400              " -:o              disable stack overflow checks\n"
 1401              " -:hiSIZE         set initial heap size\n"
 1402              " -:hmSIZE         set maximal heap size\n"
 1403              " -:hfSIZE         set minimum unused heap size\n"
 1404              " -:hgPERCENTAGE   set heap growth percentage\n"
 1405              " -:hsPERCENTAGE   set heap shrink percentage\n"
 1406              " -:huPERCENTAGE   set percentage of memory used at which heap will be shrunk\n"
 1407              " -:hSIZE          set fixed heap size\n"
 1408              " -:r              write trace output to stderr\n"
 1409              " -:RSEED          initialize rand() seed with SEED (helpful for benchmark stability)\n"
 1410              " -:p              collect statistical profile and write to file at exit\n"
 1411              " -:PFREQUENCY     like -:p, specifying sampling frequency in us (default: 10000)\n"
 1412              " -:sSIZE          set nursery (stack) size\n"
 1413              " -:tSIZE          set symbol-table size\n"
 1414              " -:fSIZE          set maximal number of pending finalizers\n"
 1415              " -:x              deliver uncaught exceptions of other threads to primordial one\n"
 1416              " -:B              sound bell on major GC\n"
 1417              " -:G              force GUI mode\n"
 1418              " -:aSIZE          set trace-buffer/call-chain size\n"
 1419              " -:ASIZE          set fixed temporary stack size\n"
 1420              " -:H              dump heap state on exit\n"
 1421              " -:S              do not handle segfaults or other serious conditions\n"
 1422              "\n  SIZE may have a `k' (`K'), `m' (`M') or `g' (`G') suffix, meaning size\n"
 1423              "  times 1024, 1048576, and 1073741824, respectively.\n\n");
 1424        C_exit_runtime(C_fix(0));
 1425
 1426      case 'h':
 1427        switch(*ptr) {
 1428        case 'i':
 1429          *heap = arg_val(ptr + 1);
 1430          heap_size_changed = 1;
 1431          goto next;
 1432        case 'f':
 1433          C_heap_half_min_free = arg_val(ptr + 1);
 1434          goto next;
 1435        case 'g':
 1436          C_heap_growth = arg_val(ptr + 1);
 1437          goto next;
 1438        case 'm':
 1439          C_maximal_heap_size = arg_val(ptr + 1);
 1440          goto next;
 1441        case 's':
 1442          C_heap_shrinkage = arg_val(ptr + 1);
 1443          goto next;
 1444        case 'u':
 1445          C_heap_shrinkage_used = arg_val(ptr + 1);
 1446          goto next;
 1447        default:
 1448          *heap = arg_val(ptr);
 1449          heap_size_changed = 1;
 1450          C_heap_size_is_fixed = 1;
 1451          goto next;
 1452        }
 1453
 1454      case 'o':
 1455        C_disable_overflow_check = 1;
 1456        break;
 1457
 1458      case 'B':
 1459        gc_bell = 1;
 1460        break;
 1461
 1462      case 'G':
 1463        C_gui_mode = 1;
 1464        break;
 1465
 1466      case 'H':
 1467        dump_heap_on_exit = 1;
 1468        break;
 1469
 1470      case 'S':
 1471        pass_serious_signals = 1;
 1472        break;
 1473
 1474      case 's':
 1475        *stack = arg_val(ptr);
 1476        stack_size_changed = 1;
 1477        goto next;
 1478
 1479      case 'f':
 1480        C_max_pending_finalizers = arg_val(ptr);
 1481        goto next;
 1482
 1483      case 'a':
 1484        C_trace_buffer_size = arg_val(ptr);
 1485        goto next;
 1486
 1487      case 'A':
 1488        fixed_temporary_stack_size = arg_val(ptr);
 1489        goto next;
 1490
 1491      case 't':
 1492        *symbols = arg_val(ptr);
 1493        goto next;
 1494
 1495      case 'c':
 1496        fake_tty_flag = 1;
 1497        break;
 1498
 1499      case 'd':
 1500        debug_mode = 1;
 1501        break;
 1502
 1503      case 'D':
 1504        debug_mode = 2;
 1505        break;
 1506
 1507      case 'g':
 1508        gc_report_flag = 2;
 1509        break;
 1510
 1511      case 'P':
 1512        profiling = 1;
 1513        profile_frequency = arg_val(ptr);
 1514        goto next;
 1515
 1516      case 'p':
 1517        profiling = 1;
 1518        break;
 1519
 1520      case 'r':
 1521        show_trace = 1;
 1522        break;
 1523
 1524      case 'R':
 1525        C_fast_srand((unsigned int)arg_val(ptr));
 1526        random_state_initialized = 1;
 1527        goto next;
 1528
 1529      case 'x':
 1530        C_abort_on_thread_exceptions = 1;
 1531        break;
 1532
 1533      default: panic(C_text("illegal runtime option"));
 1534      }
 1535    } while(*ptr != '\0');
 1536
 1537    next:;
 1538    }
 1539}
 1540
 1541
 1542C_word arg_val(C_char *arg)
 1543{
 1544  int len;
 1545  C_char *end;
 1546  C_long val, mul = 1;
 1547
 1548  if (arg == NULL) panic(C_text("illegal runtime-option argument"));
 1549
 1550  len = C_strlen(arg);
 1551
 1552  if(len < 1) panic(C_text("illegal runtime-option argument"));
 1553
 1554  switch(arg[ len - 1 ]) {
 1555  case 'k':
 1556  case 'K': mul = 1024; break;
 1557
 1558  case 'm':
 1559  case 'M': mul = 1024 * 1024; break;
 1560
 1561  case 'g':
 1562  case 'G': mul = 1024 * 1024 * 1024; break;
 1563
 1564  default: mul = 1;
 1565  }
 1566
 1567  val = C_strtow(arg, &end, 10);
 1568
 1569  if((mul != 1 ? end[ 1 ] != '\0' : end[ 0 ] != '\0'))
 1570    panic(C_text("invalid runtime-option argument suffix"));
 1571
 1572  return val * mul;
 1573}
 1574
 1575
 1576/* Run embedded code with arguments: */
 1577
 1578C_word CHICKEN_run(void *toplevel)
 1579{
 1580  if(!chicken_is_initialized && !CHICKEN_initialize(0, 0, 0, toplevel))
 1581    panic(C_text("could not initialize"));
 1582
 1583  if(chicken_is_running)
 1584    panic(C_text("re-invocation of Scheme world while process is already running"));
 1585
 1586  chicken_is_running = chicken_ran_once = 1;
 1587  return_to_host = 0;
 1588
 1589  if(profiling) set_profile_timer(profile_frequency);
 1590
 1591#if C_STACK_GROWS_DOWNWARD
 1592  C_stack_hard_limit = (C_word *)((C_byte *)C_stack_pointer - stack_size);
 1593#else
 1594  C_stack_hard_limit = (C_word *)((C_byte *)C_stack_pointer + stack_size);
 1595#endif
 1596  C_stack_limit = C_stack_hard_limit;
 1597
 1598  stack_bottom = C_stack_pointer;
 1599
 1600  if(debug_mode)
 1601    C_dbg(C_text("debug"), C_text("stack bottom is 0x%lx\n"), (C_word)stack_bottom);
 1602
 1603  /* The point of (usually) no return... */
 1604#ifdef HAVE_SIGSETJMP
 1605  C_sigsetjmp(C_restart, 0);
 1606#else
 1607  C_setjmp(C_restart);
 1608#endif
 1609
 1610  serious_signal_occurred = 0;
 1611
 1612  if(!return_to_host) {
 1613    /* We must copy the argvector onto the stack, because
 1614     * any subsequent save() will otherwise clobber it.
 1615     */
 1616    C_word *p = C_alloc(C_restart_c);
 1617    assert(C_restart_c == (C_temporary_stack_bottom - C_temporary_stack));
 1618    C_memcpy(p, C_temporary_stack, C_restart_c * sizeof(C_word));
 1619    C_temporary_stack = C_temporary_stack_bottom;
 1620    ((C_proc)C_restart_trampoline)(C_restart_c, p);
 1621  }
 1622
 1623  if(profiling) set_profile_timer(0);
 1624
 1625  chicken_is_running = 0;
 1626  return C_restore;
 1627}
 1628
 1629
 1630C_word CHICKEN_continue(C_word k)
 1631{
 1632  if(C_temporary_stack_bottom != C_temporary_stack)
 1633    panic(C_text("invalid temporary stack level"));
 1634
 1635  if(!chicken_is_initialized)
 1636    panic(C_text("runtime system has not been initialized - `CHICKEN_run' has probably not been called"));
 1637
 1638  C_save(k);
 1639  return CHICKEN_run(NULL);
 1640}
 1641
 1642
 1643/* The final continuation: */
 1644
 1645void C_ccall termination_continuation(C_word c, C_word *av)
 1646{
 1647  if(debug_mode) {
 1648    C_dbg(C_text("debug"), C_text("application terminated normally\n"));
 1649  }
 1650
 1651  C_exit_runtime(C_fix(0));
 1652}
 1653
 1654
 1655/* Signal unrecoverable runtime error: */
 1656
 1657void panic(C_char *msg)
 1658{
 1659  if(C_panic_hook != NULL) C_panic_hook(msg);
 1660
 1661  usual_panic(msg);
 1662}
 1663
 1664
 1665void usual_panic(C_char *msg)
 1666{
 1667  C_char *dmp = C_dump_trace(0);
 1668
 1669  C_dbg_hook(C_SCHEME_UNDEFINED);
 1670
 1671  if(C_gui_mode) {
 1672    C_snprintf(buffer, sizeof(buffer), C_text("%s\n\n%s"), msg, dmp);
 1673#if defined(_WIN32) && !defined(__CYGWIN__)
 1674    MessageBox(NULL, buffer, C_text("CHICKEN runtime"), MB_OK | MB_ICONERROR);
 1675    ExitProcess(1);
 1676#endif
 1677  } /* fall through if not WIN32 GUI app */
 1678
 1679  C_dbg("panic", C_text("%s - execution terminated\n\n%s"), msg, dmp);
 1680  C_exit_runtime(C_fix(1));
 1681}
 1682
 1683
 1684void horror(C_char *msg)
 1685{
 1686  C_dbg_hook(C_SCHEME_UNDEFINED);
 1687
 1688  if(C_gui_mode) {
 1689    C_snprintf(buffer, sizeof(buffer), C_text("%s"), msg);
 1690#if defined(_WIN32) && !defined(__CYGWIN__)
 1691    MessageBox(NULL, buffer, C_text("CHICKEN runtime"), MB_OK | MB_ICONERROR);
 1692    ExitProcess(1);
 1693#endif
 1694  } /* fall through */
 1695
 1696  C_dbg("horror", C_text("\n%s - execution terminated"), msg);
 1697  C_exit_runtime(C_fix(1));
 1698}
 1699
 1700
 1701/* Error-hook, called from C-level runtime routines: */
 1702
 1703void barf(int code, char *loc, ...)
 1704{
 1705  C_char *msg;
 1706  C_word err = error_hook_symbol;
 1707  int c, i;
 1708  va_list v;
 1709  C_word *av;
 1710
 1711  C_dbg_hook(C_SCHEME_UNDEFINED);
 1712
 1713  C_temporary_stack = C_temporary_stack_bottom;
 1714  err = C_block_item(err, 0);
 1715
 1716  switch(code) {
 1717  case C_BAD_ARGUMENT_COUNT_ERROR:
 1718    msg = C_text("bad argument count");
 1719    c = 3;
 1720    break;
 1721
 1722  case C_BAD_MINIMUM_ARGUMENT_COUNT_ERROR:
 1723    msg = C_text("too few arguments");
 1724    c = 3;
 1725    break;
 1726
 1727  case C_BAD_ARGUMENT_TYPE_ERROR:
 1728    msg = C_text("bad argument type");
 1729    c = 1;
 1730    break;
 1731
 1732  case C_UNBOUND_VARIABLE_ERROR:
 1733    msg = C_text("unbound variable");
 1734    c = 1;
 1735    break;
 1736
 1737  case C_BAD_ARGUMENT_TYPE_NO_KEYWORD_ERROR:
 1738    msg = C_text("bad argument type - not a keyword");
 1739    c = 1;
 1740    break;
 1741
 1742  case C_OUT_OF_MEMORY_ERROR:
 1743    msg = C_text("not enough memory");
 1744    c = 0;
 1745    break;
 1746
 1747  case C_DIVISION_BY_ZERO_ERROR:
 1748    msg = C_text("division by zero");
 1749    c = 0;
 1750    break;
 1751
 1752  case C_OUT_OF_BOUNDS_ERROR:
 1753    msg = C_text("out of range");
 1754    c = 2;
 1755    break;
 1756
 1757  case C_NOT_A_CLOSURE_ERROR:
 1758    msg = C_text("call of non-procedure");
 1759    c = 1;
 1760    break;
 1761
 1762  case C_CONTINUATION_CANT_RECEIVE_VALUES_ERROR:
 1763    msg = C_text("continuation cannot receive multiple values");
 1764    c = 1;
 1765    break;
 1766
 1767  case C_BAD_ARGUMENT_TYPE_CYCLIC_LIST_ERROR:
 1768    msg = C_text("bad argument type - not a non-cyclic list");
 1769    c = 1;
 1770    break;
 1771
 1772  case C_TOO_DEEP_RECURSION_ERROR:
 1773    msg = C_text("recursion too deep");
 1774    c = 0;
 1775    break;
 1776
 1777  case C_CANT_REPRESENT_INEXACT_ERROR:
 1778    msg = C_text("inexact number cannot be represented as an exact number");
 1779    c = 1;
 1780    break;
 1781
 1782  case C_NOT_A_PROPER_LIST_ERROR:
 1783    msg = C_text("bad argument type - not a proper list");
 1784    c = 1;
 1785    break;
 1786
 1787  case C_BAD_ARGUMENT_TYPE_NO_FIXNUM_ERROR:
 1788    msg = C_text("bad argument type - not a fixnum");
 1789    c = 1;
 1790    break;
 1791
 1792  case C_BAD_ARGUMENT_TYPE_NO_STRING_ERROR:
 1793    msg = C_text("bad argument type - not a string");
 1794    c = 1;
 1795    break;
 1796
 1797  case C_BAD_ARGUMENT_TYPE_NO_PAIR_ERROR:
 1798    msg = C_text("bad argument type - not a pair");
 1799    c = 1;
 1800    break;
 1801
 1802  case C_BAD_ARGUMENT_TYPE_NO_BOOLEAN_ERROR:
 1803    msg = C_text("bad argument type - not a boolean");
 1804    c = 1;
 1805    break;
 1806
 1807  case C_BAD_ARGUMENT_TYPE_NO_LOCATIVE_ERROR:
 1808    msg = C_text("bad argument type - not a locative");
 1809    c = 1;
 1810    break;
 1811
 1812  case C_BAD_ARGUMENT_TYPE_NO_LIST_ERROR:
 1813    msg = C_text("bad argument type - not a list");
 1814    c = 1;
 1815    break;
 1816
 1817  case C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR:
 1818    msg = C_text("bad argument type - not a number");
 1819    c = 1;
 1820    break;
 1821
 1822  case C_BAD_ARGUMENT_TYPE_NO_SYMBOL_ERROR:
 1823    msg = C_text("bad argument type - not a symbol");
 1824    c = 1;
 1825    break;
 1826
 1827  case C_BAD_ARGUMENT_TYPE_NO_VECTOR_ERROR:
 1828    msg = C_text("bad argument type - not a vector");
 1829    c = 1;
 1830    break;
 1831
 1832  case C_BAD_ARGUMENT_TYPE_NO_CHAR_ERROR:
 1833    msg = C_text("bad argument type - not a character");
 1834    c = 1;
 1835    break;
 1836
 1837  case C_STACK_OVERFLOW_ERROR:
 1838    msg = C_text("stack overflow");
 1839    c = 0;
 1840    break;
 1841
 1842  case C_BAD_ARGUMENT_TYPE_BAD_STRUCT_ERROR:
 1843    msg = C_text("bad argument type - not a structure of the required type");
 1844    c = 2;
 1845    break;
 1846
 1847  case C_BAD_ARGUMENT_TYPE_NO_BYTEVECTOR_ERROR:
 1848    msg = C_text("bad argument type - not a bytevector");
 1849    c = 1;
 1850    break;
 1851
 1852  case C_LOST_LOCATIVE_ERROR:
 1853    msg = C_text("locative refers to reclaimed object");
 1854    c = 1;
 1855    break;
 1856
 1857  case C_BAD_ARGUMENT_TYPE_NO_BLOCK_ERROR:
 1858    msg = C_text("bad argument type - not a object");
 1859    c = 1;
 1860    break;
 1861
 1862  case C_BAD_ARGUMENT_TYPE_NO_NUMBER_VECTOR_ERROR:
 1863    msg = C_text("bad argument type - not a number vector");
 1864    c = 2;
 1865    break;
 1866
 1867  case C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR:
 1868    msg = C_text("bad argument type - not an integer");
 1869    c = 1;
 1870    break;
 1871
 1872  case C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR:
 1873    msg = C_text("bad argument type - not an unsigned integer");
 1874    c = 1;
 1875    break;
 1876
 1877  case C_BAD_ARGUMENT_TYPE_NO_POINTER_ERROR:
 1878    msg = C_text("bad argument type - not a pointer");
 1879    c = 1;
 1880    break;
 1881
 1882  case C_BAD_ARGUMENT_TYPE_NO_TAGGED_POINTER_ERROR:
 1883    msg = C_text("bad argument type - not a tagged pointer");
 1884    c = 2;
 1885    break;
 1886
 1887  case C_BAD_ARGUMENT_TYPE_NO_FLONUM_ERROR:
 1888    msg = C_text("bad argument type - not a flonum");
 1889    c = 1;
 1890    break;
 1891
 1892  case C_BAD_ARGUMENT_TYPE_NO_CLOSURE_ERROR:
 1893    msg = C_text("bad argument type - not a procedure");
 1894    c = 1;
 1895    break;
 1896
 1897  case C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR:
 1898    msg = C_text("bad argument type - invalid base");
 1899    c = 1;
 1900    break;
 1901
 1902  case C_CIRCULAR_DATA_ERROR:
 1903    msg = C_text("recursion too deep or circular data encountered");
 1904    c = 0;
 1905    break;
 1906
 1907  case C_BAD_ARGUMENT_TYPE_NO_PORT_ERROR:
 1908    msg = C_text("bad argument type - not a port");
 1909    c = 1;
 1910    break;
 1911
 1912  case C_BAD_ARGUMENT_TYPE_PORT_DIRECTION_ERROR:
 1913    msg = C_text("bad argument type - not a port of the correct type");
 1914    c = 1;
 1915    break;
 1916
 1917  case C_BAD_ARGUMENT_TYPE_PORT_NO_INPUT_ERROR:
 1918    msg = C_text("bad argument type - not an input-port");
 1919    c = 1;
 1920    break;
 1921
 1922  case C_BAD_ARGUMENT_TYPE_PORT_NO_OUTPUT_ERROR:
 1923    msg = C_text("bad argument type - not an output-port");
 1924    c = 1;
 1925    break;
 1926
 1927  case C_PORT_CLOSED_ERROR:
 1928    msg = C_text("port already closed");
 1929    c = 1;
 1930    break;
 1931
 1932  case C_ASCIIZ_REPRESENTATION_ERROR:
 1933    msg = C_text("cannot represent string with NUL bytes as C string");
 1934    c = 1;
 1935    break;
 1936
 1937  case C_MEMORY_VIOLATION_ERROR:
 1938    msg = C_text("segmentation violation");
 1939    c = 0;
 1940    break;
 1941
 1942  case C_FLOATING_POINT_EXCEPTION_ERROR:
 1943    msg = C_text("floating point exception");
 1944    c = 0;
 1945    break;
 1946
 1947  case C_ILLEGAL_INSTRUCTION_ERROR:
 1948    msg = C_text("illegal instruction");
 1949    c = 0;
 1950    break;
 1951
 1952  case C_BUS_ERROR:
 1953    msg = C_text("bus error");
 1954    c = 0;
 1955    break;
 1956
 1957  case C_BAD_ARGUMENT_TYPE_NO_EXACT_ERROR:
 1958    msg = C_text("bad argument type - not an exact number");
 1959    c = 1;
 1960    break;
 1961
 1962  case C_BAD_ARGUMENT_TYPE_NO_INEXACT_ERROR:
 1963    msg = C_text("bad argument type - not an inexact number");
 1964    c = 1;
 1965    break;
 1966
 1967  case C_BAD_ARGUMENT_TYPE_NO_REAL_ERROR:
 1968    msg = C_text("bad argument type - not an real");
 1969    c = 1;
 1970    break;
 1971
 1972  case C_BAD_ARGUMENT_TYPE_COMPLEX_NO_ORDERING_ERROR:
 1973    msg = C_text("bad argument type - complex number has no ordering");
 1974    c = 1;
 1975    break;
 1976
 1977  case C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR:
 1978    msg = C_text("bad argument type - not an exact integer");
 1979    c = 1;
 1980    break;
 1981
 1982  case C_BAD_ARGUMENT_TYPE_FOREIGN_LIMITATION:
 1983    msg = C_text("number does not fit in foreign type");
 1984    c = 1;
 1985    break;
 1986
 1987  case C_BAD_ARGUMENT_TYPE_COMPLEX_ABS:
 1988    msg = C_text("cannot compute absolute value of complex number");
 1989    c = 1;
 1990    break;
 1991
 1992  case C_REST_ARG_OUT_OF_BOUNDS_ERROR:
 1993    msg = C_text("attempted rest argument access beyond end of list");
 1994    c = 3;
 1995    break;
 1996
 1997  case C_DECODING_ERROR:
 1998    msg = C_text("string contains invalid UTF-8 sequence");
 1999    c = 2;
 2000    break;
 2001
 2002  case C_BAD_ARGUMENT_TYPE_NUMERIC_RANGE_ERROR:
 2003    msg = C_text("bad argument type - value exceeds numeric range");
 2004    c = 1;
 2005    break;
 2006
 2007  default: panic(C_text("illegal internal error code"));
 2008  }
 2009
 2010  if(C_immediatep(err)) {
 2011    C_dbg(C_text("error"), C_text("%s\n"), msg);
 2012    panic(C_text("`##sys#error-hook' is not defined - the `library' unit was probably not linked with this executable"));
 2013  } else {
 2014    av = C_alloc(c + 4);
 2015    va_start(v, loc);
 2016    av[ 0 ] = err;
 2017    /* No continuation is passed: '##sys#error-hook' may not return: */
 2018    av[ 1 ] = C_SCHEME_UNDEFINED;
 2019    av[ 2 ] = C_fix(code);
 2020
 2021    if(loc != NULL)
 2022      av[ 3 ] = intern0(loc);
 2023    else {
 2024      av[ 3 ] = error_location;
 2025      error_location = C_SCHEME_FALSE;
 2026    }
 2027
 2028    for(i = 0; i < c; ++i)
 2029      av[ i + 4 ] = va_arg(v, C_word);
 2030
 2031    va_end(v);
 2032    C_do_apply(c + 4, av);
 2033  }
 2034}
 2035
 2036
 2037/* Never use extended number hook procedure names longer than this! */
 2038/* Current longest name: ##sys#integer->string/recursive */
 2039#define MAX_EXTNUM_HOOK_NAME 32
 2040
 2041/* This exists so that we don't have to create any extra closures */
 2042static void try_extended_number(char *ext_proc_name, C_word c, C_word k, ...)
 2043{
 2044  static C_word ab[C_SIZEOF_STRING(MAX_EXTNUM_HOOK_NAME)];
 2045  int i;
 2046  va_list v;
 2047  C_word ext_proc_sym, ext_proc = C_SCHEME_FALSE, *a = ab;
 2048
 2049  ext_proc_sym = C_lookup_symbol(C_intern2(&a, ext_proc_name));
 2050
 2051  if(!C_immediatep(ext_proc_sym))
 2052    ext_proc = C_block_item(ext_proc_sym, 0);
 2053
 2054  if (!C_immediatep(ext_proc) && C_closurep(ext_proc)) {
 2055    C_word *av = C_alloc(c + 1);
 2056    av[ 0 ] = ext_proc;
 2057    av[ 1 ] = k;
 2058    va_start(v, k);
 2059
 2060    for(i = 0; i < c - 1; ++i)
 2061      av[ i + 2 ] = va_arg(v, C_word);
 2062
 2063    va_end(v);
 2064    C_do_apply(c + 1, av);
 2065  } else {
 2066    barf(C_UNBOUND_VARIABLE_ERROR, NULL, ext_proc_sym);
 2067  }
 2068}
 2069
 2070
 2071/* Hook for setting breakpoints */
 2072
 2073C_word C_dbg_hook(C_word dummy)
 2074{
 2075  return dummy;
 2076}
 2077
 2078
 2079/* Timing routines: */
 2080
 2081/* DEPRECATED */
 2082C_regparm C_u64 C_milliseconds(void)
 2083{
 2084  return C_current_process_milliseconds();
 2085}
 2086
 2087C_regparm C_u64 C_current_process_milliseconds(void)
 2088{
 2089#if defined(__MINGW32__)
 2090# if defined(__MINGW64_VERSION_MAJOR)
 2091    ULONGLONG tick_count = GetTickCount64();
 2092# else
 2093    ULONGLONG tick_count = GetTickCount();
 2094# endif
 2095    return tick_count - (C_startup_time_sec * 1000) - C_startup_time_msec;
 2096#else
 2097    struct timeval tv;
 2098
 2099    if(C_gettimeofday(&tv, NULL) == -1) return 0;
 2100    else return (tv.tv_sec - C_startup_time_sec) * 1000 + tv.tv_usec / 1000 - C_startup_time_msec;
 2101#endif
 2102}
 2103
 2104
 2105C_regparm time_t C_seconds(C_long *ms)
 2106{
 2107#ifdef C_NONUNIX
 2108  if(ms != NULL) *ms = 0;
 2109
 2110  return (time_t)(clock() / CLOCKS_PER_SEC);
 2111#else
 2112  struct timeval tv;
 2113
 2114  if(C_gettimeofday(&tv, NULL) == -1) {
 2115    if(ms != NULL) *ms = 0;
 2116
 2117    return (time_t)0;
 2118  }
 2119  else {
 2120    if(ms != NULL) *ms = tv.tv_usec / 1000;
 2121
 2122    return tv.tv_sec;
 2123  }
 2124#endif
 2125}
 2126
 2127
 2128C_regparm C_u64 C_cpu_milliseconds(void)
 2129{
 2130#if defined(C_NONUNIX) || defined(__CYGWIN__)
 2131    if(CLOCKS_PER_SEC == 1000) return clock();
 2132    else return ((C_u64)clock() / CLOCKS_PER_SEC) * 1000;
 2133#else
 2134    struct rusage ru;
 2135
 2136    if(C_getrusage(RUSAGE_SELF, &ru) == -1) return 0;
 2137    else return (((C_u64)ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) * 1000
 2138                 + ((C_u64)ru.ru_utime.tv_usec + ru.ru_stime.tv_usec) / 1000);
 2139#endif
 2140}
 2141
 2142
 2143/* Support code for callbacks: */
 2144
 2145int C_save_callback_continuation(C_word **ptr, C_word k)
 2146{
 2147  C_word p = C_a_pair(ptr, k, C_block_item(callback_continuation_stack_symbol, 0));
 2148
 2149  C_mutate_slot(&C_block_item(callback_continuation_stack_symbol, 0), p);
 2150  return ++callback_continuation_level;
 2151}
 2152
 2153
 2154C_word C_restore_callback_continuation(void)
 2155{
 2156  /* obsolete, but retained for keeping old code working */
 2157  C_word p = C_block_item(callback_continuation_stack_symbol, 0),
 2158         k;
 2159
 2160  assert(!C_immediatep(p) && C_header_type(p) == C_PAIR_TYPE);
 2161  k = C_u_i_car(p);
 2162
 2163  C_mutate(&C_block_item(callback_continuation_stack_symbol, 0), C_u_i_cdr(p));
 2164  --callback_continuation_level;
 2165  return k;
 2166}
 2167
 2168
 2169C_word C_restore_callback_continuation2(int level)
 2170{
 2171  C_word p = C_block_item(callback_continuation_stack_symbol, 0),
 2172         k;
 2173
 2174  if(level != callback_continuation_level || C_immediatep(p) || C_header_type(p) != C_PAIR_TYPE)
 2175    panic(C_text("unbalanced callback continuation stack"));
 2176
 2177  k = C_u_i_car(p);
 2178
 2179  C_mutate(&C_block_item(callback_continuation_stack_symbol, 0), C_u_i_cdr(p));
 2180  --callback_continuation_level;
 2181  return k;
 2182}
 2183
 2184
 2185C_word C_callback(C_word closure, int argc)
 2186{
 2187#ifdef HAVE_SIGSETJMP
 2188  sigjmp_buf prev;
 2189#else
 2190  jmp_buf prev;
 2191#endif
 2192  C_word
 2193    *a = C_alloc(C_SIZEOF_CLOSURE(2)),
 2194    k = C_closure(&a, 2, (C_word)callback_return_continuation, C_SCHEME_FALSE),
 2195    *av;
 2196  int old = chicken_is_running;
 2197
 2198  if(old && C_block_item(callback_continuation_stack_symbol, 0) == C_SCHEME_END_OF_LIST)
 2199    panic(C_text("callback invoked in non-safe context"));
 2200
 2201  C_memcpy(&prev, &C_restart, sizeof(C_restart));
 2202  callback_returned_flag = 0;
 2203  chicken_is_running = 1;
 2204  av = C_alloc(argc + 2);
 2205  av[ 0 ] = closure;
 2206  av[ 1 ] = k;
 2207  /*XXX is the order of arguments an issue? */
 2208  C_memcpy(av + 2, C_temporary_stack, argc * sizeof(C_word));
 2209  C_temporary_stack = C_temporary_stack_bottom;
 2210
 2211#ifdef HAVE_SIGSETJMP
 2212  if(!C_sigsetjmp(C_restart, 0)) C_do_apply(argc + 2, av);
 2213#else
 2214  if(!C_setjmp(C_restart)) C_do_apply(argc + 2, av);
 2215#endif
 2216
 2217  serious_signal_occurred = 0;
 2218
 2219  if(!callback_returned_flag) {
 2220    /* We must copy the argvector onto the stack, because
 2221     * any subsequent save() will otherwise clobber it.
 2222     */
 2223    C_word *p = C_alloc(C_restart_c);
 2224    assert(C_restart_c == (C_temporary_stack_bottom - C_temporary_stack));
 2225    C_memcpy(p, C_temporary_stack, C_restart_c * sizeof(C_word));
 2226    C_temporary_stack = C_temporary_stack_bottom;
 2227    ((C_proc)C_restart_trampoline)(C_restart_c, p);
 2228  }
 2229  else {
 2230    C_memcpy(&C_restart, &prev, sizeof(C_restart));
 2231    callback_returned_flag = 0;
 2232  }
 2233
 2234  chicken_is_running = old;
 2235  return C_restore;
 2236}
 2237
 2238
 2239void C_callback_adjust_stack(C_word *a, int size)
 2240{
 2241  if(!chicken_is_running && !C_in_stackp((C_word)a)) {
 2242    if(debug_mode)
 2243      C_dbg(C_text("debug"),
 2244	    C_text("callback invoked in lower stack region - adjusting limits:\n"
 2245		   "[debug]   current:  \t%p\n"
 2246		   "[debug]   previous: \t%p (bottom) - %p (limit)\n"),
 2247	    a, stack_bottom, C_stack_limit);
 2248
 2249#if C_STACK_GROWS_DOWNWARD
 2250    C_stack_hard_limit = (C_word *)((C_byte *)a - stack_size);
 2251    stack_bottom = a + size;
 2252#else
 2253    C_stack_hard_limit = (C_word *)((C_byte *)a + stack_size);
 2254    stack_bottom = a;
 2255#endif
 2256    C_stack_limit = C_stack_hard_limit;
 2257
 2258    if(debug_mode)
 2259      C_dbg(C_text("debug"), C_text("new:      \t%p (bottom) - %p (limit)\n"),
 2260	    stack_bottom, C_stack_limit);
 2261  }
 2262}
 2263
 2264
 2265C_word C_callback_wrapper(void *proc, int argc)
 2266{
 2267  C_word
 2268    *a = C_alloc(C_SIZEOF_CLOSURE(1)),
 2269    closure = C_closure(&a, 1, (C_word)proc),
 2270    result;
 2271
 2272  result = C_callback(closure, argc);
 2273  assert(C_temporary_stack == C_temporary_stack_bottom);
 2274  return result;
 2275}
 2276
 2277
 2278void C_ccall callback_return_continuation(C_word c, C_word *av)
 2279{
 2280  C_word self = av[0];
 2281  C_word r = av[1];
 2282
 2283  if(C_block_item(self, 1) == C_SCHEME_TRUE)
 2284    panic(C_text("callback returned twice"));
 2285
 2286  assert(callback_returned_flag == 0);
 2287  callback_returned_flag = 1;
 2288  C_set_block_item(self, 1, C_SCHEME_TRUE);
 2289  C_save(r);
 2290  C_reclaim(NULL, 0);
 2291}
 2292
 2293
 2294/* Register/unregister literal frame: */
 2295
 2296void C_initialize_lf(C_word *lf, int count)
 2297{
 2298  while(count-- > 0)
 2299    *(lf++) = C_SCHEME_UNBOUND;
 2300}
 2301
 2302
 2303void *C_register_lf(C_word *lf, int count)
 2304{
 2305  return C_register_lf2(lf, count, NULL);
 2306}
 2307
 2308
 2309void *C_register_lf2(C_word *lf, int count, C_PTABLE_ENTRY *ptable)
 2310{
 2311  LF_LIST *node = (LF_LIST *)C_malloc(sizeof(LF_LIST));
 2312  LF_LIST *np;
 2313  int status = 0;
 2314
 2315  node->lf = lf;
 2316  node->count = count;
 2317  node->ptable = ptable;
 2318  node->module_name = current_module_name;
 2319  node->module_handle = current_module_handle;
 2320  current_module_handle = NULL;
 2321
 2322  if(lf_list) lf_list->prev = node;
 2323
 2324  node->next = lf_list;
 2325  node->prev = NULL;
 2326  lf_list = node;
 2327  return (void *)node;
 2328}
 2329
 2330
 2331LF_LIST *find_module_handle(char *name)
 2332{
 2333  LF_LIST *np;
 2334
 2335  for(np = lf_list; np != NULL; np = np->next) {
 2336    if(np->module_name != NULL && !C_strcmp(np->module_name, name))
 2337      return np;
 2338  }
 2339
 2340  return NULL;
 2341}
 2342
 2343
 2344void C_unregister_lf(void *handle)
 2345{
 2346  LF_LIST *node = (LF_LIST *) handle;
 2347
 2348  if (node->next) node->next->prev = node->prev;
 2349
 2350  if (node->prev) node->prev->next = node->next;
 2351
 2352  if (lf_list == node) lf_list = node->next;
 2353
 2354  C_free(node->module_name);
 2355  C_free(node);
 2356}
 2357
 2358
 2359/* Intern symbol into symbol-table: */
 2360
 2361C_regparm C_word C_intern(C_word **ptr, int len, C_char *str)
 2362{
 2363  return C_intern_in(ptr, len, str, symbol_table);
 2364}
 2365
 2366
 2367C_regparm C_word C_h_intern(C_word *slot, int len, C_char *str)
 2368{
 2369  return C_h_intern_in(slot, len, str, symbol_table);
 2370}
 2371
 2372
 2373C_regparm C_word C_intern_kw(C_word **ptr, int len, C_char *str)
 2374{
 2375  C_word kw = C_intern_in(ptr, len, str, keyword_table);
 2376  C_set_block_item(kw, 0, kw); /* Keywords evaluate to themselves */
 2377  C_set_block_item(kw, 2, C_SCHEME_FALSE); /* Keywords have no plists */
 2378  return kw;
 2379}
 2380
 2381
 2382C_regparm C_word C_h_intern_kw(C_word *slot, int len, C_char *str)
 2383{
 2384  C_word kw = C_h_intern_in(slot, len, str, keyword_table);
 2385  C_set_block_item(kw, 0, kw); /* Keywords evaluate to themselves */
 2386  C_set_block_item(kw, 2, C_SCHEME_FALSE); /* Keywords have no plists */
 2387  return kw;
 2388}
 2389
 2390C_regparm C_word C_intern_in(C_word **ptr, int len, C_char *str, C_SYMBOL_TABLE *stable)
 2391{
 2392  int key;
 2393  C_word s;
 2394
 2395  if(stable == NULL) stable = symbol_table;
 2396
 2397  key = hash_string(len, str, stable->size, stable->rand);
 2398
 2399  if(C_truep(s = lookup(key, len, str, stable))) return s;
 2400
 2401  s = C_bytevector(ptr, len + 1, str);
 2402  return add_symbol(ptr, key, s, stable);
 2403}
 2404
 2405
 2406C_regparm C_word C_h_intern_in(C_word *slot, int len, C_char *str, C_SYMBOL_TABLE *stable)
 2407{
 2408  /* Intern as usual, but remember slot, and allocate in static
 2409   * memory.  If symbol already exists, replace its string by a fresh
 2410   * statically allocated string to ensure it never gets collected, as
 2411   * lf[] entries are not tracked by the GC.
 2412   */
 2413  int key;
 2414  C_word s, bv;
 2415
 2416  if(stable == NULL) stable = symbol_table;
 2417
 2418  key = hash_string(len, str, stable->size, stable->rand);
 2419
 2420  if(C_truep(s = lookup(key, len, str, stable))) {
 2421    if(C_in_stackp(s)) C_mutate_slot(slot, s);
 2422
 2423    if(!C_truep(C_permanentp(C_symbol_name(s)))) {
 2424      /* Replace by statically allocated string, and persist it */
 2425      bv = C_static_bytevector(C_heaptop, len + 1, str);
 2426      C_c_bytevector(bv)[ len ] = 0;
 2427      C_set_block_item(s, 1, bv);
 2428      C_i_persist_symbol(s);
 2429    }
 2430    return s;
 2431  }
 2432
 2433  bv = C_static_bytevector(C_heaptop, len + 1, str);
 2434  C_c_bytevector(bv)[ len ] = 0;
 2435  return add_symbol(C_heaptop, key, bv, stable);
 2436}
 2437
 2438
 2439C_regparm C_word intern0(C_char *str)
 2440{
 2441  int len = C_strlen(str);
 2442  int key = hash_string(len, str, symbol_table->size, symbol_table->rand);
 2443  C_word s;
 2444
 2445  if(C_truep(s = lookup(key, len, str, symbol_table))) return s;
 2446  else return C_SCHEME_FALSE;
 2447}
 2448
 2449
 2450C_regparm C_word C_lookup_symbol(C_word sym)
 2451{
 2452  int key;
 2453  C_word bv = C_block_item(sym, 1);
 2454  int len = C_header_size(bv) - 1;
 2455
 2456  key = hash_string(len, C_c_string(bv), symbol_table->size, symbol_table->rand);
 2457
 2458  return lookup(key, len, C_c_string(bv), symbol_table);
 2459}
 2460
 2461
 2462C_regparm C_word C_intern2(C_word **ptr, C_char *str)
 2463{
 2464  return C_intern_in(ptr, C_strlen(str), str, symbol_table);
 2465}
 2466
 2467
 2468C_regparm C_word C_intern3(C_word **ptr, C_char *str, C_word value)
 2469{
 2470  C_word s = C_intern_in(ptr, C_strlen(str), str, symbol_table);
 2471
 2472  C_mutate(&C_block_item(s,0), value);
 2473  C_i_persist_symbol(s); /* Symbol has a value now; persist it */
 2474  return s;
 2475}
 2476
 2477
 2478C_regparm C_word hash_string(int len, C_char *str, C_word m, C_word r)
 2479{
 2480  C_uword key = r;
 2481
 2482  while(len--)
 2483      key ^= (key << 6) + (key >> 2) + *(str++);
 2484
 2485  return (C_word)(key % (C_uword)m);
 2486}
 2487
 2488
 2489C_regparm C_word lookup(C_word key, int len, C_char *str, C_SYMBOL_TABLE *stable)
 2490{
 2491  C_word bucket, last = 0, sym, s;
 2492
 2493  for(bucket = stable->table[ key ]; bucket != C_SCHEME_END_OF_LIST;
 2494      bucket = C_block_item(bucket,1)) {
 2495    sym = C_block_item(bucket,0);
 2496
 2497    /* If the symbol is unreferenced, drop it: */
 2498    if (sym == C_SCHEME_BROKEN_WEAK_PTR) {
 2499       if (last) C_set_block_item(last, 1, C_block_item(bucket, 1));
 2500       else stable->table[ key ] = C_block_item(bucket,1);
 2501    } else {
 2502      last = bucket;
 2503      s = C_block_item(sym, 1);
 2504
 2505      if(C_header_size(s) - 1 == (C_word)len
 2506         && !C_memcmp(str, (C_char *)C_data_pointer(s), len))
 2507        return sym;
 2508    }
 2509  }
 2510
 2511  return C_SCHEME_FALSE;
 2512}
 2513
 2514/* Mark a symbol as "persistent", to prevent it from being GC'ed */
 2515C_regparm C_word C_i_persist_symbol(C_word sym)
 2516{
 2517  C_word bucket;
 2518  C_SYMBOL_TABLE *stp;
 2519
 2520  /* Normally, this will get called with a symbol, but in
 2521   * C_h_intern_kw we may call it with keywords too.
 2522   */
 2523  if(!C_truep(C_i_symbolp(sym)) && !C_truep(C_i_keywordp(sym))) {
 2524    error_location = C_SCHEME_FALSE;
 2525    barf(C_BAD_ARGUMENT_TYPE_NO_SYMBOL_ERROR, NULL, sym);
 2526  }
 2527
 2528  for(stp = symbol_table_list; stp != NULL; stp = stp->next) {
 2529    bucket = lookup_bucket(sym, stp);
 2530
 2531    if (C_truep(bucket)) {
 2532      /* Change weak to strong ref to ensure long-term survival */
 2533      C_block_header(bucket) = C_block_header(bucket) & ~C_SPECIALBLOCK_BIT;
 2534      /* Ensure survival on next minor GC */
 2535      if (C_in_stackp(sym)) C_mutate_slot(&C_block_item(bucket, 0), sym);
 2536    }
 2537  }
 2538  return C_SCHEME_UNDEFINED;
 2539}
 2540
 2541/* Possibly remove "persistence" of symbol, to allowed it to be GC'ed.
 2542 * This is only done if the symbol is unbound, has an empty plist and
 2543 * is allocated in managed memory.
 2544 */
 2545C_regparm C_word C_i_unpersist_symbol(C_word sym)
 2546{
 2547  C_word bucket;
 2548  C_SYMBOL_TABLE *stp;
 2549
 2550  C_i_check_symbol(sym);
 2551
 2552  if (C_persistable_symbol(sym) ||
 2553      C_truep(C_permanentp(C_symbol_name(sym)))) {
 2554    return C_SCHEME_FALSE;
 2555  }
 2556
 2557  for(stp = symbol_table_list; stp != NULL; stp = stp->next) {
 2558    bucket = lookup_bucket(sym, NULL);
 2559
 2560    if (C_truep(bucket)) {
 2561      /* Turn it into a weak ref */
 2562      C_block_header(bucket) = C_block_header(bucket) | C_SPECIALBLOCK_BIT;
 2563      return C_SCHEME_TRUE;
 2564    }
 2565  }
 2566  return C_SCHEME_FALSE;
 2567}
 2568
 2569C_regparm C_word lookup_bucket(C_word sym, C_SYMBOL_TABLE *stable)
 2570{
 2571  C_word bucket, str = C_block_item(sym, 1);
 2572  int key, len = C_header_size(str) - 1;
 2573
 2574  if (stable == NULL) stable = symbol_table;
 2575
 2576  key = hash_string(len, C_c_string(str), stable->size, stable->rand);
 2577
 2578  for(bucket = stable->table[ key ]; bucket != C_SCHEME_END_OF_LIST;
 2579      bucket = C_block_item(bucket,1)) {
 2580    if (C_block_item(bucket,0) == sym) return bucket;
 2581  }
 2582  return C_SCHEME_FALSE;
 2583}
 2584
 2585
 2586double compute_symbol_table_load(double *avg_bucket_len, int *total_n)
 2587{
 2588  C_word bucket, last;
 2589  int i, j, alen = 0, bcount = 0, total = 0;
 2590
 2591  for(i = 0; i < symbol_table->size; ++i) {
 2592    last = 0;
 2593    j = 0;
 2594    for(bucket = symbol_table->table[ i ]; bucket != C_SCHEME_END_OF_LIST;
 2595        bucket = C_block_item(bucket,1)) {
 2596      /* If the symbol is unreferenced, drop it: */
 2597      if (C_block_item(bucket,0) == C_SCHEME_BROKEN_WEAK_PTR) {
 2598         if (last) C_set_block_item(last, 1, C_block_item(bucket, 1));
 2599         else symbol_table->table[ i ] = C_block_item(bucket,1);
 2600      } else {
 2601        last = bucket;
 2602        ++j;
 2603      }
 2604    }
 2605
 2606    if(j > 0) {
 2607      alen += j;
 2608      ++bcount;
 2609    }
 2610
 2611    total += j;
 2612  }
 2613
 2614  if(avg_bucket_len != NULL)
 2615    *avg_bucket_len = (double)alen / (double)bcount;
 2616
 2617  *total_n = total;
 2618
 2619  /* return load: */
 2620  return (double)total / (double)symbol_table->size;
 2621}
 2622
 2623
 2624C_word add_symbol(C_word **ptr, C_word key, C_word bv, C_SYMBOL_TABLE *stable)
 2625{
 2626  C_word bucket, sym, b2, *p;
 2627
 2628  p = *ptr;
 2629  sym = (C_word)p;
 2630  p += C_SIZEOF_SYMBOL;
 2631  C_block_header_init(sym, C_SYMBOL_TAG);
 2632  C_set_block_item(sym, 0, C_SCHEME_UNBOUND);
 2633  C_set_block_item(sym, 1, bv);
 2634  C_set_block_item(sym, 2, C_SCHEME_END_OF_LIST);
 2635  *ptr = p;
 2636  b2 = stable->table[ key ];	/* previous bucket */
 2637
 2638  /* Create new weak or strong bucket depending on persistability */
 2639  if (C_truep(C_permanentp(bv))) {
 2640    bucket = C_a_pair(ptr, sym, b2);
 2641  } else {
 2642    bucket = C_a_weak_pair(ptr, sym, b2);
 2643  }
 2644
 2645  if(ptr != C_heaptop) C_mutate_slot(&stable->table[ key ], bucket);
 2646  else {
 2647    /* If a stack-allocated bucket was here, and we allocate from
 2648       heap-top (say, in a toplevel literal frame allocation) then we have
 2649       to inform the memory manager that a 2nd gen. block points to a
 2650       1st gen. block, hence the mutation: */
 2651    C_mutate(&C_block_item(bucket,1), b2);
 2652    stable->table[ key ] = bucket;
 2653  }
 2654
 2655  return sym;
 2656}
 2657
 2658
 2659C_regparm int C_in_stackp(C_word x)
 2660{
 2661  C_word *ptr = (C_word *)(C_uword)x;
 2662
 2663#if C_STACK_GROWS_DOWNWARD
 2664  return ptr >= C_stack_pointer_test && ptr <= stack_bottom;
 2665#else
 2666  return ptr < C_stack_pointer_test && ptr >= stack_bottom;
 2667#endif
 2668}
 2669
 2670
 2671C_regparm int C_in_heapp(C_word x)
 2672{
 2673  C_byte *ptr = (C_byte *)(C_uword)x;
 2674  return (ptr >= fromspace_start && ptr < C_fromspace_limit) ||
 2675         (ptr >= tospace_start && ptr < tospace_limit);
 2676}
 2677
 2678/* Only used during major GC (heap realloc) */
 2679static C_regparm int C_in_new_heapp(C_word x)
 2680{
 2681  C_byte *ptr = (C_byte *)(C_uword)x;
 2682  return (ptr >= new_tospace_start && ptr < new_tospace_limit);
 2683}
 2684
 2685C_regparm int C_in_fromspacep(C_word x)
 2686{
 2687  C_byte *ptr = (C_byte *)(C_uword)x;
 2688  return (ptr >= fromspace_start && ptr < C_fromspace_limit);
 2689}
 2690
 2691C_regparm int C_in_scratchspacep(C_word x)
 2692{
 2693  C_word *ptr = (C_word *)(C_uword)x;
 2694  return (ptr >= C_scratchspace_start && ptr < C_scratchspace_limit);
 2695}
 2696
 2697/* Cons the rest-aguments together: */
 2698
 2699C_regparm C_word C_build_rest(C_word **ptr, C_word c, C_word n, C_word *av)
 2700{
 2701  C_word
 2702    x = C_SCHEME_END_OF_LIST,
 2703    *p = *ptr;
 2704  C_SCHEME_BLOCK *node;
 2705
 2706  av += c;
 2707
 2708  while(--c >= n) {
 2709    node = (C_SCHEME_BLOCK *)p;
 2710    p += 3;
 2711    node->header = C_PAIR_TYPE | (C_SIZEOF_PAIR - 1);
 2712    node->data[ 0 ] = *(--av);
 2713    node->data[ 1 ] = x;
 2714    x = (C_word)node;
 2715  }
 2716
 2717  *ptr = p;
 2718  return x;
 2719}
 2720
 2721
 2722/* Print error messages and exit: */
 2723
 2724void C_bad_memory(void)
 2725{
 2726  panic(C_text("there is not enough stack-space to run this executable"));
 2727}
 2728
 2729
 2730void C_bad_memory_2(void)
 2731{
 2732  panic(C_text("there is not enough heap-space to run this executable - try using the '-:h...' option"));
 2733}
 2734
 2735
 2736/* The following two can be thrown out in the next release... */
 2737
 2738void C_bad_argc(int c, int n)
 2739{
 2740  C_bad_argc_2(c, n, C_SCHEME_FALSE);
 2741}
 2742
 2743
 2744void C_bad_min_argc(int c, int n)
 2745{
 2746  C_bad_min_argc_2(c, n, C_SCHEME_FALSE);
 2747}
 2748
 2749
 2750void C_bad_argc_2(int c, int n, C_word closure)
 2751{
 2752  barf(C_BAD_ARGUMENT_COUNT_ERROR, NULL, C_fix(n - 2), C_fix(c - 2), closure);
 2753}
 2754
 2755
 2756void C_bad_min_argc_2(int c, int n, C_word closure)
 2757{
 2758  barf(C_BAD_MINIMUM_ARGUMENT_COUNT_ERROR, NULL, C_fix(n - 2), C_fix(c - 2), closure);
 2759}
 2760
 2761
 2762void C_stack_overflow(C_char *loc)
 2763{
 2764  barf(C_STACK_OVERFLOW_ERROR, loc);
 2765}
 2766
 2767
 2768void C_no_closure_error(C_word x)
 2769{
 2770  barf(C_NOT_A_CLOSURE_ERROR, NULL, x);
 2771}
 2772
 2773
 2774void C_div_by_zero_error(C_char *loc)
 2775{
 2776  barf(C_DIVISION_BY_ZERO_ERROR, loc);
 2777}
 2778
 2779void C_unimplemented(C_char *msg)
 2780{
 2781	C_fprintf(C_stderr, C_text("Error: unimplemented feature: %s\n"), msg);
 2782  	C_exit_runtime(C_fix(EX_SOFTWARE));
 2783}
 2784
 2785void C_not_an_integer_error(C_char *loc, C_word x)
 2786{
 2787  barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, loc, x);
 2788}
 2789
 2790void C_not_an_uinteger_error(C_char *loc, C_word x)
 2791{
 2792  barf(C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR, loc, x);
 2793}
 2794
 2795void C_rest_arg_out_of_bounds_error(C_word c, C_word n, C_word ka)
 2796{
 2797  C_rest_arg_out_of_bounds_error_2(c, n, ka, C_SCHEME_FALSE);
 2798}
 2799
 2800void C_rest_arg_out_of_bounds_error_2(C_word c, C_word n, C_word ka, C_word closure)
 2801{
 2802  barf(C_REST_ARG_OUT_OF_BOUNDS_ERROR, NULL, C_u_fixnum_difference(c, ka), C_u_fixnum_difference(n, ka), closure);
 2803}
 2804
 2805/* Allocate and initialize record: */
 2806
 2807C_regparm C_word C_string(C_word **ptr, int len, C_char *str)
 2808{
 2809  C_word buf = C_bytevector(ptr, len + 1, str);
 2810  C_word s = (C_word)(*ptr);
 2811  int n;
 2812  *ptr += 5; /* C_SIZEOF_STRING */
 2813  C_c_bytevector(buf)[ len ] = 0;
 2814  C_block_header_init(s, C_STRING_TAG);
 2815  C_set_block_item(s, 0, buf);
 2816  n = C_utf_count(str, len);
 2817  C_set_block_item(s, 1, C_fix(n));
 2818  C_set_block_item(s, 2, C_fix(0));
 2819  C_set_block_item(s, 3, C_fix(0));
 2820  return s;
 2821}
 2822
 2823C_regparm C_word C_static_string(C_word **ptr, int len, C_char *str)
 2824{
 2825  C_word buf = C_static_bytevector(ptr, len + 1, str);
 2826  C_word s = (C_word)(*ptr);
 2827  int n;
 2828  *ptr += 5; /* C_SIZEOF_STRING */
 2829  C_c_bytevector(buf)[ len ] = 0;
 2830  C_block_header_init(s, C_STRING_TAG);
 2831  C_set_block_item(s, 0, buf);
 2832  n = C_utf_count(str, len);
 2833  C_set_block_item(s, 1, C_fix(n));
 2834  C_set_block_item(s, 2, C_fix(0));
 2835  C_set_block_item(s, 3, C_fix(0));
 2836  return s;
 2837}
 2838
 2839C_regparm C_word C_static_bignum(C_word **ptr, int len, C_char *str)
 2840{
 2841  C_word *dptr, bignum, bigvec, retval, size, negp = 0;
 2842
 2843  if (*str == '+' || *str == '-') {
 2844    negp = ((*str++) == '-') ? 1 : 0;
 2845    --len;
 2846  }
 2847  size = C_BIGNUM_BITS_TO_DIGITS((unsigned int)len << 2);
 2848
 2849  dptr = (C_word *)C_malloc(C_wordstobytes(C_SIZEOF_INTERNAL_BIGNUM_VECTOR(size)));
 2850  if(dptr == NULL)
 2851    panic(C_text("out of memory - cannot allocate static bignum"));
 2852
 2853  bigvec = (C_word)dptr;
 2854  C_block_header_init(bigvec, C_BYTEVECTOR_TYPE | C_wordstobytes(size + 1));
 2855  C_set_block_item(bigvec, 0, negp);
 2856  /* This needs to be allocated at ptr, not dptr, because GC moves type tag */
 2857  bignum = C_a_i_bignum_wrapper(ptr, bigvec);
 2858
 2859  retval = str_to_bignum(bignum, str, str + len, 16);
 2860  if (retval & C_FIXNUM_BIT)
 2861    C_free(dptr); /* Might have been simplified */
 2862  return retval;
 2863}
 2864
 2865C_regparm C_word C_static_lambda_info(C_word **ptr, int len, C_char *str)
 2866{
 2867  int dlen = sizeof(C_header) + C_align(len);
 2868  void *dptr = C_malloc(dlen);
 2869  C_word strblock;
 2870
 2871  if(dptr == NULL)
 2872    panic(C_text("out of memory - cannot allocate static lambda info"));
 2873
 2874  strblock = (C_word)dptr;
 2875  C_block_header_init(strblock, C_LAMBDA_INFO_TYPE | len);
 2876  C_memcpy(C_data_pointer(strblock), str, len);
 2877  return strblock;
 2878}
 2879
 2880
 2881C_regparm C_word C_bytevector(C_word **ptr, int len, C_char *str)
 2882{
 2883  C_word block = (C_word)(*ptr);
 2884  *ptr = (C_word *)((C_word)(*ptr) + sizeof(C_header) + C_align(len));
 2885  C_block_header_init(block, C_BYTEVECTOR_TYPE | len);
 2886  C_memcpy(C_data_pointer(block), str, len);
 2887  return block;
 2888}
 2889
 2890
 2891C_regparm C_word C_static_bytevector(C_word **ptr, int len, C_char *str)
 2892{
 2893  /* we need to add 4 here, as utf8_decode does 3-byte lookahead */
 2894  C_word *dptr = (C_word *)C_malloc(sizeof(C_header) + C_align(len + 4));
 2895  C_word block;
 2896
 2897  if(dptr == NULL)
 2898    panic(C_text("out of memory - cannot allocate static bytevector"));
 2899
 2900  block = (C_word)dptr;
 2901  C_block_header_init(block, C_BYTEVECTOR_TYPE | len);
 2902  C_memcpy(C_data_pointer(block), str, len);
 2903  return block;
 2904}
 2905
 2906
 2907C_regparm C_word C_pbytevector(int len, C_char *str)
 2908{
 2909  C_SCHEME_BLOCK *pbv = C_malloc(len + sizeof(C_header));
 2910
 2911  if(pbv == NULL) panic(C_text("out of memory - cannot allocate permanent bytevector"));
 2912
 2913  pbv->header = C_BYTEVECTOR_TYPE | len;
 2914  C_memcpy(pbv->data, str, len);
 2915  return (C_word)pbv;
 2916}
 2917
 2918
 2919C_regparm C_word C_string2(C_word **ptr, C_char *str)
 2920{
 2921  C_word strblock = (C_word)(*ptr);
 2922  int len;
 2923
 2924  if(str == NULL) return C_SCHEME_FALSE;
 2925
 2926  len = C_strlen(str);
 2927  return C_string(ptr, len, str);
 2928}
 2929
 2930
 2931C_regparm C_word C_string2_safe(C_word **ptr, int max, C_char *str)
 2932{
 2933  C_word strblock = (C_word)(*ptr);
 2934  int len;
 2935
 2936  if(str == NULL) return C_SCHEME_FALSE;
 2937
 2938  len = C_strlen(str);
 2939
 2940  if(len >= max) {
 2941    C_snprintf(buffer, sizeof(buffer), C_text("foreign string result exceeded maximum of %d bytes"), max);
 2942    panic(buffer);
 2943  }
 2944
 2945  return C_string(ptr, len, str);
 2946}
 2947
 2948
 2949C_word C_closure(C_word **ptr, int cells, C_word proc, ...)
 2950{
 2951  va_list va;
 2952  C_word *p = *ptr,
 2953         *p0 = p;
 2954
 2955  *p = C_CLOSURE_TYPE | cells;
 2956  *(++p) = proc;
 2957
 2958  for(va_start(va, proc); --cells; *(++p) = va_arg(va, C_word));
 2959
 2960  va_end(va);
 2961  *ptr = p + 1;
 2962  return (C_word)p0;
 2963}
 2964
 2965
 2966/* obsolete: replaced by C_a_pair in chicken.h */
 2967C_regparm C_word C_pair(C_word **ptr, C_word car, C_word cdr)
 2968{
 2969  C_word *p = *ptr,
 2970         *p0 = p;
 2971
 2972  *(p++) = C_PAIR_TYPE | (C_SIZEOF_PAIR - 1);
 2973  *(p++) = car;
 2974  *(p++) = cdr;
 2975  *ptr = p;
 2976  return (C_word)p0;
 2977}
 2978
 2979
 2980C_regparm C_word C_number(C_word **ptr, double n)
 2981{
 2982  C_word
 2983    *p = *ptr,
 2984    *p0;
 2985  double m;
 2986
 2987  if(n <= (double)C_MOST_POSITIVE_FIXNUM
 2988     && n >= (double)C_MOST_NEGATIVE_FIXNUM && modf(n, &m) == 0.0) {
 2989    return C_fix(n);
 2990  }
 2991
 2992#ifndef C_SIXTY_FOUR
 2993#ifndef C_DOUBLE_IS_32_BITS
 2994  /* Align double on 8-byte boundary: */
 2995  if(C_aligned8(p)) ++p;
 2996#endif
 2997#endif
 2998
 2999  p0 = p;
 3000  *(p++) = C_FLONUM_TAG;
 3001  *((double *)p) = n;
 3002  *ptr = p + sizeof(double) / sizeof(C_word);
 3003  return (C_word)p0;
 3004}
 3005
 3006
 3007C_regparm C_word C_mpointer(C_word **ptr, void *mp)
 3008{
 3009  C_word
 3010    *p = *ptr,
 3011    *p0 = p;
 3012
 3013  *(p++) = C_POINTER_TYPE | 1;
 3014  *((void **)p) = mp;
 3015  *ptr = p + 1;
 3016  return (C_word)p0;
 3017}
 3018
 3019
 3020C_regparm C_word C_mpointer_or_false(C_word **ptr, void *mp)
 3021{
 3022  C_word
 3023    *p = *ptr,
 3024    *p0 = p;
 3025
 3026  if(mp == NULL) return C_SCHEME_FALSE;
 3027
 3028  *(p++) = C_POINTER_TYPE | 1;
 3029  *((void **)p) = mp;
 3030  *ptr = p + 1;
 3031  return (C_word)p0;
 3032}
 3033
 3034
 3035C_regparm C_word C_taggedmpointer(C_word **ptr, C_word tag, void *mp)
 3036{
 3037  C_word
 3038    *p = *ptr,
 3039    *p0 = p;
 3040
 3041  *(p++) = C_TAGGED_POINTER_TAG;
 3042  *((void **)p) = mp;
 3043  *(++p) = tag;
 3044  *ptr = p + 1;
 3045  return (C_word)p0;
 3046}
 3047
 3048
 3049C_regparm C_word C_taggedmpointer_or_false(C_word **ptr, C_word tag, void *mp)
 3050{
 3051  C_word
 3052    *p = *ptr,
 3053    *p0 = p;
 3054
 3055  if(mp == NULL) return C_SCHEME_FALSE;
 3056
 3057  *(p++) = C_TAGGED_POINTER_TAG;
 3058  *((void **)p) = mp;
 3059  *(++p) = tag;
 3060  *ptr = p + 1;
 3061  return (C_word)p0;
 3062}
 3063
 3064
 3065C_word C_vector(C_word **ptr, int n, ...)
 3066{
 3067  va_list v;
 3068  C_word
 3069    *p = *ptr,
 3070    *p0 = p;
 3071
 3072  *(p++) = C_VECTOR_TYPE | n;
 3073  va_start(v, n);
 3074
 3075  while(n--)
 3076    *(p++) = va_arg(v, C_word);
 3077
 3078  *ptr = p;
 3079  va_end(v);
 3080  return (C_word)p0;
 3081}
 3082
 3083
 3084C_word C_structure(C_word **ptr, int n, ...)
 3085{
 3086  va_list v;
 3087  C_word *p = *ptr,
 3088         *p0 = p;
 3089
 3090  *(p++) = C_STRUCTURE_TYPE | n;
 3091  va_start(v, n);
 3092
 3093  while(n--)
 3094    *(p++) = va_arg(v, C_word);
 3095
 3096  *ptr = p;
 3097  va_end(v);
 3098  return (C_word)p0;
 3099}
 3100
 3101
 3102C_regparm C_word
 3103C_mutate_slot(C_word *slot, C_word val)
 3104{
 3105  unsigned int mssize, newmssize, bytes;
 3106
 3107  ++mutation_count;
 3108  /* Mutation stack exists to track mutations pointing from elsewhere
 3109   * into nursery.  Stuff pointing anywhere else can be skipped, as
 3110   * well as mutations on nursery objects.
 3111   */
 3112  if(C_in_stackp((C_word)slot) || (!C_in_stackp(val) && !C_in_scratchspacep(val)))
 3113    return *slot = val;
 3114
 3115#ifdef C_GC_HOOKS
 3116  if(C_gc_mutation_hook != NULL && C_gc_mutation_hook(slot, val)) return val;
 3117#endif
 3118
 3119  if(mutation_stack_top >= mutation_stack_limit) {
 3120    assert(mutation_stack_top == mutation_stack_limit);
 3121    mssize = mutation_stack_top - mutation_stack_bottom;
 3122    newmssize = mssize * 2;
 3123    bytes = newmssize * sizeof(C_word *);
 3124
 3125    if(debug_mode)
 3126      C_dbg(C_text("debug"), C_text("resizing mutation stack from %uk to %uk ...\n"),
 3127	    (mssize * sizeof(C_word *)) / 1024, bytes / 1024);
 3128
 3129    mutation_stack_bottom = (C_word **)realloc(mutation_stack_bottom, bytes);
 3130
 3131    if(mutation_stack_bottom == NULL)
 3132      panic(C_text("out of memory - cannot re-allocate mutation stack"));
 3133
 3134    mutation_stack_limit = mutation_stack_bottom + newmssize;
 3135    mutation_stack_top = mutation_stack_bottom + mssize;
 3136  }
 3137
 3138  *(mutation_stack_top++) = slot;
 3139  ++tracked_mutation_count;
 3140  return *slot = val;
 3141}
 3142
 3143/* Allocate memory in scratch space, "size" is in words, like C_alloc.
 3144 * The memory in the scratch space is laid out as follows: First,
 3145 * there's a count that indicates how big the object originally was,
 3146 * followed by a pointer to the slot in the object which points to the
 3147 * object in scratch space, finally followed by the object itself.
 3148 * The reason we store the slot pointer is so that we can figure out
 3149 * whether the object is still "live" when reallocating; that's
 3150 * because we don't have a saved continuation from where we can trace
 3151 * the live data.  The reason we store the total length of the object
 3152 * is because we may be mutating in-place the lengths of the stored
 3153 * objects, and we need to know how much to skip over while scanning.
 3154 *
 3155 * If the allocating function returns, it *must* first mark all the
 3156 * values in scratch space as reclaimable.  This is needed because
 3157 * there is no way to distinguish between a stale pointer into scratch
 3158 * space that's still somewhere on the stack in "uninitialized" memory
 3159 * versus a word that's been recycled by the next called function,
 3160 * which now holds a value that happens to have the same bit pattern
 3161 * but represents another thing entirely.
 3162 */
 3163C_regparm C_word C_scratch_alloc(C_uword size)
 3164{
 3165  C_word result;
 3166
 3167  if (C_scratchspace_top + size + 2 >= C_scratchspace_limit) {
 3168    C_word *new_scratch_start, *new_scratch_top, *new_scratch_limit;
 3169    C_uword needed = C_scratch_usage + size + 2,
 3170            new_size = nmax(scratchspace_size << 1, 2UL << C_ilen(needed));
 3171
 3172    /* Shrink if the needed size is much smaller, but not below minimum */
 3173    if (needed < (new_size >> 4)) new_size >>= 1;
 3174    new_size = nmax(new_size, DEFAULT_SCRATCH_SPACE_SIZE);
 3175
 3176    /* TODO: Maybe we should work with two semispaces to reduce mallocs? */
 3177    new_scratch_start = (C_word *)C_malloc(C_wordstobytes(new_size));
 3178    if (new_scratch_start == NULL)
 3179      panic(C_text("out of memory - cannot (re-)allocate scratch space"));
 3180    new_scratch_top = new_scratch_start;
 3181    new_scratch_limit = new_scratch_start + new_size;
 3182
 3183    if(debug_mode) {
 3184      C_dbg(C_text("debug"), C_text("resizing scratchspace dynamically from "
 3185				    UWORD_COUNT_FORMAT_STRING "k to "
 3186				    UWORD_COUNT_FORMAT_STRING "k ...\n"),
 3187	    C_wordstobytes(scratchspace_size) / 1024,
 3188            C_wordstobytes(new_size) / 1024);
 3189    }
 3190
 3191    if(gc_report_flag) {
 3192      C_dbg(C_text("GC"), C_text("(old) scratchspace: \tstart=" UWORD_FORMAT_STRING
 3193				 ", \tlimit=" UWORD_FORMAT_STRING "\n"),
 3194            (C_word)C_scratchspace_start, (C_word)C_scratchspace_limit);
 3195      C_dbg(C_text("GC"), C_text("(new) scratchspace:   \tstart=" UWORD_FORMAT_STRING
 3196                                 ", \tlimit=" UWORD_FORMAT_STRING "\n"),
 3197            (C_word)new_scratch_start, (C_word)new_scratch_limit);
 3198    }
 3199
 3200    /* Move scratch data into new space and mutate slots pointing there.
 3201     * This is basically a much-simplified version of really_mark.
 3202     */
 3203    if (C_scratchspace_start != NULL) {
 3204      C_word val, *sscan, *slot;
 3205      C_uword n, words;
 3206      C_header h;
 3207      C_SCHEME_BLOCK *p, *p2;
 3208
 3209      sscan = C_scratchspace_start;
 3210
 3211      while (sscan < C_scratchspace_top) {
 3212        words = *sscan;
 3213        slot = (C_word *)*(sscan+1);
 3214
 3215        if (*(sscan+2) == ALIGNMENT_HOLE_MARKER) val = (C_word)(sscan+3);
 3216        else val = (C_word)(sscan+2);
 3217
 3218        sscan += words + 2;
 3219
 3220        p = (C_SCHEME_BLOCK *)val;
 3221        h = p->header;
 3222        if (is_fptr(h)) /* TODO: Support scratch->scratch pointers? */
 3223          panic(C_text("Unexpected forwarding pointer in scratch space"));
 3224
 3225        p2 = (C_SCHEME_BLOCK *)(new_scratch_top+2);
 3226
 3227#ifndef C_SIXTY_FOUR
 3228        if ((h & C_8ALIGN_BIT) && C_aligned8(p2) &&
 3229            (C_word *)p2 < new_scratch_limit) {
 3230          *((C_word *)p2) = ALIGNMENT_HOLE_MARKER;
 3231          p2 = (C_SCHEME_BLOCK *)((C_word *)p2 + 1);
 3232        }
 3233#endif
 3234
 3235        /* If orig slot still points here, copy data and update it */
 3236        if (slot != NULL) {
 3237          assert(*slot == val);
 3238          n = C_header_size(p);
 3239          n = (h & C_BYTEBLOCK_BIT) ? C_bytestowords(n) : n;
 3240
 3241          *slot = (C_word)p2;
 3242          /* size = header plus block size plus optional alignment hole */
 3243          *new_scratch_top = ((C_word *)p2-(C_word *)new_scratch_top-2) + n + 1;
 3244          *(new_scratch_top+1) = (C_word)slot;
 3245
 3246          new_scratch_top = (C_word *)p2 + n + 1;
 3247          if(new_scratch_top > new_scratch_limit)
 3248            panic(C_text("out of memory - scratch space full while resizing"));
 3249
 3250          p2->header = h;
 3251          p->header = ptr_to_fptr((C_uword)p2);
 3252          C_memcpy(p2->data, p->data, C_wordstobytes(n));
 3253        }
 3254      }
 3255      free(C_scratchspace_start);
 3256    }
 3257    C_scratchspace_start = new_scratch_start;
 3258    C_scratchspace_top = new_scratch_top;
 3259    C_scratchspace_limit = new_scratch_limit;
 3260    /* Scratch space is now tightly packed */
 3261    C_scratch_usage = (new_scratch_top - new_scratch_start);
 3262    scratchspace_size = new_size;
 3263  }
 3264  assert(C_scratchspace_top + size + 2 <= C_scratchspace_limit);
 3265
 3266  *C_scratchspace_top = size;
 3267  *(C_scratchspace_top+1) = (C_word)NULL; /* Nothing points here 'til mutated */
 3268  result = (C_word)(C_scratchspace_top+2);
 3269  C_scratchspace_top += size + 2;
 3270  /* This will only be marked as "used" when it's claimed by a pointer */
 3271  /* C_scratch_usage += size + 2; */
 3272  return result;
 3273}
 3274
 3275/* Given a root object, scan its slots recursively (the objects
 3276 * themselves should be shallow and non-recursive), and migrate every
 3277 * object stored between the memory boundaries to the supplied
 3278 * pointer.  Scratch data pointed to by objects between the memory
 3279 * boundaries is updated to point to the new memory region.  If the
 3280 * supplied pointer is NULL, the scratch memory is marked reclaimable.
 3281 */
 3282C_regparm C_word
 3283C_migrate_buffer_object(C_word **ptr, C_word *start, C_word *end, C_word obj)
 3284{
 3285  C_word size, header, *data, *p = NULL, obj_in_buffer;
 3286
 3287  if (C_immediatep(obj)) return obj;
 3288
 3289  size = C_header_size(obj);
 3290  header = C_block_header(obj);
 3291  data = C_data_pointer(obj);
 3292  obj_in_buffer = (obj >= (C_word)start && obj < (C_word)end);
 3293
 3294  /* Only copy object if we have a target pointer and it's in the buffer */
 3295  if (ptr != NULL && obj_in_buffer) {
 3296    p = *ptr;
 3297    obj = (C_word)p; /* Return the object's new location at the end */
 3298  }
 3299
 3300  if (p != NULL) *p++ = header;
 3301
 3302  if (header & C_BYTEBLOCK_BIT) {
 3303    if (p != NULL) {
 3304      *ptr = (C_word *)((C_byte *)(*ptr) + sizeof(C_header) + C_align(size));
 3305      C_memcpy(p, data, size);
 3306    }
 3307  } else {
 3308    if (p != NULL) *ptr += size + 1;
 3309
 3310    if(header & C_SPECIALBLOCK_BIT) {
 3311      if (p != NULL) *(p++) = *data;
 3312      size--;
 3313      data++;
 3314    }
 3315
 3316    /* TODO: See if we can somehow make this use Cheney's algorithm */
 3317    while(size--) {
 3318      C_word slot = *data;
 3319
 3320      if(!C_immediatep(slot)) {
 3321        if (C_in_scratchspacep(slot)) {
 3322          if (obj_in_buffer) { /* Otherwise, don't touch scratch backpointer */
 3323            /* TODO: Support recursing into objects in scratch space? */
 3324            C_word *sp = (C_word *)slot;
 3325
 3326            if (*(sp-1) == ALIGNMENT_HOLE_MARKER) --sp;
 3327            if (*(sp-1) != (C_word)NULL && p == NULL)
 3328              C_scratch_usage -= *(sp-2) + 2;
 3329            *(sp-1) = (C_word)p; /* This is why we traverse even if p = NULL */
 3330
 3331            *data = C_SCHEME_UNBOUND; /* Ensure old reference is killed dead */
 3332          }
 3333        } else { /* Slot is not a scratchspace object: check sub-objects */
 3334          slot = C_migrate_buffer_object(ptr, start, end, slot);
 3335        }
 3336      }
 3337      if (p != NULL) *(p++) = slot;
 3338      else *data = slot; /* Sub-object may have moved! */
 3339      data++;
 3340    }
 3341  }
 3342  return obj; /* Should be NULL if ptr was NULL */
 3343}
 3344
 3345/* Register an object's slot as holding data to scratch space.  Only
 3346 * one slot can point to a scratch space object; the object in scratch
 3347 * space is preceded by a pointer that points to this slot (or NULL).
 3348 */
 3349C_regparm C_word C_mutate_scratch_slot(C_word *slot, C_word val)
 3350{
 3351  C_word *ptr = (C_word *)val;
 3352  assert(C_in_scratchspacep(val));
 3353/* XXX  assert(slot == NULL || C_in_stackp((C_word)slot));
 3354*/
 3355  if (*(ptr-1) == ALIGNMENT_HOLE_MARKER) --ptr;
 3356  if (*(ptr-1) == (C_word)NULL && slot != NULL)
 3357    C_scratch_usage += *(ptr-2) + 2;
 3358  if (*(ptr-1) != (C_word)NULL && slot == NULL)
 3359    C_scratch_usage -= *(ptr-2) + 2;
 3360  *(ptr-1) = (C_word)slot; /* Remember the slot pointing here, for realloc */
 3361  if (slot != NULL) *slot = val;
 3362  return val;
 3363}
 3364
 3365/* Initiate garbage collection: */
 3366
 3367
 3368void C_save_and_reclaim(void *trampoline, int n, C_word *av)
 3369{
 3370  C_word new_size = nmax((C_word)1 << C_ilen(n), DEFAULT_TEMPORARY_STACK_SIZE);
 3371
 3372  assert(av > C_temporary_stack_bottom || av < C_temporary_stack_limit);
 3373  assert(C_temporary_stack == C_temporary_stack_bottom);
 3374
 3375  /* Don't *immediately* slam back to default size */
 3376  if (new_size < temporary_stack_size / 4)
 3377    new_size = temporary_stack_size >> 1;
 3378
 3379  if (new_size != temporary_stack_size) {
 3380
 3381    if(fixed_temporary_stack_size)
 3382      panic(C_text("fixed temporary stack overflow (\"apply\" called with too many arguments?)"));
 3383
 3384    if(gc_report_flag) {
 3385      C_dbg(C_text("GC"), C_text("resizing temporary stack dynamically from " UWORD_COUNT_FORMAT_STRING "k to " UWORD_COUNT_FORMAT_STRING "k ...\n"),
 3386            C_wordstobytes(temporary_stack_size) / 1024,
 3387            C_wordstobytes(new_size) / 1024);
 3388    }
 3389
 3390    C_free(C_temporary_stack_limit);
 3391
 3392    if((C_temporary_stack_limit = (C_word *)C_malloc(new_size * sizeof(C_word))) == NULL)
 3393      panic(C_text("out of memory - could not resize temporary stack"));
 3394
 3395    C_temporary_stack_bottom = C_temporary_stack_limit + new_size;
 3396    C_temporary_stack = C_temporary_stack_bottom;
 3397    temporary_stack_size = new_size;
 3398  }
 3399
 3400  C_temporary_stack = C_temporary_stack_bottom - n;
 3401
 3402  assert(C_temporary_stack >= C_temporary_stack_limit);
 3403
 3404  C_memmove(C_temporary_stack, av, n * sizeof(C_word));
 3405  C_reclaim(trampoline, n);
 3406}
 3407
 3408
 3409void C_save_and_reclaim_args(void *trampoline, int n, ...)
 3410{
 3411  va_list v;
 3412  int i;
 3413
 3414  va_start(v, n);
 3415
 3416  for(i = 0; i < n; ++i)
 3417    C_save(va_arg(v, C_word));
 3418
 3419  va_end(v);
 3420  C_reclaim(trampoline, n);
 3421}
 3422
 3423
 3424#ifdef __SUNPRO_C
 3425static void _mark(C_word *x, C_byte *s, C_byte **t, C_byte *l) {   \
 3426  C_word *_x = (x), _val = *_x;                                   \
 3427  if(!C_immediatep(_val)) really_mark(_x,s,t,l);                  \
 3428}
 3429#else
 3430# define _mark(x,s,t,l)                                  \
 3431  C_cblock						\
 3432  C_word *_x = (x), _val = *_x;				\
 3433  if(!C_immediatep(_val)) really_mark(_x,s,t,l);	\
 3434  C_cblockend
 3435#endif
 3436
 3437/* NOTE: This macro is particularly unhygienic! */
 3438#define mark(x) _mark(x, tgt_space_start, tgt_space_top, tgt_space_limit)
 3439
 3440C_regparm void C_reclaim(void *trampoline, C_word c)
 3441{
 3442  int i, j, fcount;
 3443  C_uword count;
 3444  C_word **msp, last;
 3445  C_byte *tmp, *start;
 3446  C_GC_ROOT *gcrp;
 3447  double tgc = 0;
 3448  volatile int finalizers_checked;
 3449  FINALIZER_NODE *flist;
 3450  C_DEBUG_INFO cell;
 3451  C_byte *tgt_space_start, **tgt_space_top, *tgt_space_limit;
 3452
 3453  /* assert(C_timer_interrupt_counter >= 0); */
 3454
 3455  if(pending_interrupts_count > 0 && C_interrupts_enabled) {
 3456    stack_check_demand = 0; /* forget demand: we're not going to gc yet */
 3457    handle_interrupt(trampoline);
 3458  }
 3459
 3460  cell.enabled = 0;
 3461  cell.event = C_DEBUG_GC;
 3462  cell.loc = "<runtime>";
 3463  cell.val = "GC_MINOR";
 3464  C_debugger(&cell, 0, NULL);
 3465
 3466  /* Note: the mode argument will always be GC_MINOR or GC_REALLOC. */
 3467  if(C_pre_gc_hook != NULL) C_pre_gc_hook(GC_MINOR);
 3468
 3469  finalizers_checked = 0;
 3470  C_restart_trampoline = trampoline;
 3471  C_restart_c = c;
 3472  gc_mode = GC_MINOR;
 3473  tgt_space_start = fromspace_start;
 3474  tgt_space_top = &C_fromspace_top;
 3475  tgt_space_limit = C_fromspace_limit;
 3476  weak_pair_chain = (C_word)NULL;
 3477  locative_chain = (C_word)NULL;
 3478
 3479  start = C_fromspace_top;
 3480
 3481  /* Entry point for second-level GC (on explicit request or because of full fromspace): */
 3482#ifdef HAVE_SIGSETJMP
 3483  if(C_sigsetjmp(gc_restart, 0) || start >= C_fromspace_limit) {
 3484#else
 3485  if(C_setjmp(gc_restart) || start >= C_fromspace_limit) {
 3486#endif
 3487    if(gc_bell) {
 3488      C_putchar(7);
 3489      C_fflush(stdout);
 3490    }
 3491
 3492    tgc = C_cpu_milliseconds();
 3493
 3494    if(gc_mode == GC_REALLOC) {
 3495      cell.val = "GC_REALLOC";
 3496      C_debugger(&cell, 0, NULL);
 3497      C_rereclaim2(percentage(heap_size, C_heap_growth), 0);
 3498      gc_mode = GC_MAJOR;
 3499
 3500      tgt_space_start = tospace_start;
 3501      tgt_space_top = &tospace_top;
 3502      tgt_space_limit= tospace_limit;
 3503
 3504      count = (C_uword)tospace_top - (C_uword)tospace_start;
 3505      goto never_mind_edsger;
 3506    }
 3507
 3508    start = (C_byte *)C_align((C_uword)tospace_top);
 3509    gc_mode = GC_MAJOR;
 3510    tgt_space_start = tospace_start;
 3511    tgt_space_top = &tospace_top;
 3512    tgt_space_limit= tospace_limit;
 3513    weak_pair_chain = (C_word)NULL; /* only chain up weak pairs forwarded into tospace */
 3514    locative_chain = (C_word)NULL;  /* same for locatives */
 3515
 3516    cell.val = "GC_MAJOR";
 3517    C_debugger(&cell, 0, NULL);
 3518
 3519    mark_live_heap_only_objects(tgt_space_start, tgt_space_top, tgt_space_limit);
 3520
 3521    /* mark normal GC roots (see below for finalizer handling): */
 3522    for(gcrp = gc_root_list; gcrp != NULL; gcrp = gcrp->next) {
 3523      if(!gcrp->finalizable) mark(&gcrp->value);
 3524    }
 3525  }
 3526  else {
 3527    /* Mark mutated slots: */
 3528    for(msp = mutation_stack_bottom; msp < mutation_stack_top; ++msp)
 3529      mark(*msp);
 3530  }
 3531
 3532  mark_live_objects(tgt_space_start, tgt_space_top, tgt_space_limit);
 3533
 3534  mark_nested_objects(start, tgt_space_start, tgt_space_top, tgt_space_limit);
 3535  start = *tgt_space_top;
 3536
 3537  if(gc_mode == GC_MINOR) {
 3538    count = (C_uword)C_fromspace_top - (C_uword)start;
 3539    ++gc_count_1;
 3540    ++gc_count_1_total;
 3541    update_locatives(GC_MINOR, start, *tgt_space_top);
 3542    update_weak_pairs(GC_MINOR, start, *tgt_space_top);
 3543  }
 3544  else {
 3545    /* Mark finalizer list and remember pointers to non-forwarded items: */
 3546    last = C_block_item(pending_finalizers_symbol, 0);
 3547
 3548    if(!C_immediatep(last) && (j = C_unfix(C_block_item(last, 0))) != 0) {
 3549      /* still finalizers pending: just mark table items... */
 3550      if(gc_report_flag)
 3551        C_dbg(C_text("GC"), C_text("%d finalized item(s) still pending\n"), j);
 3552
 3553      j = fcount = 0;
 3554
 3555      for(flist = finalizer_list; flist != NULL; flist = flist->next) {
 3556        mark(&flist->item);
 3557        mark(&flist->finalizer);
 3558        ++fcount;
 3559      }
 3560
 3561      /* mark finalizable GC roots: */
 3562      for(gcrp = gc_root_list; gcrp != NULL; gcrp = gcrp->next) {
 3563        if(gcrp->finalizable) mark(&gcrp->value);
 3564      }
 3565
 3566      if(gc_report_flag && fcount > 0)
 3567        C_dbg(C_text("GC"), C_text("%d finalizer value(s) marked\n"), fcount);
 3568    }
 3569    else {
 3570      j = fcount = 0;
 3571
 3572      /* move into pending */
 3573      for(flist = finalizer_list; flist != NULL; flist = flist->next) {
 3574        if(j < C_max_pending_finalizers) {
 3575          if(!is_fptr(C_block_header(flist->item)))
 3576            pending_finalizer_indices[ j++ ] = flist;
 3577        }
 3578      }
 3579
 3580      /* mark */
 3581      for(flist = finalizer_list; flist != NULL; flist = flist->next) {
 3582        mark(&flist->item);
 3583        mark(&flist->finalizer);
 3584      }
 3585
 3586      /* mark finalizable GC roots: */
 3587      for(gcrp = gc_root_list; gcrp != NULL; gcrp = gcrp->next) {
 3588        if(gcrp->finalizable) mark(&gcrp->value);
 3589      }
 3590    }
 3591
 3592    pending_finalizer_count = j;
 3593    finalizers_checked = 1;
 3594
 3595    if(pending_finalizer_count > 0 && gc_report_flag)
 3596      C_dbg(C_text("GC"), C_text("%d finalizer(s) pending (%d live)\n"),
 3597            pending_finalizer_count, live_finalizer_count);
 3598
 3599    /* Once more mark nested objects after (maybe) copying finalizer objects: */
 3600    mark_nested_objects(start, tgt_space_start, tgt_space_top, tgt_space_limit);
 3601
 3602    /* Copy finalized items with remembered indices into `##sys#pending-finalizers'
 3603       (and release finalizer node): */
 3604    if(pending_finalizer_count > 0) {
 3605      if(gc_report_flag)
 3606        C_dbg(C_text("GC"), C_text("queueing %d finalizer(s)\n"), pending_finalizer_count);
 3607
 3608      last = C_block_item(pending_finalizers_symbol, 0);
 3609      assert(C_block_item(last, 0) == C_fix(0));
 3610      C_set_block_item(last, 0, C_fix(pending_finalizer_count));
 3611
 3612      for(i = 0; i < pending_finalizer_count; ++i) {
 3613        flist = pending_finalizer_indices[ i ];
 3614        C_set_block_item(last, 1 + i * 2, flist->item);
 3615        C_set_block_item(last, 2 + i * 2, flist->finalizer);
 3616
 3617        if(flist->previous != NULL) flist->previous->next = flist->next;
 3618        else finalizer_list = flist->next;
 3619
 3620        if(flist->next != NULL) flist->next->previous = flist->previous;
 3621
 3622        flist->next = finalizer_free_list;
 3623        flist->previous = NULL;
 3624        finalizer_free_list = flist;
 3625        --live_finalizer_count;
 3626      }
 3627    }
 3628
 3629    update_locatives(gc_mode, start, *tgt_space_top);
 3630    update_weak_pairs(gc_mode, start, *tgt_space_top);
 3631
 3632    count = (C_uword)tospace_top - (C_uword)tospace_start; // Actual used, < heap_size/2
 3633
 3634    {
 3635      C_uword min_half = count + C_heap_half_min_free;
 3636      C_uword low_half = percentage(heap_size/2, C_heap_shrinkage_used);
 3637      C_uword grown    = percentage(heap_size, C_heap_growth);
 3638      C_uword shrunk   = percentage(heap_size, C_heap_shrinkage);
 3639
 3640      if (count < low_half) {
 3641        heap_shrink_counter++;
 3642      } else {
 3643        heap_shrink_counter = 0;
 3644      }
 3645
 3646      /*** isn't gc_mode always GC_MAJOR here? */
 3647      if(gc_mode == GC_MAJOR && !C_heap_size_is_fixed &&
 3648         C_heap_shrinkage > 0 &&
 3649         // This prevents grow, shrink, grow, shrink... spam
 3650         HEAP_SHRINK_COUNTS < heap_shrink_counter &&
 3651         (min_half * 2) <= shrunk && // Min. size trumps shrinkage
 3652         heap_size > MINIMAL_HEAP_SIZE) {
 3653        if(gc_report_flag) {
 3654          C_dbg(C_text("GC"), C_text("Heap low water mark hit (%d%%), shrinking...\n"),
 3655                C_heap_shrinkage_used);
 3656        }
 3657        heap_shrink_counter = 0;
 3658        C_rereclaim2(shrunk, 0);
 3659      } else if (gc_mode == GC_MAJOR && !C_heap_size_is_fixed &&
 3660                 (heap_size / 2) < min_half) {
 3661        if(gc_report_flag) {
 3662          C_dbg(C_text("GC"), C_text("Heap high water mark hit, growing...\n"));
 3663        }
 3664        heap_shrink_counter = 0;
 3665        C_rereclaim2(grown, 0);
 3666      } else {
 3667        C_fromspace_top = tospace_top;
 3668        tmp = fromspace_start;
 3669        fromspace_start = tospace_start;
 3670        tospace_start = tospace_top = tmp;
 3671        tmp = C_fromspace_limit;
 3672        C_fromspace_limit = tospace_limit;
 3673        tospace_limit = tmp;
 3674      }
 3675    }
 3676
 3677  never_mind_edsger:
 3678    ++gc_count_2;
 3679  }
 3680
 3681  if(gc_mode == GC_MAJOR) {
 3682    tgc = C_cpu_milliseconds() - tgc;
 3683    gc_ms += tgc;
 3684    timer_accumulated_gc_ms += tgc;
 3685  }
 3686
 3687  /* Display GC report:
 3688     Note: stubbornly writes to stderr - there is no provision for other output-ports */
 3689  if(gc_report_flag == 1 || (gc_report_flag && gc_mode == GC_MAJOR)) {
 3690    C_dbg(C_text("GC"), C_text("level  %d\tgcs(minor)  %d\tgcs(major)  %d\n"),
 3691	  gc_mode, gc_count_1, gc_count_2);
 3692    i = (C_uword)C_stack_pointer;
 3693
 3694#if C_STACK_GROWS_DOWNWARD
 3695    C_dbg("GC", C_text("stack\t" UWORD_FORMAT_STRING "\t" UWORD_FORMAT_STRING "\t" UWORD_FORMAT_STRING),
 3696	  (C_uword)C_stack_limit, (C_uword)i, (C_uword)C_stack_limit + stack_size);
 3697#else
 3698    C_dbg("GC", C_text("stack\t" UWORD_FORMAT_STRING "\t" UWORD_FORMAT_STRING "\t" UWORD_FORMAT_STRING),
 3699	  (C_uword)C_stack_limit - stack_size, (C_uword)i, (C_uword)C_stack_limit);
 3700#endif
 3701
 3702    if(gc_mode == GC_MINOR)
 3703      C_fprintf(C_stderr, C_text("\t" UWORD_FORMAT_STRING), (C_uword)count);
 3704
 3705    C_fputc('\n', C_stderr);
 3706    C_dbg("GC", C_text(" from\t" UWORD_FORMAT_STRING "\t" UWORD_FORMAT_STRING "\t" UWORD_FORMAT_STRING),
 3707	  (C_uword)fromspace_start, (C_uword)C_fromspace_top, (C_uword)C_fromspace_limit);
 3708
 3709    if(gc_mode == GC_MAJOR)
 3710      C_fprintf(C_stderr, C_text("\t" UWORD_FORMAT_STRING), (C_uword)count);
 3711
 3712    C_fputc('\n', C_stderr);
 3713    C_dbg("GC", C_text("   to\t" UWORD_FORMAT_STRING "\t" UWORD_FORMAT_STRING "\t" UWORD_FORMAT_STRING" \n"),
 3714	  (C_uword)tospace_start, (C_uword)tospace_top,
 3715	  (C_uword)tospace_limit);
 3716  }
 3717
 3718  /* GC will have copied any live objects out of scratch space: clear it */
 3719  if (C_scratchspace_start != C_scratchspace_top) {
 3720    /* And drop the scratchspace in case of a major or reallocating collection */
 3721    if (gc_mode != GC_MINOR) {
 3722      C_free(C_scratchspace_start);
 3723      C_scratchspace_start = NULL;
 3724      C_scratchspace_limit = NULL;
 3725      scratchspace_size = 0;
 3726    }
 3727    C_scratchspace_top = C_scratchspace_start;
 3728    C_scratch_usage = 0;
 3729  }
 3730
 3731  if(gc_mode == GC_MAJOR) {
 3732    gc_count_1 = 0;
 3733    maximum_heap_usage = count > maximum_heap_usage ? count : maximum_heap_usage;
 3734  }
 3735
 3736  if(C_post_gc_hook != NULL) C_post_gc_hook(gc_mode, (C_long)tgc);
 3737
 3738  /* Unwind stack completely */
 3739#ifdef HAVE_SIGSETJMP
 3740  C_siglongjmp(C_restart, 1);
 3741#else
 3742  C_longjmp(C_restart, 1);
 3743#endif
 3744}
 3745
 3746
 3747/* Mark live objects which can exist in the nursery and/or the heap */
 3748static C_regparm void mark_live_objects(C_byte *tgt_space_start, C_byte **tgt_space_top, C_byte *tgt_space_limit)
 3749{
 3750  C_word *p;
 3751  TRACE_INFO *tinfo;
 3752
 3753  assert(C_temporary_stack >= C_temporary_stack_limit);
 3754
 3755  /* Mark live values from the currently running closure: */
 3756  for(p = C_temporary_stack; p < C_temporary_stack_bottom; ++p)
 3757    mark(p);
 3758
 3759  /* Clear the mutated slot stack: */
 3760  mutation_stack_top = mutation_stack_bottom;
 3761
 3762  /* Mark trace-buffer: */
 3763  for(tinfo = trace_buffer; tinfo < trace_buffer_limit; ++tinfo) {
 3764    mark(&tinfo->cooked_location);
 3765    mark(&tinfo->cooked1);
 3766    mark(&tinfo->cooked2);
 3767    mark(&tinfo->thread);
 3768  }
 3769}
 3770
 3771
 3772/*
 3773 * Mark all live *heap* objects that don't need GC mode-specific
 3774 * treatment.  Thus, no finalizers or other GC roots.
 3775 *
 3776 * Finalizers are excluded because these need special handling:
 3777 * finalizers referring to dead objects must be marked and queued.
 3778 * However, *pending* finalizers (for objects previously determined
 3779 * to be collectable) are marked so that these objects stick around
 3780 * until after the finalizer has been run.
 3781 *
 3782 * This function does not need to be called on a minor GC, since these
 3783 * objects won't ever exist in the nursery.
 3784 */
 3785static C_regparm void mark_live_heap_only_objects(C_byte *tgt_space_start, C_byte **tgt_space_top, C_byte *tgt_space_limit)
 3786{
 3787  LF_LIST *lfn;
 3788  C_word *p, **msp, last;
 3789  unsigned int i;
 3790  C_SYMBOL_TABLE *stp;
 3791
 3792  /* Mark items in forwarding table: */
 3793  for(p = forwarding_table; *p != 0; p += 2) {
 3794    last = p[ 1 ];
 3795    mark(&p[ 1 ]);
 3796    C_block_header(p[ 0 ]) = C_block_header(last);
 3797  }
 3798
 3799  /* Mark literal frames: */
 3800  for(lfn = lf_list; lfn != NULL; lfn = lfn->next)
 3801    for(i = 0; i < (unsigned int)lfn->count; ++i)
 3802      mark(&lfn->lf[i]);
 3803
 3804  /* Mark symbol tables: */
 3805  for(stp = symbol_table_list; stp != NULL; stp = stp->next)
 3806    for(i = 0; i < stp->size; ++i)
 3807      mark(&stp->table[i]);
 3808
 3809  /* Mark collectibles: */
 3810  for(msp = collectibles; msp < collectibles_top; ++msp)
 3811    if(*msp != NULL) mark(*msp);
 3812
 3813  /* Mark system globals */
 3814  mark(&core_provided_symbol);
 3815  mark(&interrupt_hook_symbol);
 3816  mark(&error_hook_symbol);
 3817  mark(&callback_continuation_stack_symbol);
 3818  mark(&pending_finalizers_symbol);
 3819  mark(&current_thread_symbol);
 3820
 3821  mark(&s8vector_symbol);
 3822  mark(&u16vector_symbol);
 3823  mark(&s16vector_symbol);
 3824  mark(&u32vector_symbol);
 3825  mark(&s32vector_symbol);
 3826  mark(&u64vector_symbol);
 3827  mark(&s64vector_symbol);
 3828  mark(&f32vector_symbol);
 3829  mark(&f64vector_symbol);
 3830}
 3831
 3832
 3833/*
 3834 * Mark nested values in already moved (i.e., marked) blocks in
 3835 * breadth-first manner (Cheney's algorithm).
 3836 */
 3837static C_regparm void mark_nested_objects(C_byte *heap_scan_top, C_byte *tgt_space_start, C_byte **tgt_space_top, C_byte *tgt_space_limit)
 3838{
 3839  int n;
 3840  C_word bytes;
 3841  C_word *p;
 3842  C_header h;
 3843  C_SCHEME_BLOCK *bp;
 3844
 3845  while(heap_scan_top < *tgt_space_top) {
 3846    bp = (C_SCHEME_BLOCK *)heap_scan_top;
 3847
 3848    if(*((C_word *)bp) == ALIGNMENT_HOLE_MARKER)
 3849      bp = (C_SCHEME_BLOCK *)((C_word *)bp + 1);
 3850
 3851    n = C_header_size(bp);
 3852    h = bp->header;
 3853    bytes = (h & C_BYTEBLOCK_BIT) ? n : n * sizeof(C_word);
 3854    p = bp->data;
 3855
 3856    if(n > 0 && (h & C_BYTEBLOCK_BIT) == 0) {
 3857      if(h & C_SPECIALBLOCK_BIT) {
 3858	--n;
 3859	++p;
 3860      }
 3861
 3862      while(n--) mark(p++);
 3863    }
 3864
 3865    heap_scan_top = (C_byte *)bp + C_align(bytes) + sizeof(C_word);
 3866  }
 3867}
 3868
 3869
 3870static C_regparm void really_mark(C_word *x, C_byte *tgt_space_start, C_byte **tgt_space_top, C_byte *tgt_space_limit)
 3871{
 3872  C_word val;
 3873  C_uword n, bytes;
 3874  C_header h;
 3875  C_SCHEME_BLOCK *p, *p2;
 3876
 3877  val = *x;
 3878
 3879  if (!C_in_stackp(val) && !C_in_heapp(val) && !C_in_scratchspacep(val)) {
 3880#ifdef C_GC_HOOKS
 3881    if(C_gc_trace_hook != NULL)
 3882      C_gc_trace_hook(x, gc_mode);
 3883#endif
 3884    return;
 3885  }
 3886
 3887  p = (C_SCHEME_BLOCK *)val;
 3888  h = p->header;
 3889
 3890  while(is_fptr(h)) { /* TODO: Pass in fptr chain limit? */
 3891    val = fptr_to_ptr(h);
 3892    p = (C_SCHEME_BLOCK *)val;
 3893    h = p->header;
 3894  }
 3895
 3896  /* Already in target space, probably as result of chasing fptrs */
 3897  if ((C_uword)val >= (C_uword)tgt_space_start && (C_uword)val < (C_uword)*tgt_space_top) {
 3898    *x = val;
 3899    return;
 3900  }
 3901
 3902  p2 = (C_SCHEME_BLOCK *)C_align((C_uword)*tgt_space_top);
 3903
 3904#ifndef C_SIXTY_FOUR
 3905  if((h & C_8ALIGN_BIT) && C_aligned8(p2) && (C_byte *)p2 < tgt_space_limit) {
 3906    *((C_word *)p2) = ALIGNMENT_HOLE_MARKER;
 3907    p2 = (C_SCHEME_BLOCK *)((C_word *)p2 + 1);
 3908  }
 3909#endif
 3910
 3911  n = C_header_size(p);
 3912  bytes = (h & C_BYTEBLOCK_BIT) ? n : n * sizeof(C_word);
 3913
 3914  if(C_unlikely(((C_byte *)p2 + bytes + sizeof(C_word)) > tgt_space_limit)) {
 3915    if (gc_mode == GC_MAJOR) {
 3916      /* Detect impossibilities before GC_REALLOC to preserve state: */
 3917      if (C_in_stackp((C_word)p) && bytes > stack_size)
 3918        panic(C_text("Detected corrupted data in stack"));
 3919      if (C_in_heapp((C_word)p) && bytes > (heap_size / 2))
 3920        panic(C_text("Detected corrupted data in heap"));
 3921      if(C_heap_size_is_fixed)
 3922        panic(C_text("out of memory - heap full"));
 3923
 3924      gc_mode = GC_REALLOC;
 3925    } else if (gc_mode == GC_REALLOC) {
 3926      if (new_tospace_top > new_tospace_limit) {
 3927        panic(C_text("out of memory - heap full while resizing"));
 3928      }
 3929    }
 3930#ifdef HAVE_SIGSETJMP
 3931    C_siglongjmp(gc_restart, 1);
 3932#else
 3933    C_longjmp(gc_restart, 1);
 3934#endif
 3935  }
 3936
 3937  *tgt_space_top = (C_byte *)p2 + C_align(bytes) + sizeof(C_word);
 3938
 3939  *x = (C_word)p2;
 3940  p2->header = h;
 3941  p->header = ptr_to_fptr((C_uword)p2);
 3942  C_memcpy(p2->data, p->data, bytes);
 3943  if (h == C_WEAK_PAIR_TAG && !C_immediatep(p2->data[0])) {
 3944    p->data[0] = weak_pair_chain; /* "Recycle" the weak pair's CAR to point to prev head */
 3945    weak_pair_chain = (C_word)p;  /* Make this fwd ptr the new head of the weak pair chain */
 3946  } else if (h == C_LOCATIVE_TAG) {
 3947    p->data[0] = locative_chain; /* "Recycle" the locative pointer field to point to prev head */
 3948    locative_chain = (C_word)p;  /* Make this fwd ptr the new head of the locative chain */
 3949  }
 3950}
 3951
 3952
 3953/* Do a major GC into a freshly allocated heap: */
 3954
 3955#define remark(x)  _mark(x, new_tospace_start, &new_tospace_top, new_tospace_limit)
 3956
 3957C_regparm void C_rereclaim2(C_uword size, int relative_resize)
 3958{
 3959  int i;
 3960  C_GC_ROOT *gcrp;
 3961  FINALIZER_NODE *flist;
 3962  C_byte *new_heapspace, *start;
 3963  size_t  new_heapspace_size;
 3964
 3965  if(C_pre_gc_hook != NULL) C_pre_gc_hook(GC_REALLOC);
 3966
 3967  /*
 3968   * Normally, size is "absolute": it indicates the desired size of
 3969   * the entire new heap.  With relative_resize, size is a demanded
 3970   * increase of the heap, so we'll have to add it.  This calculation
 3971   * doubles the current heap size because heap_size is already both
 3972   * halves.  We add size*2 because we'll eventually divide the size
 3973   * by 2 for both halves.  We also add stack_size*2 because all the
 3974   * nursery data is also copied to the heap on GC, and the requested
 3975   * memory "size" must be available after the GC.
 3976   */
 3977  if(relative_resize) size = (heap_size + size + stack_size) * 2;
 3978
 3979  if(size < MINIMAL_HEAP_SIZE) size = MINIMAL_HEAP_SIZE;
 3980
 3981  /*
 3982   * When heap grows, ensure it's enough to accommodate first
 3983   * generation (nursery).  Because we're calculating the total heap
 3984   * size here (fromspace *AND* tospace), we have to double the stack
 3985   * size, otherwise we'd accommodate only half the stack in the tospace.
 3986   */
 3987  if(size > heap_size && size - heap_size < stack_size * 2)
 3988    size = heap_size + stack_size * 2;
 3989
 3990  /*
 3991   * The heap has grown but we've already hit the maximal size with the current
 3992   * heap, we can't do anything else but panic.
 3993   */
 3994  if(size > heap_size && heap_size >= C_maximal_heap_size)
 3995    panic(C_text("out of memory - heap has reached its maximum size"));
 3996
 3997  if(size > C_maximal_heap_size) size = C_maximal_heap_size;
 3998
 3999  if(debug_mode) {
 4000    C_dbg(C_text("debug"), C_text("resizing heap dynamically from "
 4001                                  UWORD_COUNT_FORMAT_STRING "k to "
 4002                                  UWORD_COUNT_FORMAT_STRING "k ...\n"),
 4003	  heap_size / 1024, size / 1024);
 4004  }
 4005
 4006  if(gc_report_flag) {
 4007    C_dbg(C_text("GC"), C_text("(old) fromspace: \tstart=" UWORD_FORMAT_STRING
 4008			       ", \tlimit=" UWORD_FORMAT_STRING "\n"),
 4009	  (C_word)fromspace_start, (C_word)C_fromspace_limit);
 4010    C_dbg(C_text("GC"), C_text("(old) tospace:   \tstart=" UWORD_FORMAT_STRING
 4011			       ", \tlimit=" UWORD_FORMAT_STRING "\n"),
 4012	  (C_word)tospace_start, (C_word)tospace_limit);
 4013  }
 4014
 4015  heap_size = size;         /* Total heap size of the two halves... */
 4016  size /= 2;                /* ...each half is this big */
 4017
 4018  /*
 4019   * Start by allocating the new heap's fromspace.  After remarking,
 4020   * allocate the other half of the new heap (its tospace).
 4021   *
 4022   * To clarify: what we call "new_space" here is what will eventually
 4023   * be cycled over to "fromspace" when re-reclamation has finished
 4024   * (that is, after the old one has been freed).
 4025   */
 4026  if ((new_heapspace = heap_alloc (size, &new_tospace_start)) == NULL)
 4027    panic(C_text("out of memory - cannot allocate heap segment"));
 4028  new_heapspace_size = size;
 4029
 4030  new_tospace_top = new_tospace_start;
 4031  new_tospace_limit = new_tospace_start + size;
 4032  start = new_tospace_top;
 4033  weak_pair_chain = (C_word)NULL; /* only chain up weak pairs forwarded into new heap */
 4034  locative_chain = (C_word)NULL;  /* same for locatives */
 4035
 4036  /* Mark standard live objects in nursery and heap */
 4037  mark_live_objects(new_tospace_start, &new_tospace_top, new_tospace_limit);
 4038  mark_live_heap_only_objects(new_tospace_start, &new_tospace_top, new_tospace_limit);
 4039
 4040  /* Mark finalizer table: */
 4041  for(flist = finalizer_list; flist != NULL; flist = flist->next) {
 4042    remark(&flist->item);
 4043    remark(&flist->finalizer);
 4044  }
 4045
 4046  /* Mark *all* GC roots */
 4047  for(gcrp = gc_root_list; gcrp != NULL; gcrp = gcrp->next) {
 4048    remark(&gcrp->value);
 4049  }
 4050
 4051  /* Mark nested values in already moved (marked) blocks in breadth-first manner: */
 4052  mark_nested_objects(start, new_tospace_start, &new_tospace_top, new_tospace_limit);
 4053  update_locatives(GC_REALLOC, new_tospace_top, new_tospace_top);
 4054  update_weak_pairs(GC_REALLOC, new_tospace_top, new_tospace_top);
 4055
 4056  heap_free (heapspace1, heapspace1_size);
 4057  heap_free (heapspace2, heapspace2_size);
 4058
 4059  if ((heapspace2 = heap_alloc (size, &tospace_start)) == NULL)
 4060    panic(C_text("out of memory - cannot allocate next heap segment"));
 4061  heapspace2_size = size;
 4062
 4063  heapspace1 = new_heapspace;
 4064  heapspace1_size = new_heapspace_size;
 4065  tospace_limit = tospace_start + size;
 4066  tospace_top = tospace_start;
 4067  fromspace_start = new_tospace_start;
 4068  C_fromspace_top = new_tospace_top;
 4069  C_fromspace_limit = new_tospace_limit;
 4070
 4071  if(gc_report_flag) {
 4072    C_dbg(C_text("GC"), C_text("resized heap to %d bytes\n"), heap_size);
 4073    C_dbg(C_text("GC"), C_text("(new) fromspace: \tstart=" UWORD_FORMAT_STRING
 4074			       ", \tlimit=" UWORD_FORMAT_STRING "\n"),
 4075	  (C_word)fromspace_start, (C_word)C_fromspace_limit);
 4076    C_dbg(C_text("GC"), C_text("(new) tospace:   \tstart=" UWORD_FORMAT_STRING
 4077			       ", \tlimit=" UWORD_FORMAT_STRING "\n"),
 4078	  (C_word)tospace_start, (C_word)tospace_limit);
 4079  }
 4080
 4081  if(C_post_gc_hook != NULL) C_post_gc_hook(GC_REALLOC, 0);
 4082}
 4083
 4084
 4085/* When a weak pair is encountered by GC, it turns it into a
 4086 * forwarding reference as usual, but then it re-uses the now-defunct
 4087 * pair's CAR field.  It clobbers that field with a plain C pointer to
 4088 * the current "weak pair chain".  Then, the weak pair chain is
 4089 * updated to point to this new forwarding pointer, creating a crude
 4090 * linked list of sorts.
 4091 *
 4092 * We can get away with this because the slots of an object are
 4093 * unused/dead when it is turned into a forwarding pointer - the
 4094 * forwarding pointer itself is just a header, but those data fields
 4095 * remain allocated.  Since the weak pair chain is a linked list that
 4096 * can *only* contain weak-pairs-turned-forwarding-pointer, we may
 4097 * freely access the first slot of such forwarding pointers.
 4098 */
 4099static C_regparm void update_weak_pairs(int mode, C_byte *undead_start, C_byte *undead_end)
 4100{
 4101  int weakn = 0;
 4102  C_word p, pair, car, h;
 4103  C_byte *car_ptr;
 4104
 4105  /* NOTE: Don't use C_block_item() because it asserts the block is
 4106   * big enough in DEBUGBUILD, but forwarding pointers have size 0.
 4107   */
 4108  for (p = weak_pair_chain; p != (C_word)NULL; p = *((C_word *)C_data_pointer(p))) {
 4109    /* NOTE: We only chain up the weak pairs' forwarding pointers into
 4110     * the new space.  This is safe because already forwarded weak
 4111     * pairs in nursery/fromspace will be forwarded *again* into
 4112     * tospace/new heap.  That forwarding pointer is chained up.
 4113     * Still-unforwarded weak pairs will be forwarded straight to the
 4114     * new space, and also chained up.
 4115     */
 4116    h = C_block_header(p);
 4117    assert(is_fptr(h));
 4118    pair = fptr_to_ptr(h);
 4119    assert(!is_fptr(C_block_header(pair)));
 4120
 4121    /* The pair itself should be live */
 4122    assert((mode == GC_MINOR && !C_in_stackp(pair)) ||
 4123           (mode == GC_MAJOR && !C_in_stackp(pair) && !C_in_fromspacep(pair)) ||
 4124           (mode == GC_REALLOC && !C_in_stackp(pair) && !C_in_heapp(pair))); /* NB: *old* heap! */
 4125
 4126    car = C_block_item(pair, 0);
 4127    assert(!C_immediatep(car)); /* should be ensured when adding it to the chain */
 4128    h = C_block_header(car);
 4129    while (is_fptr(h)) {
 4130      car = fptr_to_ptr(h);
 4131      h = C_block_header(car);
 4132    }
 4133
 4134    car_ptr = (C_byte *)(C_uword)car;
 4135    /* If the car is unreferenced by anyone else, it wasn't moved by GC.  Or, if it's in the "undead" portion of
 4136       the new heap, it was moved because it was only referenced by a revived finalizable object.  In either case, drop it: */
 4137    if((mode == GC_MINOR && C_in_stackp(car)) ||
 4138       (mode == GC_MAJOR && (C_in_stackp(car) || C_in_fromspacep(car) || (car_ptr >= undead_start && car_ptr < undead_end))) ||
 4139       (mode == GC_REALLOC && (C_in_stackp(car) || C_in_heapp(car) || (car_ptr >= undead_start && car_ptr < undead_end)))) { /* NB: *old* heap! */
 4140
 4141      C_set_block_item(pair, 0, C_SCHEME_BROKEN_WEAK_PTR);
 4142      ++weakn;
 4143    } else {
 4144      /* Might have moved, re-set the car to the target value */
 4145      C_set_block_item(pair, 0, car);
 4146    }
 4147  }
 4148  weak_pair_chain = (C_word)NULL;
 4149  if(gc_report_flag && weakn)
 4150    C_dbg("GC", C_text("%d recoverable weak pairs found\n"), weakn);
 4151}
 4152
 4153/* Same as weak pairs (see above), but for locatives.  Note that this
 4154 * also includes non-weak locatives, as these point *into* an object,
 4155 * so the updating of that pointer is not handled by the GC proper
 4156 * (which only deals with full objects).
 4157 */
 4158static C_regparm void update_locatives(int mode, C_byte *undead_start, C_byte *undead_end)
 4159{
 4160  int weakn = 0;
 4161  C_word p, loc, ptr, obj, h, offset;
 4162  C_byte *obj_ptr;
 4163
 4164  for (p = locative_chain; p != (C_word)NULL; p = *((C_word *)C_data_pointer(p))) {
 4165    h = C_block_header(p);
 4166    assert(is_fptr(h));
 4167    loc = fptr_to_ptr(h);
 4168    assert(!is_fptr(C_block_header(loc)));
 4169
 4170    /* The locative object itself should be live */
 4171    assert((mode == GC_MINOR && !C_in_stackp(loc)) ||
 4172           (mode == GC_MAJOR && !C_in_stackp(loc) && !C_in_fromspacep(loc)) ||
 4173           (mode == GC_REALLOC && !C_in_stackp(loc) && !C_in_heapp(loc))); /* NB: *old* heap! */
 4174
 4175    ptr = C_block_item(loc, 0); /* fix up ptr */
 4176    if (ptr == 0) continue; /* Skip already dropped weak locatives */
 4177    offset = C_unfix(C_block_item(loc, 1));
 4178    obj = ptr - offset;
 4179
 4180    h = C_block_header(obj);
 4181    while (is_fptr(h)) {
 4182      obj = fptr_to_ptr(h);
 4183      h = C_block_header(obj);
 4184    }
 4185
 4186    obj_ptr = (C_byte *)(C_uword)obj;
 4187    /* If the object is unreferenced by anyone else, it wasn't moved by GC.  Or, if it's in the "undead" portion of
 4188       the new heap, it was moved because it was only referenced by a revived finalizable object.  In either case, drop it: */
 4189    if((mode == GC_MINOR && C_in_stackp(obj)) ||
 4190       (mode == GC_MAJOR && (C_in_stackp(obj) || C_in_fromspacep(obj) || (obj_ptr >= undead_start && obj_ptr < undead_end))) ||
 4191       (mode == GC_REALLOC && (C_in_stackp(obj) || C_in_heapp(obj) || (obj_ptr >= undead_start && obj_ptr < undead_end)))) { /* NB: *old* heap! */
 4192
 4193      /* NOTE: This does *not* use BROKEN_WEAK_POINTER.  This slot
 4194       * holds an unaligned raw C pointer, not a Scheme object */
 4195      C_set_block_item(loc, 0, 0);
 4196      ++weakn;
 4197    } else {
 4198      /* Might have moved, re-set the object to the target value */
 4199      C_set_block_item(loc, 0, obj + offset);
 4200    }
 4201  }
 4202  locative_chain = (C_word)NULL;
 4203  if(gc_report_flag && weakn)
 4204    C_dbg("GC", C_text("%d recoverable weak locatives found\n"), weakn);
 4205}
 4206
 4207
 4208void handle_interrupt(void *trampoline)
 4209{
 4210  C_word *p, h, reason, state, proc, n;
 4211  double c;
 4212  C_word av[ 4 ];
 4213
 4214  /* Build vector with context information: */
 4215  n = C_temporary_stack_bottom - C_temporary_stack;
 4216  p = C_alloc(C_SIZEOF_VECTOR(2) + C_SIZEOF_VECTOR(n));
 4217  proc = (C_word)p;
 4218  *(p++) = C_VECTOR_TYPE | C_BYTEBLOCK_BIT | sizeof(C_word);
 4219  *(p++) = (C_word)trampoline;
 4220  state = (C_word)p;
 4221  *(p++) = C_VECTOR_TYPE | (n + 1);
 4222  *(p++) = proc;
 4223  C_memcpy(p, C_temporary_stack, n * sizeof(C_word));
 4224
 4225  /* Restore state to the one at the time of the interrupt: */
 4226  C_temporary_stack = C_temporary_stack_bottom;
 4227  C_stack_limit = C_stack_hard_limit;
 4228
 4229  /* Invoke high-level interrupt handler: */
 4230  reason = C_fix(pending_interrupts[ --pending_interrupts_count ]);
 4231  proc = C_block_item(interrupt_hook_symbol, 0);
 4232
 4233  if(C_immediatep(proc))
 4234    panic(C_text("`##sys#interrupt-hook' is not defined"));
 4235
 4236  c = C_cpu_milliseconds() - interrupt_time;
 4237  last_interrupt_latency = c;
 4238  C_timer_interrupt_counter = C_initial_timer_interrupt_period;
 4239  /* <- no continuation is passed: "##sys#interrupt-hook" may not return! */
 4240  av[ 0 ] = proc;
 4241  av[ 1 ] = C_SCHEME_UNDEFINED;
 4242  av[ 2 ] = reason;
 4243  av[ 3 ] = state;
 4244  C_do_apply(4, av);
 4245}
 4246
 4247
 4248void
 4249C_unbound_variable(C_word sym)
 4250{
 4251  barf(C_UNBOUND_VARIABLE_ERROR, NULL, sym);
 4252}
 4253
 4254
 4255void
 4256C_decoding_error(C_word str, C_word index)
 4257{
 4258  barf(C_DECODING_ERROR, NULL, str, index);
 4259}
 4260
 4261
 4262/* XXX: This needs to be given a better name.
 4263   C_retrieve used to exist but it just called C_fast_retrieve */
 4264C_regparm C_word C_retrieve2(C_word val, char *name)
 4265{
 4266  C_word *p;
 4267  int len;
 4268
 4269  if(val == C_SCHEME_UNBOUND) {
 4270    len = C_strlen(name);
 4271    /* this is ok: we won't return from `C_retrieve2'
 4272     * (or the value isn't needed). */
 4273    p = C_alloc(C_SIZEOF_STRING(len));
 4274    C_unbound_variable(C_string2(&p, name));
 4275  }
 4276
 4277  return val;
 4278}
 4279
 4280
 4281void C_ccall C_invalid_procedure(C_word c, C_word *av)
 4282{
 4283  C_word self = av[0];
 4284  barf(C_NOT_A_CLOSURE_ERROR, NULL, self);
 4285}
 4286
 4287
 4288C_regparm void *C_retrieve2_symbol_proc(C_word val, char *name)
 4289{
 4290  C_word *p;
 4291  int len;
 4292
 4293  if(val == C_SCHEME_UNBOUND) {
 4294    len = C_strlen(name);
 4295    /* this is ok: we won't return from `C_retrieve2' (or the value isn't needed). */
 4296    p = C_alloc(C_SIZEOF_STRING(len));
 4297    barf(C_UNBOUND_VARIABLE_ERROR, NULL, C_string2(&p, name));
 4298  }
 4299
 4300  return C_fast_retrieve_proc(val);
 4301}
 4302
 4303#ifdef C_NONUNIX
 4304VOID CALLBACK win_timer(PVOID data_ignored, BOOLEAN wait_or_fired)
 4305{
 4306  if (profiling) take_profile_sample();
 4307}
 4308#endif
 4309
 4310static void set_profile_timer(C_uword freq)
 4311{
 4312#ifdef C_NONUNIX
 4313  static HANDLE timer = NULL;
 4314
 4315  if (freq == 0) {
 4316    assert(timer != NULL);
 4317    if (!DeleteTimerQueueTimer(NULL, timer, NULL)) goto error;
 4318    timer = NULL;
 4319  } else if (freq < 1000) {
 4320    panic(C_text("On Windows, sampling can only be done in milliseconds"));
 4321  } else {
 4322    if (!CreateTimerQueueTimer(&timer, NULL, win_timer, NULL, 0, freq/1000, 0))
 4323      goto error;
 4324  }
 4325#else
 4326  struct itimerval itv;
 4327
 4328  itv.it_value.tv_sec = freq / 1000000;
 4329  itv.it_value.tv_usec = freq % 1000000;
 4330  itv.it_interval.tv_sec = itv.it_value.tv_sec;
 4331  itv.it_interval.tv_usec = itv.it_value.tv_usec;
 4332
 4333  if (setitimer(C_PROFILE_TIMER, &itv, NULL) == -1) goto error;
 4334#endif
 4335
 4336  return;
 4337
 4338error:
 4339  if (freq == 0) panic(C_text("error clearing timer for profiling"));
 4340  else panic(C_text("error setting timer for profiling"));
 4341}
 4342
 4343/* Bump profile count for current top of trace buffer */
 4344static void take_profile_sample()
 4345{
 4346  PROFILE_BUCKET **bp, *b;
 4347  C_char *key;
 4348  TRACE_INFO *tb;
 4349  /* To count distinct calls of a procedure, remember last call */
 4350  static C_char *prev_key = NULL;
 4351  static TRACE_INFO *prev_tb = NULL;
 4352
 4353  /* trace_buffer_top points *beyond* the topmost entry: Go back one */
 4354  if (trace_buffer_top == trace_buffer) {
 4355    if (!trace_buffer_full) return; /* No data yet */
 4356    tb = trace_buffer_limit - 1;
 4357  } else {
 4358    tb = trace_buffer_top - 1;
 4359  }
 4360
 4361  if (tb->raw_location != NULL) {
 4362    key = tb->raw_location;
 4363  } else {
 4364    key = "<eval>"; /* Location string is GCable, can't use it */
 4365  }
 4366
 4367  /* We could also just hash the pointer but that's a bit trickier */
 4368  bp = profile_table + hash_string(C_strlen(key), key, PROFILE_TABLE_SIZE, 0);
 4369  b = *bp;
 4370
 4371  /* First try to find pre-existing item in hash table */
 4372  while(b != NULL) {
 4373    if(b->key == key) {
 4374      b->sample_count++;
 4375      if (prev_key != key && prev_tb != tb)
 4376        b->call_count++;
 4377      goto done;
 4378    }
 4379    else b = b->next;
 4380  }
 4381
 4382  /* Not found, allocate a new item and use it as bucket's new head */
 4383  b = next_profile_bucket;
 4384  next_profile_bucket = NULL;
 4385
 4386  assert(b != NULL);
 4387
 4388  b->next = *bp;
 4389  b->key = key;
 4390  *bp = b;
 4391  b->sample_count = 1;
 4392  b->call_count = 1;
 4393
 4394done:
 4395  prev_tb = tb;
 4396  prev_key = key;
 4397}
 4398
 4399
 4400C_regparm void C_trace(C_char *name)
 4401{
 4402  C_word thread;
 4403
 4404  if(show_trace) {
 4405    C_fputs(name, C_stderr);
 4406    C_fputc('\n', C_stderr);
 4407  }
 4408
 4409  /*
 4410   * When profiling, pre-allocate profile bucket if necessary.  This
 4411   * is used in the signal handler, because it may not malloc.
 4412   */
 4413  if(profiling && next_profile_bucket == NULL) {
 4414    next_profile_bucket = (PROFILE_BUCKET *)C_malloc(sizeof(PROFILE_BUCKET));
 4415    if (next_profile_bucket == NULL) {
 4416      panic(C_text("out of memory - cannot allocate profile table-bucket"));
 4417    }
 4418  }
 4419
 4420  if(trace_buffer_top >= trace_buffer_limit) {
 4421    trace_buffer_top = trace_buffer;
 4422    trace_buffer_full = 1;
 4423  }
 4424
 4425  trace_buffer_top->raw_location = name;
 4426  trace_buffer_top->cooked_location = C_SCHEME_FALSE;
 4427  trace_buffer_top->cooked1 = C_SCHEME_FALSE;
 4428  trace_buffer_top->cooked2 = C_SCHEME_FALSE;
 4429  thread = C_block_item(current_thread_symbol, 0);
 4430  trace_buffer_top->thread = C_and(C_blockp(thread), C_thread_id(thread));
 4431  ++trace_buffer_top;
 4432}
 4433
 4434
 4435C_regparm C_word C_emit_trace_info2(char *raw, C_word l, C_word x, C_word y, C_word t)
 4436{
 4437  /* See above */
 4438  if(profiling && next_profile_bucket == NULL) {
 4439    next_profile_bucket = (PROFILE_BUCKET *)C_malloc(sizeof(PROFILE_BUCKET));
 4440    if (next_profile_bucket == NULL) {
 4441      panic(C_text("out of memory - cannot allocate profile table-bucket"));
 4442    }
 4443  }
 4444
 4445  if(trace_buffer_top >= trace_buffer_limit) {
 4446    trace_buffer_top = trace_buffer;
 4447    trace_buffer_full = 1;
 4448  }
 4449
 4450  trace_buffer_top->raw_location = raw;
 4451  trace_buffer_top->cooked_location = l;
 4452  trace_buffer_top->cooked1 = x;
 4453  trace_buffer_top->cooked2 = y;
 4454  trace_buffer_top->thread = t;
 4455  ++trace_buffer_top;
 4456  return x;
 4457}
 4458
 4459
 4460C_char *C_dump_trace(int start)
 4461{
 4462  TRACE_INFO *ptr;
 4463  C_char *result;
 4464  int i, result_len;
 4465
 4466  result_len = STRING_BUFFER_SIZE;
 4467  if((result = (char *)C_malloc(result_len)) == NULL)
 4468    horror(C_text("out of memory - cannot allocate trace-dump buffer"));
 4469
 4470  *result = '\0';
 4471
 4472  if(trace_buffer_top > trace_buffer || trace_buffer_full) {
 4473    if(trace_buffer_full) {
 4474      i = C_trace_buffer_size;
 4475      C_strlcat(result, C_text("...more...\n"), result_len);
 4476    }
 4477    else i = trace_buffer_top - trace_buffer;
 4478
 4479    ptr = trace_buffer_full ? trace_buffer_top : trace_buffer;
 4480    ptr += start;
 4481    i -= start;
 4482
 4483    for(;i--; ++ptr) {
 4484      if(ptr >= trace_buffer_limit) ptr = trace_buffer;
 4485
 4486      if(C_strlen(result) > STRING_BUFFER_SIZE - 32) {
 4487        result_len = C_strlen(result) * 2;
 4488        result = C_realloc(result, result_len);
 4489	if(result == NULL)
 4490	  horror(C_text("out of memory - cannot reallocate trace-dump buffer"));
 4491      }
 4492
 4493      if (ptr->raw_location != NULL) {
 4494        C_strlcat(result, ptr->raw_location, result_len);
 4495      } else if (ptr->cooked_location != C_SCHEME_FALSE) {
 4496        C_word bv = C_block_item(ptr->cooked_location, 0);
 4497        C_strlcat(result, C_c_string(bv), nmin(C_header_size(bv) - 1, result_len));
 4498      } else {
 4499        C_strlcat(result, "<unknown>", result_len);
 4500      }
 4501
 4502      if(i > 0) C_strlcat(result, "\n", result_len);
 4503      else C_strlcat(result, " \t<--\n", result_len);
 4504    }
 4505  }
 4506
 4507  return result;
 4508}
 4509
 4510
 4511C_regparm void C_clear_trace_buffer(void)
 4512{
 4513  int i, old_profiling = profiling;
 4514
 4515  profiling = 0;
 4516
 4517  if(trace_buffer == NULL) {
 4518    if(C_trace_buffer_size < MIN_TRACE_BUFFER_SIZE)
 4519      C_trace_buffer_size = MIN_TRACE_BUFFER_SIZE;
 4520
 4521    trace_buffer = (TRACE_INFO *)C_malloc(sizeof(TRACE_INFO) * C_trace_buffer_size);
 4522
 4523    if(trace_buffer == NULL)
 4524      panic(C_text("out of memory - cannot allocate trace-buffer"));
 4525  }
 4526
 4527  trace_buffer_top = trace_buffer;
 4528  trace_buffer_limit = trace_buffer + C_trace_buffer_size;
 4529  trace_buffer_full = 0;
 4530
 4531  for(i = 0; i < C_trace_buffer_size; ++i) {
 4532    trace_buffer[ i ].raw_location = NULL;
 4533    trace_buffer[ i ].cooked_location = C_SCHEME_FALSE;
 4534    trace_buffer[ i ].cooked1 = C_SCHEME_FALSE;
 4535    trace_buffer[ i ].cooked2 = C_SCHEME_FALSE;
 4536    trace_buffer[ i ].thread = C_SCHEME_FALSE;
 4537  }
 4538
 4539  profiling = old_profiling;
 4540}
 4541
 4542C_word C_resize_trace_buffer(C_word size) {
 4543  int old_size = C_trace_buffer_size, old_profiling = profiling;
 4544  assert(trace_buffer);
 4545  profiling = 0;
 4546  free(trace_buffer);
 4547  trace_buffer = NULL;
 4548  C_trace_buffer_size = C_unfix(size);
 4549  C_clear_trace_buffer();
 4550  profiling = old_profiling;
 4551  return(C_fix(old_size));
 4552}
 4553
 4554C_word C_fetch_trace(C_word starti, C_word buffer)
 4555{
 4556  TRACE_INFO *ptr;
 4557  int i, p = 0, start = C_unfix(starti);
 4558
 4559  if(trace_buffer_top > trace_buffer || trace_buffer_full) {
 4560    if(trace_buffer_full) i = C_trace_buffer_size;
 4561    else i = trace_buffer_top - trace_buffer;
 4562
 4563    ptr = trace_buffer_full ? trace_buffer_top : trace_buffer;
 4564    ptr += start;
 4565    i -= start;
 4566
 4567    if(C_header_size(buffer) < i * 5)
 4568      panic(C_text("destination buffer too small for call-chain"));
 4569
 4570    for(;i--; ++ptr) {
 4571      if(ptr >= trace_buffer_limit) ptr = trace_buffer;
 4572
 4573      /* outside-pointer, will be ignored by GC */
 4574      C_mutate(&C_block_item(buffer, p++), (C_word)ptr->raw_location);
 4575
 4576      /* subject to GC */
 4577      C_mutate(&C_block_item(buffer, p++), ptr->cooked_location);
 4578      C_mutate(&C_block_item(buffer, p++), ptr->cooked1);
 4579      C_mutate(&C_block_item(buffer, p++), ptr->cooked2);
 4580      C_mutate(&C_block_item(buffer, p++), ptr->thread);
 4581    }
 4582  }
 4583
 4584  return C_fix(p);
 4585}
 4586
 4587C_regparm C_word C_u_i_bytevector_hash(C_word str, C_word start, C_word end, C_word rnd)
 4588{
 4589  int len = C_header_size(str);
 4590  C_char *ptr = C_c_string(str);
 4591  return C_fix(hash_string(C_unfix(end) - C_unfix(start), ptr + C_unfix(start), C_MOST_POSITIVE_FIXNUM, C_unfix(rnd)));
 4592}
 4593
 4594C_regparm void C_toplevel_entry(C_char *name)
 4595{
 4596  if(debug_mode)
 4597    C_dbg(C_text("debug"), C_text("entering %s...\n"), name);
 4598}
 4599
 4600C_regparm C_word C_a_i_provide(C_word **a, int c, C_word id)
 4601{
 4602  if (debug_mode == 2) {
 4603    C_word str = C_block_item(id, 1);
 4604    C_dbg(C_text("debug"), C_text("providing %s...\n"), C_c_string(str));
 4605  }
 4606  return C_a_i_putprop(a, 3, core_provided_symbol, id, C_SCHEME_TRUE);
 4607}
 4608
 4609C_regparm C_word C_i_providedp(C_word id)
 4610{
 4611  return C_i_getprop(core_provided_symbol, id, C_SCHEME_FALSE);
 4612}
 4613
 4614C_word C_halt(C_word msg)
 4615{
 4616  C_char *dmp = msg != C_SCHEME_FALSE ? C_dump_trace(0) : NULL;
 4617
 4618  if(C_gui_mode) {
 4619    if(msg != C_SCHEME_FALSE) {
 4620      int n = C_header_size(msg);
 4621
 4622      if (n >= sizeof(buffer))
 4623	n = sizeof(buffer) - 1;
 4624      C_strlcpy(buffer, (C_char *)C_data_pointer(msg), n);
 4625      /* XXX msg isn't checked for NUL bytes, but we can't barf here either! */
 4626    }
 4627    else C_strlcpy(buffer, C_text("(aborted)"), sizeof(buffer));
 4628
 4629    C_strlcat(buffer, C_text("\n\n"), sizeof(buffer));
 4630
 4631    if(dmp != NULL) C_strlcat(buffer, dmp, sizeof(buffer));
 4632
 4633#if defined(_WIN32) && !defined(__CYGWIN__)
 4634    MessageBox(NULL, buffer, C_text("CHICKEN runtime"), MB_OK | MB_ICONERROR);
 4635    ExitProcess(1);
 4636#endif
 4637  } /* otherwise fall through */
 4638
 4639  if(msg != C_SCHEME_FALSE) {
 4640    C_fwrite(C_data_pointer(msg), C_header_size(msg), sizeof(C_char), C_stderr);
 4641    C_fputc('\n', C_stderr);
 4642  }
 4643
 4644  if(dmp != NULL)
 4645    C_dbg("", C_text("\n%s"), dmp);
 4646
 4647  C_exit_runtime(C_fix(EX_SOFTWARE));
 4648  return 0;
 4649}
 4650
 4651
 4652C_word C_message(C_word msg)
 4653{
 4654  C_word m = C_block_item(msg, 0);
 4655  unsigned int n = C_header_size(m);
 4656  /*
 4657   * Strictly speaking this isn't necessary for the non-gui-mode,
 4658   * but let's try and keep this consistent across modes.
 4659   */
 4660  if (C_memchr(C_c_string(m), '\0', n - 1) != NULL)
 4661    barf(C_ASCIIZ_REPRESENTATION_ERROR, "##sys#message", msg);
 4662
 4663  if(C_gui_mode) {
 4664    if (n >= sizeof(buffer))
 4665      n = sizeof(buffer) - 1;
 4666    C_strncpy(buffer, C_c_string(m), n);
 4667    buffer[ n ] = '\0';
 4668#if defined(_WIN32) && !defined(__CYGWIN__)
 4669    MessageBox(NULL, buffer, C_text("CHICKEN runtime"), MB_OK | MB_ICONEXCLAMATION);
 4670    return C_SCHEME_UNDEFINED;
 4671#endif
 4672  } /* fall through */
 4673
 4674  C_fwrite(C_c_string(m), n, sizeof(C_char), stdout);
 4675  C_putchar('\n');
 4676  return C_SCHEME_UNDEFINED;
 4677}
 4678
 4679
 4680C_regparm C_word C_equalp(C_word x, C_word y)
 4681{
 4682  C_header header;
 4683  C_word bits, n, i;
 4684
 4685  C_stack_check1(barf(C_CIRCULAR_DATA_ERROR, "equal?"));
 4686
 4687 loop:
 4688  if(x == y) return 1;
 4689
 4690  if(C_immediatep(x) || C_immediatep(y)) return 0;
 4691
 4692  /* NOTE: Extra check at the end is special consideration for pairs being equal to weak pairs */
 4693  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;
 4694  else if((bits = header & C_HEADER_BITS_MASK) & C_BYTEBLOCK_BIT) {
 4695    if(header == C_FLONUM_TAG && C_block_header(y) == C_FLONUM_TAG)
 4696      return C_ub_i_flonum_eqvp(C_flonum_magnitude(x),
 4697                                C_flonum_magnitude(y));
 4698    else return !C_memcmp(C_data_pointer(x), C_data_pointer(y), header & C_HEADER_SIZE_MASK);
 4699  }
 4700  else if(C_header_bits(x) == C_STRING_TYPE)
 4701    return C_equalp(C_block_item(x, 0), C_block_item(y, 0));
 4702  else if(header == C_SYMBOL_TAG) return 0;
 4703  else {
 4704    i = 0;
 4705    n = header & C_HEADER_SIZE_MASK;
 4706
 4707    if(bits & C_SPECIALBLOCK_BIT) {
 4708      /* do not recurse into closures */
 4709      if(C_header_bits(x) == C_CLOSURE_TYPE)
 4710	return !C_memcmp(C_data_pointer(x), C_data_pointer(y), n * sizeof(C_word));
 4711      else if(C_block_item(x, 0) != C_block_item(y, 0)) return 0;
 4712      else ++i;
 4713
 4714      if(n == 1) return 1;
 4715    }
 4716
 4717    if(--n < 0) return 1;
 4718
 4719    while(i < n)
 4720      if(!C_equalp(C_block_item(x, i), C_block_item(y, i))) return 0;
 4721      else ++i;
 4722
 4723    x = C_block_item(x, i);
 4724    y = C_block_item(y, i);
 4725    goto loop;
 4726  }
 4727}
 4728
 4729
 4730C_regparm C_word C_set_gc_report(C_word flag)
 4731{
 4732  if(flag == C_SCHEME_FALSE) gc_report_flag = 0;
 4733  else if(flag == C_SCHEME_TRUE) gc_report_flag = 2;
 4734  else gc_report_flag = 1;
 4735
 4736  return C_SCHEME_UNDEFINED;
 4737}
 4738
 4739C_regparm C_word C_i_accumulated_gc_time(void)
 4740{
 4741  double tgc;
 4742
 4743  tgc = timer_accumulated_gc_ms;
 4744  timer_accumulated_gc_ms = 0;
 4745  return C_fix(tgc);
 4746}
 4747
 4748C_regparm C_word C_start_timer(void)
 4749{
 4750  tracked_mutation_count = 0;
 4751  mutation_count = 0;
 4752  gc_count_1_total = 0;
 4753  gc_count_2 = 0;
 4754  timer_start_ms = C_cpu_milliseconds();
 4755  gc_ms = 0;
 4756  maximum_heap_usage = 0;
 4757  return C_SCHEME_UNDEFINED;
 4758}
 4759
 4760
 4761void C_ccall C_stop_timer(C_word c, C_word *av)
 4762{
 4763  C_word
 4764    closure = av[ 0 ],
 4765    k = av[ 1 ];
 4766  double t0 = C_cpu_milliseconds() - timer_start_ms;
 4767  C_word
 4768    ab[ WORDS_PER_FLONUM * 2 + C_SIZEOF_BIGNUM(1) + C_SIZEOF_VECTOR(7) ],
 4769    *a = ab,
 4770    elapsed = C_flonum(&a, t0 / 1000.0),
 4771    gc_time = C_flonum(&a, gc_ms / 1000.0),
 4772    heap_usage = C_unsigned_int_to_num(&a, maximum_heap_usage),
 4773    info;
 4774
 4775  info = C_vector(&a, 7, elapsed, gc_time, C_fix(mutation_count),
 4776                  C_fix(tracked_mutation_count), C_fix(gc_count_1_total),
 4777		  C_fix(gc_count_2), heap_usage);
 4778  C_kontinue(k, info);
 4779}
 4780
 4781
 4782C_word C_exit_runtime(C_word code)
 4783{
 4784  C_fflush(NULL);
 4785  C__exit(C_unfix(code));
 4786}
 4787
 4788
 4789C_regparm C_word C_set_print_precision(C_word n)
 4790{
 4791  flonum_print_precision = C_unfix(n);
 4792  return C_SCHEME_UNDEFINED;
 4793}
 4794
 4795
 4796C_regparm C_word C_get_print_precision(void)
 4797{
 4798  return C_fix(flonum_print_precision);
 4799}
 4800
 4801
 4802C_regparm C_word C_read_char(C_word port)
 4803{
 4804  C_FILEPTR fp = C_port_file(port);
 4805  C_char buf[ 5 ];
 4806  int n = 0, r, c;
 4807
 4808  do {
 4809    c = C_getc(fp);
 4810
 4811    if(c == EOF) {
 4812        if(ferror(fp)) {
 4813            clearerr(fp);
 4814            if(n == 0) return C_fix(-1);
 4815        }
 4816    /* Found here:
 4817       http://mail.python.org/pipermail/python-bugs-list/2002-July/012579.html */
 4818#if defined(_WIN32) && !defined(__CYGWIN__)
 4819        else if(GetLastError() == ERROR_OPERATION_ABORTED) {
 4820            if(n == 0) return C_fix(-1);
 4821        }
 4822#endif
 4823        else if(n == 0) return C_SCHEME_END_OF_FILE;
 4824    }
 4825
 4826    if(n == 0) r = C_utf_expect(c);
 4827    buf[ n++ ] = c;
 4828  } while(n < r);
 4829
 4830  return C_utf_decode_ptr(buf);
 4831}
 4832
 4833
 4834C_regparm C_word C_execute_shell_command(C_word string)
 4835{
 4836  C_word bv = C_block_item(string, 0);
 4837  int n = C_header_size(bv);
 4838  char *buf = buffer;
 4839
 4840  /* Windows doc says to flush all output streams before calling system.
 4841     Probably a good idea for all platforms. */
 4842  (void)fflush(NULL);
 4843
 4844  if(n >= STRING_BUFFER_SIZE) {
 4845    if((buf = (char *)C_malloc(n + 1)) == NULL)
 4846      barf(C_OUT_OF_MEMORY_ERROR, "system");
 4847  }
 4848
 4849  C_memcpy(buf, C_data_pointer(bv), n); /* includes 0 */
 4850  if (n - 1 != strlen(buf))
 4851    barf(C_ASCIIZ_REPRESENTATION_ERROR, "system", string);
 4852
 4853  n = C_system(C_OS_FILENAME(bv, 0));
 4854
 4855  if(buf != buffer) C_free(buf);
 4856
 4857  return C_fix(n);
 4858}
 4859
 4860/*
 4861 * TODO: Implement something for Windows that supports selecting on
 4862 * arbitrary fds (there, select() only works on network sockets and
 4863 * poll() is not available at all).
 4864 */
 4865C_regparm int C_check_fd_ready(int fd)
 4866{
 4867#ifdef NO_POSIX_POLL
 4868  fd_set in;
 4869  struct timeval tm;
 4870  int rv;
 4871  FD_ZERO(&in);
 4872  FD_SET(fd, &in);
 4873  tm.tv_sec = tm.tv_usec = 0;
 4874  rv = select(fd + 1, &in, NULL, NULL, &tm);
 4875  if(rv > 0) { rv = FD_ISSET(fd, &in) ? 1 : 0; }
 4876  return rv;
 4877#else
 4878  struct pollfd ps;
 4879  ps.fd = fd;
 4880  ps.events = POLLIN;
 4881  return poll(&ps, 1, 0);
 4882#endif
 4883}
 4884
 4885C_regparm C_word C_char_ready_p(C_word port)
 4886{
 4887#if defined(C_NONUNIX)
 4888  /* The best we can currently do on Windows... */
 4889  return C_SCHEME_TRUE;
 4890#else
 4891  int fd = C_fileno(C_port_file(port));
 4892  return C_mk_bool(C_check_fd_ready(fd) == 1);
 4893#endif
 4894}
 4895
 4896C_regparm C_word C_i_tty_forcedp(void)
 4897{
 4898  return C_mk_bool(fake_tty_flag);
 4899}
 4900
 4901C_regparm C_word C_i_debug_modep(void)
 4902{
 4903  return C_mk_bool(debug_mode);
 4904}
 4905
 4906C_regparm C_word C_i_dump_heap_on_exitp(void)
 4907{
 4908  return C_mk_bool(dump_heap_on_exit);
 4909}
 4910
 4911C_regparm C_word C_i_profilingp(void)
 4912{
 4913  return C_mk_bool(profiling);
 4914}
 4915
 4916C_regparm C_word C_i_live_finalizer_count(void)
 4917{
 4918  return C_fix(live_finalizer_count);
 4919}
 4920
 4921C_regparm C_word C_i_allocated_finalizer_count(void)
 4922{
 4923  return C_fix(allocated_finalizer_count);
 4924}
 4925
 4926
 4927C_regparm void C_raise_interrupt(int reason)
 4928{
 4929  if(C_interrupts_enabled) {
 4930    if(pending_interrupts_count == 0 && !handling_interrupts) {
 4931      pending_interrupts[ pending_interrupts_count++ ] = reason;
 4932      /*
 4933       * Force the next "soft" stack check to fail by faking a "full"
 4934       * stack.  This causes save_and_reclaim() to be called, which
 4935       * invokes handle_interrupt(), which restores the stack limit.
 4936       */
 4937      C_stack_limit = stack_bottom;
 4938      interrupt_time = C_cpu_milliseconds();
 4939    } else if(pending_interrupts_count < MAX_PENDING_INTERRUPTS) {
 4940      int i;
 4941      /*
 4942       * Drop signals if too many, but don't queue up multiple entries
 4943       * for the same signal.
 4944       */
 4945      for (i = 0; i < pending_interrupts_count; ++i) {
 4946        if (pending_interrupts[i] == reason)
 4947          return;
 4948      }
 4949      pending_interrupts[ pending_interrupts_count++ ] = reason;
 4950    }
 4951  }
 4952}
 4953
 4954
 4955C_regparm C_word C_enable_interrupts(void)
 4956{
 4957  C_timer_interrupt_counter = C_initial_timer_interrupt_period;
 4958  /* assert(C_timer_interrupt_counter > 0); */
 4959  C_interrupts_enabled = 1;
 4960  return C_SCHEME_UNDEFINED;
 4961}
 4962
 4963
 4964C_regparm C_word C_disable_interrupts(void)
 4965{
 4966  C_interrupts_enabled = 0;
 4967  return C_SCHEME_UNDEFINED;
 4968}
 4969
 4970
 4971C_regparm C_word C_establish_signal_handler(C_word signum, C_word reason)
 4972{
 4973  int sig = C_unfix(signum);
 4974#if defined(HAVE_SIGACTION)
 4975  struct sigaction newsig;
 4976#endif
 4977
 4978  if(reason == C_SCHEME_FALSE) C_signal(sig, SIG_IGN);
 4979  else if(reason == C_SCHEME_TRUE) C_signal(sig, SIG_DFL);
 4980  else {
 4981    signal_mapping_table[ sig ] = C_unfix(reason);
 4982#if defined(HAVE_SIGACTION)
 4983    newsig.sa_flags = 0;
 4984    /* The global signal handler is used for all signals, and
 4985       manipulates a single queue.  Don't allow other signals to
 4986       concurrently arrive while it's doing this, to avoid races. */
 4987    sigfillset(&newsig.sa_mask);
 4988    newsig.sa_handler = global_signal_handler;
 4989    C_sigaction(sig, &newsig, NULL);
 4990#else
 4991    C_signal(sig, global_signal_handler);
 4992#endif
 4993  }
 4994
 4995  return C_SCHEME_UNDEFINED;
 4996}
 4997
 4998
 4999/* Copy blocks into collected or static memory: */
 5000
 5001C_regparm C_word C_copy_block(C_word from, C_word to)
 5002{
 5003  int n = C_header_size(from);
 5004  C_long bytes;
 5005
 5006  if(C_header_bits(from) & C_BYTEBLOCK_BIT) {
 5007    bytes = n;
 5008    C_memcpy((C_SCHEME_BLOCK *)to, (C_SCHEME_BLOCK *)from, bytes + sizeof(C_header));
 5009  }
 5010  else {
 5011    bytes = C_wordstobytes(n);
 5012    C_memcpy((C_SCHEME_BLOCK *)to, (C_SCHEME_BLOCK *)from, bytes + sizeof(C_header));
 5013  }
 5014
 5015  return to;
 5016}
 5017
 5018
 5019C_regparm C_word C_evict_block(C_word from, C_word ptr)
 5020{
 5021  int n = C_header_size(from);
 5022  C_long bytes;
 5023  C_word *p = (C_word *)C_pointer_address(ptr);
 5024
 5025  if(C_header_bits(from) & C_BYTEBLOCK_BIT) bytes = n;
 5026  else bytes = C_wordstobytes(n);
 5027
 5028  C_memcpy(p, (C_SCHEME_BLOCK *)from, bytes + sizeof(C_header));
 5029  return (C_word)p;
 5030}
 5031
 5032
 5033/* Inline versions of some standard procedures: */
 5034
 5035C_regparm C_word C_i_listp(C_word x)
 5036{
 5037  C_word fast = x, slow = x;
 5038
 5039  while(fast != C_SCHEME_END_OF_LIST)
 5040    if(!C_immediatep(fast) && C_header_type(fast) == C_PAIR_TYPE) {
 5041      fast = C_u_i_cdr(fast);
 5042
 5043      if(fast == C_SCHEME_END_OF_LIST) return C_SCHEME_TRUE;
 5044      else if(!C_immediatep(fast) && C_header_type(fast) == C_PAIR_TYPE) {
 5045	fast = C_u_i_cdr(fast);
 5046	slow = C_u_i_cdr(slow);
 5047
 5048	if(fast == slow) return C_SCHEME_FALSE;
 5049      }
 5050      else return C_SCHEME_FALSE;
 5051    }
 5052    else return C_SCHEME_FALSE;
 5053
 5054  return C_SCHEME_TRUE;
 5055}
 5056
 5057C_regparm C_word C_i_s8vectorp(C_word x)
 5058{
 5059  return C_i_structurep(x, s8vector_symbol);
 5060}
 5061
 5062C_regparm C_word C_i_u16vectorp(C_word x)
 5063{
 5064  return C_i_structurep(x, u16vector_symbol);
 5065}
 5066
 5067C_regparm C_word C_i_s16vectorp(C_word x)
 5068{
 5069  return C_i_structurep(x, s16vector_symbol);
 5070}
 5071
 5072C_regparm C_word C_i_u32vectorp(C_word x)
 5073{
 5074  return C_i_structurep(x, u32vector_symbol);
 5075}
 5076
 5077C_regparm C_word C_i_s32vectorp(C_word x)
 5078{
 5079  return C_i_structurep(x, s32vector_symbol);
 5080}
 5081
 5082C_regparm C_word C_i_u64vectorp(C_word x)
 5083{
 5084  return C_i_structurep(x, u64vector_symbol);
 5085}
 5086
 5087C_regparm C_word C_i_s64vectorp(C_word x)
 5088{
 5089  return C_i_structurep(x, s64vector_symbol);
 5090}
 5091
 5092C_regparm C_word C_i_f32vectorp(C_word x)
 5093{
 5094  return C_i_structurep(x, f32vector_symbol);
 5095}
 5096
 5097C_regparm C_word C_i_f64vectorp(C_word x)
 5098{
 5099  return C_i_structurep(x, f64vector_symbol);
 5100}
 5101
 5102
 5103C_regparm C_word C_i_string_equal_p(C_word x, C_word y)
 5104{
 5105  if(C_immediatep(x) || C_header_bits(x) != C_STRING_TYPE)
 5106    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string=?", x);
 5107
 5108  if(C_immediatep(y) || C_header_bits(y) != C_STRING_TYPE)
 5109    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string=?", y);
 5110
 5111  return C_utf_equal(x, y);
 5112}
 5113
 5114
 5115C_regparm C_word C_i_string_ci_equal_p(C_word x, C_word y)
 5116{
 5117  if(C_immediatep(x) || C_header_bits(x) != C_STRING_TYPE)
 5118    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string-ci=?", x);
 5119
 5120  if(C_immediatep(y) || C_header_bits(y) != C_STRING_TYPE)
 5121    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string-ci=?", y);
 5122
 5123  return C_utf_equal_ci(x, y);
 5124}
 5125
 5126
 5127C_word C_a_i_list(C_word **a, int c, ...)
 5128{
 5129  va_list v;
 5130  C_word x, last, current,
 5131         first = C_SCHEME_END_OF_LIST;
 5132
 5133  va_start(v, c);
 5134
 5135  for(last = C_SCHEME_UNDEFINED; c--; last = current) {
 5136    x = va_arg(v, C_word);
 5137    current = C_a_pair(a, x, C_SCHEME_END_OF_LIST);
 5138
 5139    if(last != C_SCHEME_UNDEFINED)
 5140      C_set_block_item(last, 1, current);
 5141    else first = current;
 5142  }
 5143
 5144  va_end(v);
 5145  return first;
 5146}
 5147
 5148
 5149C_word C_a_i_string(C_word **a, int c, ...)
 5150{
 5151  va_list v;
 5152  C_word x, s, b;
 5153  char *p;
 5154  int len;
 5155
 5156  s = (C_word)(*a);
 5157  *a = (C_word *)((C_word)(*a) + sizeof(C_word) * 5); /* C_SIZEOF_STRING */
 5158  b = (C_word)(*a);
 5159
 5160  C_block_header_init(s, C_STRING_TAG);
 5161  C_set_block_item(s, 0, b);
 5162  C_set_block_item(s, 1, C_fix(c));
 5163  C_set_block_item(s, 2, C_fix(0));
 5164  C_set_block_item(s, 3, C_fix(0));
 5165  p = (char *)C_data_pointer(b);
 5166  va_start(v, c);
 5167
 5168  for(; c; c--) {
 5169    x = va_arg(v, C_word);
 5170
 5171    if((x & C_IMMEDIATE_TYPE_BITS) == C_CHARACTER_BITS)
 5172      p = C_utf_encode(p, C_character_code(x));
 5173    else break;
 5174  }
 5175
 5176  len = p - (char *)C_data_pointer(b) + 1;
 5177  *a = (C_word *)((C_word)(*a) + sizeof(C_header) + C_align(len));
 5178  *p = '\0';
 5179  C_block_header_init(b, C_BYTEVECTOR_TYPE | len);
 5180  va_end(v);
 5181  if (c) barf(C_BAD_ARGUMENT_TYPE_ERROR, "string", x);
 5182  return s;
 5183}
 5184
 5185
 5186C_word C_a_i_record(C_word **ptr, int n, ...)
 5187{
 5188  va_list v;
 5189  C_word *p = *ptr,
 5190         *p0 = p;
 5191
 5192  *(p++) = C_STRUCTURE_TYPE | n;
 5193  va_start(v, n);
 5194
 5195  while(n--)
 5196    *(p++) = va_arg(v, C_word);
 5197
 5198  *ptr = p;
 5199  va_end(v);
 5200  return (C_word)p0;
 5201}
 5202
 5203
 5204C_word C_a_i_port(C_word **ptr, int n)
 5205{
 5206  C_word
 5207    *p = *ptr,
 5208    *p0 = p;
 5209  int i;
 5210
 5211  *(p++) = C_PORT_TYPE | (C_SIZEOF_PORT - 1);
 5212  *(p++) = (C_word)NULL;
 5213
 5214  for(i = 0; i < C_SIZEOF_PORT - 2; ++i)
 5215    *(p++) = C_SCHEME_FALSE;
 5216
 5217  *ptr = p;
 5218  return (C_word)p0;
 5219}
 5220
 5221
 5222C_regparm C_word C_a_i_bytevector(C_word **ptr, int c, C_word num)
 5223{
 5224  C_word *p = *ptr,
 5225         *p0;
 5226  int n = C_unfix(num);
 5227
 5228#ifndef C_SIXTY_FOUR
 5229  /* Align on 8-byte boundary: */
 5230  if(C_aligned8(p)) ++p;
 5231#endif
 5232
 5233  p0 = p;
 5234  *(p++) = C_BYTEVECTOR_TYPE | C_wordstobytes(n);
 5235  *ptr = p + n;
 5236  return (C_word)p0;
 5237}
 5238
 5239
 5240C_word C_a_i_smart_mpointer(C_word **ptr, int c, C_word x)
 5241{
 5242  C_word
 5243    *p = *ptr,
 5244    *p0 = p;
 5245  void *mp;
 5246
 5247  if(C_immediatep(x)) mp = NULL;
 5248  else if((C_header_bits(x) & C_SPECIALBLOCK_BIT) != 0) mp = C_pointer_address(x);
 5249  else mp = C_data_pointer(x);
 5250
 5251  *(p++) = C_POINTER_TYPE | 1;
 5252  *((void **)p) = mp;
 5253  *ptr = p + 1;
 5254  return (C_word)p0;
 5255}
 5256
 5257C_regparm C_word C_i_nanp(C_word x)
 5258{
 5259  if (x & C_FIXNUM_BIT) {
 5260    return C_SCHEME_FALSE;
 5261  } else if (C_immediatep(x)) {
 5262    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "nan?", x);
 5263  } else if (C_block_header(x) == C_FLONUM_TAG) {
 5264    return C_u_i_flonum_nanp(x);
 5265  } else if (C_truep(C_bignump(x))) {
 5266    return C_SCHEME_FALSE;
 5267  } else if (C_block_header(x) == C_RATNUM_TAG) {
 5268    return C_SCHEME_FALSE;
 5269  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 5270    return C_mk_bool(C_truep(C_i_nanp(C_u_i_cplxnum_real(x))) ||
 5271		     C_truep(C_i_nanp(C_u_i_cplxnum_imag(x))));
 5272  } else {
 5273    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "nan?", x);
 5274  }
 5275}
 5276
 5277C_regparm C_word C_i_finitep(C_word x)
 5278{
 5279  if (x & C_FIXNUM_BIT) {
 5280    return C_SCHEME_TRUE;
 5281  } else if (C_immediatep(x)) {
 5282    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "finite?", x);
 5283  } else if (C_block_header(x) == C_FLONUM_TAG) {
 5284    return C_u_i_flonum_finitep(x);
 5285  } else if (C_truep(C_bignump(x))) {
 5286    return C_SCHEME_TRUE;
 5287  } else if (C_block_header(x) == C_RATNUM_TAG) {
 5288    return C_SCHEME_TRUE;
 5289  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 5290    return C_and(C_i_finitep(C_u_i_cplxnum_real(x)),
 5291		 C_i_finitep(C_u_i_cplxnum_imag(x)));
 5292  } else {
 5293    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "finite?", x);
 5294  }
 5295}
 5296
 5297C_regparm C_word C_i_infinitep(C_word x)
 5298{
 5299  if (x & C_FIXNUM_BIT) {
 5300    return C_SCHEME_FALSE;
 5301  } else if (C_immediatep(x)) {
 5302    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "infinite?", x);
 5303  } else if (C_block_header(x) == C_FLONUM_TAG) {
 5304    return C_u_i_flonum_infinitep(x);
 5305  } else if (C_truep(C_bignump(x))) {
 5306    return C_SCHEME_FALSE;
 5307  } else if (C_block_header(x) == C_RATNUM_TAG) {
 5308    return C_SCHEME_FALSE;
 5309  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 5310    return C_mk_bool(C_truep(C_i_infinitep(C_u_i_cplxnum_real(x))) ||
 5311                     C_truep(C_i_infinitep(C_u_i_cplxnum_imag(x))));
 5312  } else {
 5313    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "infinite?", x);
 5314  }
 5315}
 5316
 5317C_regparm C_word C_i_exactp(C_word x)
 5318{
 5319  if (x & C_FIXNUM_BIT) {
 5320    return C_SCHEME_TRUE;
 5321  } else if (C_immediatep(x)) {
 5322    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "exact?", x);
 5323  } else if (C_block_header(x) == C_FLONUM_TAG) {
 5324    return C_SCHEME_FALSE;
 5325  } else if (C_truep(C_bignump(x))) {
 5326    return C_SCHEME_TRUE;
 5327  } else if (C_block_header(x) == C_RATNUM_TAG) {
 5328    return C_SCHEME_TRUE;
 5329  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 5330    return C_i_exactp(C_u_i_cplxnum_real(x)); /* Exactness of i and r matches */
 5331  } else {
 5332    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "exact?", x);
 5333  }
 5334}
 5335
 5336
 5337C_regparm C_word C_i_inexactp(C_word x)
 5338{
 5339  if (x & C_FIXNUM_BIT) {
 5340    return C_SCHEME_FALSE;
 5341  } else if (C_immediatep(x)) {
 5342    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "inexact?", x);
 5343  } else if (C_block_header(x) == C_FLONUM_TAG) {
 5344    return C_SCHEME_TRUE;
 5345  } else if (C_truep(C_bignump(x))) {
 5346    return C_SCHEME_FALSE;
 5347  } else if (C_block_header(x) == C_RATNUM_TAG) {
 5348    return C_SCHEME_FALSE;
 5349  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 5350    return C_i_inexactp(C_u_i_cplxnum_real(x)); /* Exactness of i and r matches */
 5351  } else {
 5352    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "inexact?", x);
 5353  }
 5354}
 5355
 5356
 5357C_regparm C_word C_i_zerop(C_word x)
 5358{
 5359  if (x & C_FIXNUM_BIT) {
 5360    return C_mk_bool(x == C_fix(0));
 5361  } else if (C_immediatep(x)) {
 5362    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "zero?", x);
 5363  } else if (C_block_header(x) == C_FLONUM_TAG) {
 5364    return C_mk_bool(C_flonum_magnitude(x) == 0.0);
 5365  } else if (C_block_header(x) == C_BIGNUM_TAG ||
 5366             C_block_header(x) == C_RATNUM_TAG ||
 5367             C_block_header(x) == C_CPLXNUM_TAG) {
 5368    return C_SCHEME_FALSE;
 5369  } else {
 5370    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "zero?", x);
 5371  }
 5372}
 5373
 5374/* DEPRECATED */
 5375C_regparm C_word C_u_i_zerop(C_word x)
 5376{
 5377  return C_mk_bool(x == C_fix(0) ||
 5378                   (!C_immediatep(x) &&
 5379                    C_block_header(x) == C_FLONUM_TAG &&
 5380                    C_flonum_magnitude(x) == 0.0));
 5381}
 5382
 5383
 5384C_regparm C_word C_i_positivep(C_word x)
 5385{
 5386  if (x & C_FIXNUM_BIT)
 5387    return C_i_fixnum_positivep(x);
 5388  else if (C_immediatep(x))
 5389    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "positive?", x);
 5390  else if (C_block_header(x) == C_FLONUM_TAG)
 5391    return C_mk_bool(C_flonum_magnitude(x) > 0.0);
 5392  else if (C_truep(C_bignump(x)))
 5393    return C_mk_nbool(C_bignum_negativep(x));
 5394  else if (C_block_header(x) == C_RATNUM_TAG)
 5395    return C_i_integer_positivep(C_u_i_ratnum_num(x));
 5396  else if (C_block_header(x) == C_CPLXNUM_TAG)
 5397    barf(C_BAD_ARGUMENT_TYPE_NO_REAL_ERROR, "positive?", x);
 5398  else
 5399    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "positive?", x);
 5400}
 5401
 5402C_regparm C_word C_i_integer_positivep(C_word x)
 5403{
 5404  if (x & C_FIXNUM_BIT) return C_i_fixnum_positivep(x);
 5405  else return C_mk_nbool(C_bignum_negativep(x));
 5406}
 5407
 5408C_regparm C_word C_i_negativep(C_word x)
 5409{
 5410  if (x & C_FIXNUM_BIT)
 5411    return C_i_fixnum_negativep(x);
 5412  else if (C_immediatep(x))
 5413    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "negative?", x);
 5414  else if (C_block_header(x) == C_FLONUM_TAG)
 5415    return C_mk_bool(C_flonum_magnitude(x) < 0.0);
 5416  else if (C_truep(C_bignump(x)))
 5417    return C_mk_bool(C_bignum_negativep(x));
 5418  else if (C_block_header(x) == C_RATNUM_TAG)
 5419    return C_i_integer_negativep(C_u_i_ratnum_num(x));
 5420  else if (C_block_header(x) == C_CPLXNUM_TAG)
 5421    barf(C_BAD_ARGUMENT_TYPE_NO_REAL_ERROR, "negative?", x);
 5422  else
 5423    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "negative?", x);
 5424}
 5425
 5426
 5427C_regparm C_word C_i_integer_negativep(C_word x)
 5428{
 5429  if (x & C_FIXNUM_BIT) return C_i_fixnum_negativep(x);
 5430  else return C_mk_bool(C_bignum_negativep(x));
 5431}
 5432
 5433
 5434C_regparm C_word C_i_evenp(C_word x)
 5435{
 5436  if(x & C_FIXNUM_BIT) {
 5437    return C_i_fixnumevenp(x);
 5438  } else if(C_immediatep(x)) {
 5439    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "even?", x);
 5440  } else if (C_block_header(x) == C_FLONUM_TAG) {
 5441    double val, dummy;
 5442    val = C_flonum_magnitude(x);
 5443    if(C_isnan(val) || C_isinf(val) || C_modf(val, &dummy) != 0.0)
 5444      barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "even?", x);
 5445    else
 5446      return C_mk_bool(fmod(val, 2.0) == 0.0);
 5447  } else if (C_truep(C_bignump(x))) {
 5448    return C_mk_nbool(C_bignum_digits(x)[0] & 1);
 5449  } else { /* No need to try extended number */
 5450    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "even?", x);
 5451  }
 5452}
 5453
 5454C_regparm C_word C_i_integer_evenp(C_word x)
 5455{
 5456  if (x & C_FIXNUM_BIT) return C_i_fixnumevenp(x);
 5457  return C_mk_nbool(C_bignum_digits(x)[0] & 1);
 5458}
 5459
 5460
 5461C_regparm C_word C_i_oddp(C_word x)
 5462{
 5463  if(x & C_FIXNUM_BIT) {
 5464    return C_i_fixnumoddp(x);
 5465  } else if(C_immediatep(x)) {
 5466    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "odd?", x);
 5467  } else if(C_block_header(x) == C_FLONUM_TAG) {
 5468    double val, dummy;
 5469    val = C_flonum_magnitude(x);
 5470    if(C_isnan(val) || C_isinf(val) || C_modf(val, &dummy) != 0.0)
 5471      barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "odd?", x);
 5472    else
 5473      return C_mk_bool(fmod(val, 2.0) != 0.0);
 5474  } else if (C_truep(C_bignump(x))) {
 5475    return C_mk_bool(C_bignum_digits(x)[0] & 1);
 5476  } else {
 5477    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "odd?", x);
 5478  }
 5479}
 5480
 5481
 5482C_regparm C_word C_i_integer_oddp(C_word x)
 5483{
 5484  if (x & C_FIXNUM_BIT) return C_i_fixnumoddp(x);
 5485  return C_mk_bool(C_bignum_digits(x)[0] & 1);
 5486}
 5487
 5488
 5489C_regparm C_word C_i_car(C_word x)
 5490{
 5491  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE)
 5492    barf(C_BAD_ARGUMENT_TYPE_ERROR, "car", x);
 5493
 5494  return C_u_i_car(x);
 5495}
 5496
 5497
 5498C_regparm C_word C_i_cdr(C_word x)
 5499{
 5500  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE)
 5501    barf(C_BAD_ARGUMENT_TYPE_ERROR, "cdr", x);
 5502
 5503  return C_u_i_cdr(x);
 5504}
 5505
 5506
 5507C_regparm C_word C_i_caar(C_word x)
 5508{
 5509  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 5510  bad:
 5511    barf(C_BAD_ARGUMENT_TYPE_ERROR, "caar", x);
 5512  }
 5513
 5514  x = C_u_i_car(x);
 5515
 5516  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5517
 5518  return C_u_i_car(x);
 5519}
 5520
 5521
 5522C_regparm C_word C_i_cadr(C_word x)
 5523{
 5524  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 5525  bad:
 5526    barf(C_BAD_ARGUMENT_TYPE_ERROR, "cadr", x);
 5527  }
 5528
 5529  x = C_u_i_cdr(x);
 5530
 5531  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5532
 5533  return C_u_i_car(x);
 5534}
 5535
 5536
 5537C_regparm C_word C_i_cdar(C_word x)
 5538{
 5539  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 5540  bad:
 5541    barf(C_BAD_ARGUMENT_TYPE_ERROR, "cdar", x);
 5542  }
 5543
 5544  x = C_u_i_car(x);
 5545
 5546  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5547
 5548  return C_u_i_cdr(x);
 5549}
 5550
 5551
 5552C_regparm C_word C_i_cddr(C_word x)
 5553{
 5554  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 5555  bad:
 5556    barf(C_BAD_ARGUMENT_TYPE_ERROR, "cddr", x);
 5557  }
 5558
 5559  x = C_u_i_cdr(x);
 5560  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5561
 5562  return C_u_i_cdr(x);
 5563}
 5564
 5565
 5566C_regparm C_word C_i_caddr(C_word x)
 5567{
 5568  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 5569  bad:
 5570    barf(C_BAD_ARGUMENT_TYPE_ERROR, "caddr", x);
 5571  }
 5572
 5573  x = C_u_i_cdr(x);
 5574  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5575  x = C_u_i_cdr(x);
 5576  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5577
 5578  return C_u_i_car(x);
 5579}
 5580
 5581
 5582C_regparm C_word C_i_cdddr(C_word x)
 5583{
 5584  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 5585  bad:
 5586    barf(C_BAD_ARGUMENT_TYPE_ERROR, "cdddr", x);
 5587  }
 5588
 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_cdr(x);
 5595}
 5596
 5597
 5598C_regparm C_word C_i_cadddr(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, "cadddr", 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_car(x);
 5613}
 5614
 5615
 5616C_regparm C_word C_i_cddddr(C_word x)
 5617{
 5618  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 5619  bad:
 5620    barf(C_BAD_ARGUMENT_TYPE_ERROR, "cddddr", x);
 5621  }
 5622
 5623  x = C_u_i_cdr(x);
 5624  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5625  x = C_u_i_cdr(x);
 5626  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5627  x = C_u_i_cdr(x);
 5628  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5629
 5630  return C_u_i_cdr(x);
 5631}
 5632
 5633
 5634C_regparm C_word C_i_list_tail(C_word lst, C_word i)
 5635{
 5636  C_word lst0 = lst;
 5637  int n;
 5638
 5639  if(lst != C_SCHEME_END_OF_LIST &&
 5640     (C_immediatep(lst) || C_header_type(lst) != C_PAIR_TYPE))
 5641    barf(C_BAD_ARGUMENT_TYPE_ERROR, "list-tail", lst);
 5642
 5643  if(i & C_FIXNUM_BIT) n = C_unfix(i);
 5644  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "list-tail", i);
 5645
 5646  while(n--) {
 5647    if(C_immediatep(lst) || C_header_type(lst) != C_PAIR_TYPE)
 5648      barf(C_OUT_OF_BOUNDS_ERROR, "list-tail", lst0, i);
 5649
 5650    lst = C_u_i_cdr(lst);
 5651  }
 5652
 5653  return lst;
 5654}
 5655
 5656
 5657C_regparm C_word C_i_vector_ref(C_word v, C_word i)
 5658{
 5659  int j;
 5660
 5661  if(C_immediatep(v) || C_header_bits(v) != C_VECTOR_TYPE)
 5662    barf(C_BAD_ARGUMENT_TYPE_ERROR, "vector-ref", v);
 5663
 5664  if(i & C_FIXNUM_BIT) {
 5665    j = C_unfix(i);
 5666
 5667    if(j < 0 || j >= C_header_size(v)) barf(C_OUT_OF_BOUNDS_ERROR, "vector-ref", v, i);
 5668
 5669    return C_block_item(v, j);
 5670  }
 5671
 5672  barf(C_BAD_ARGUMENT_TYPE_ERROR, "vector-ref", i);
 5673  return C_SCHEME_UNDEFINED;
 5674}
 5675
 5676C_regparm C_word C_i_bytevector_ref(C_word v, C_word i)
 5677{
 5678  int j;
 5679
 5680  if(!C_truep(C_bytevectorp(v)))
 5681    barf(C_BAD_ARGUMENT_TYPE_ERROR, "bytevector-u8-ref", v);
 5682
 5683  if(i & C_FIXNUM_BIT) {
 5684    j = C_unfix(i);
 5685
 5686    if(j < 0 || j >= C_header_size(v))
 5687    	barf(C_OUT_OF_BOUNDS_ERROR, "bytevector-u8-ref", v, i);
 5688
 5689    return C_fix(((unsigned char *)C_data_pointer(v))[j]);
 5690  }
 5691
 5692  barf(C_BAD_ARGUMENT_TYPE_ERROR, "bytevector-u8-ref", i);
 5693  return C_SCHEME_UNDEFINED;
 5694}
 5695
 5696C_regparm C_word C_i_s8vector_ref(C_word v, C_word i)
 5697{
 5698  int j;
 5699
 5700  if(!C_truep(C_i_s8vectorp(v)))
 5701    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s8vector-ref", v);
 5702
 5703  if(i & C_FIXNUM_BIT) {
 5704    j = C_unfix(i);
 5705
 5706    if(j < 0 || j >= C_header_size(C_block_item(v, 1)))
 5707    	barf(C_OUT_OF_BOUNDS_ERROR, "s8vector-ref", v, i);
 5708
 5709    return C_fix(((signed char *)C_data_pointer(C_block_item(v, 1)))[j]);
 5710  }
 5711
 5712  barf(C_BAD_ARGUMENT_TYPE_ERROR, "s8vector-ref", i);
 5713  return C_SCHEME_UNDEFINED;
 5714}
 5715
 5716C_regparm C_word C_i_u16vector_ref(C_word v, C_word i)
 5717{
 5718  int j;
 5719
 5720  if(!C_truep(C_i_u16vectorp(v)))
 5721    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u16vector-ref", v);
 5722
 5723  if(i & C_FIXNUM_BIT) {
 5724    j = C_unfix(i);
 5725
 5726    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 1))
 5727    	barf(C_OUT_OF_BOUNDS_ERROR, "u16vector-ref", v, i);
 5728
 5729    return C_fix(((unsigned short *)C_data_pointer(C_block_item(v, 1)))[j]);
 5730  }
 5731
 5732  barf(C_BAD_ARGUMENT_TYPE_ERROR, "u16vector-ref", i);
 5733  return C_SCHEME_UNDEFINED;
 5734}
 5735
 5736C_regparm C_word C_i_s16vector_ref(C_word v, C_word i)
 5737{
 5738  C_word size;
 5739  int j;
 5740
 5741  if(C_immediatep(v) || C_header_bits(v) != C_STRUCTURE_TYPE ||
 5742     C_header_size(v) != 2 || C_block_item(v, 0) != s16vector_symbol)
 5743    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s16vector-ref", v);
 5744
 5745  if(i & C_FIXNUM_BIT) {
 5746    j = C_unfix(i);
 5747
 5748    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 1))
 5749    	barf(C_OUT_OF_BOUNDS_ERROR, "u16vector-ref", v, i);
 5750
 5751    return C_fix(((signed short *)C_data_pointer(C_block_item(v, 1)))[j]);
 5752  }
 5753
 5754  barf(C_BAD_ARGUMENT_TYPE_ERROR, "s16vector-ref", i);
 5755  return C_SCHEME_UNDEFINED;
 5756}
 5757
 5758C_regparm C_word C_a_i_u32vector_ref(C_word **ptr, C_word c, C_word v, C_word i)
 5759{
 5760  int j;
 5761
 5762  if(!C_truep(C_i_u32vectorp(v)))
 5763    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u32vector-ref", v);
 5764
 5765  if(i & C_FIXNUM_BIT) {
 5766    j = C_unfix(i);
 5767
 5768    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 2))
 5769    	barf(C_OUT_OF_BOUNDS_ERROR, "u32vector-ref", v, i);
 5770
 5771    return C_unsigned_int_to_num(ptr, ((C_u32 *)C_data_pointer(C_block_item(v, 1)))[j]);
 5772  }
 5773
 5774  barf(C_BAD_ARGUMENT_TYPE_ERROR, "u32vector-ref", i);
 5775  return C_SCHEME_UNDEFINED;
 5776}
 5777
 5778C_regparm C_word C_a_i_s32vector_ref(C_word **ptr, C_word c, C_word v, C_word i)
 5779{
 5780  int j;
 5781
 5782  if(!C_truep(C_i_s32vectorp(v)))
 5783    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s32vector-ref", v);
 5784
 5785  if(i & C_FIXNUM_BIT) {
 5786    j = C_unfix(i);
 5787
 5788    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 2))
 5789    	barf(C_OUT_OF_BOUNDS_ERROR, "s32vector-ref", v, i);
 5790
 5791    return C_int_to_num(ptr, ((C_s32 *)C_data_pointer(C_block_item(v, 1)))[j]);
 5792  }
 5793
 5794  barf(C_BAD_ARGUMENT_TYPE_ERROR, "s32vector-ref", i);
 5795  return C_SCHEME_UNDEFINED;
 5796}
 5797
 5798C_regparm C_word C_a_i_u64vector_ref(C_word **ptr, C_word c, C_word v, C_word i)
 5799{
 5800  int j;
 5801
 5802  if(!C_truep(C_i_u64vectorp(v)))
 5803    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u64vector-ref", v);
 5804
 5805  if(i & C_FIXNUM_BIT) {
 5806    j = C_unfix(i);
 5807
 5808    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 3))
 5809    	barf(C_OUT_OF_BOUNDS_ERROR, "u64vector-ref", v, i);
 5810
 5811    return C_uint64_to_num(ptr, ((C_u64 *)C_data_pointer(C_block_item(v, 1)))[j]);
 5812  }
 5813
 5814  barf(C_BAD_ARGUMENT_TYPE_ERROR, "u64vector-ref", i);
 5815  return C_SCHEME_UNDEFINED;
 5816}
 5817
 5818C_regparm C_word C_a_i_s64vector_ref(C_word **ptr, C_word c, C_word v, C_word i)
 5819{
 5820  int j;
 5821
 5822  if(!C_truep(C_i_s64vectorp(v)))
 5823    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s64vector-ref", v);
 5824
 5825  if(i & C_FIXNUM_BIT) {
 5826    j = C_unfix(i);
 5827
 5828    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 3))
 5829    	barf(C_OUT_OF_BOUNDS_ERROR, "s64vector-ref", v, i);
 5830
 5831    return C_int64_to_num(ptr, ((C_s64 *)C_data_pointer(C_block_item(v, 1)))[j]);
 5832  }
 5833
 5834  barf(C_BAD_ARGUMENT_TYPE_ERROR, "s64vector-ref", i);
 5835  return C_SCHEME_UNDEFINED;
 5836}
 5837
 5838C_regparm C_word C_a_i_f32vector_ref(C_word **ptr, C_word c, C_word v, C_word i)
 5839{
 5840  int j;
 5841
 5842  if(!C_truep(C_i_f32vectorp(v)))
 5843    barf(C_BAD_ARGUMENT_TYPE_ERROR, "f32vector-ref", v);
 5844
 5845  if(i & C_FIXNUM_BIT) {
 5846    j = C_unfix(i);
 5847
 5848    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 2))
 5849    	barf(C_OUT_OF_BOUNDS_ERROR, "f32vector-ref", v, i);
 5850
 5851    return C_flonum(ptr, ((float *)C_data_pointer(C_block_item(v, 1)))[j]);
 5852  }
 5853
 5854  barf(C_BAD_ARGUMENT_TYPE_ERROR, "f32vector-ref", i);
 5855  return C_SCHEME_UNDEFINED;
 5856}
 5857
 5858C_regparm C_word C_a_i_f64vector_ref(C_word **ptr, C_word c, C_word v, C_word i)
 5859{
 5860  C_word size;
 5861  int j;
 5862
 5863  if(!C_truep(C_i_f64vectorp(v)))
 5864    barf(C_BAD_ARGUMENT_TYPE_ERROR, "f64vector-ref", v);
 5865
 5866  if(i & C_FIXNUM_BIT) {
 5867    j = C_unfix(i);
 5868
 5869    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 3))
 5870    	barf(C_OUT_OF_BOUNDS_ERROR, "f64vector-ref", v, i);
 5871
 5872    return C_flonum(ptr, ((double *)C_data_pointer(C_block_item(v, 1)))[j]);
 5873  }
 5874
 5875  barf(C_BAD_ARGUMENT_TYPE_ERROR, "f64vector-ref", i);
 5876  return C_SCHEME_UNDEFINED;
 5877}
 5878
 5879
 5880C_regparm C_word C_i_block_ref(C_word x, C_word i)
 5881{
 5882  int j;
 5883
 5884  if(C_immediatep(x) || (C_header_bits(x) & C_BYTEBLOCK_BIT) != 0)
 5885    barf(C_BAD_ARGUMENT_TYPE_NO_BLOCK_ERROR, "##sys#block-ref", x);
 5886
 5887  if(i & C_FIXNUM_BIT) {
 5888    j = C_unfix(i);
 5889
 5890    if(j < 0 || j >= C_header_size(x))
 5891    	barf(C_OUT_OF_BOUNDS_ERROR, "##sys#block-ref", x, i);
 5892
 5893    return C_block_item(x, j);
 5894  }
 5895
 5896  barf(C_BAD_ARGUMENT_TYPE_ERROR, "##sys#block-ref", i);
 5897  return C_SCHEME_UNDEFINED;
 5898}
 5899
 5900
 5901C_regparm C_word C_i_string_set(C_word s, C_word i, C_word c)
 5902{
 5903  int j;
 5904
 5905  if(C_immediatep(s) || C_header_bits(s) != C_STRING_TYPE)
 5906    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string-set!", s);
 5907
 5908  if(!C_immediatep(c) || (c & C_IMMEDIATE_TYPE_BITS) != C_CHARACTER_BITS)
 5909    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string-set!", c);
 5910
 5911  if(i & C_FIXNUM_BIT) {
 5912    j = C_unfix(i);
 5913
 5914    if(j < 0 || j >= C_unfix(C_block_item(s, 1)))
 5915        barf(C_OUT_OF_BOUNDS_ERROR, "string-set!", s, i);
 5916
 5917    return C_utf_setsubchar(s, i, c);
 5918  }
 5919
 5920  barf(C_BAD_ARGUMENT_TYPE_ERROR, "string-set!", i);
 5921  return C_SCHEME_UNDEFINED;
 5922}
 5923
 5924
 5925C_regparm C_word C_i_string_ref(C_word s, C_word i)
 5926{
 5927  int j;
 5928
 5929  if(C_immediatep(s) || C_header_bits(s) != C_STRING_TYPE)
 5930    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string-ref", s);
 5931
 5932  if(i & C_FIXNUM_BIT) {
 5933    j = C_unfix(i);
 5934
 5935    if(j < 0 || j >= C_unfix(C_block_item(s, 1)))
 5936        barf(C_OUT_OF_BOUNDS_ERROR, "string-ref", s, i);
 5937
 5938    return C_utf_subchar(s, i);
 5939  }
 5940
 5941  barf(C_BAD_ARGUMENT_TYPE_ERROR, "string-ref", i);
 5942  return C_SCHEME_UNDEFINED;
 5943}
 5944
 5945
 5946C_regparm C_word C_i_vector_length(C_word v)
 5947{
 5948  if(C_immediatep(v) || C_header_bits(v) != C_VECTOR_TYPE)
 5949    barf(C_BAD_ARGUMENT_TYPE_ERROR, "vector-length", v);
 5950
 5951  return C_fix(C_header_size(v));
 5952}
 5953
 5954C_regparm C_word C_i_bytevector_length(C_word v)
 5955{
 5956  if(C_immediatep(v) || !C_truep(C_bytevectorp(v)))
 5957    barf(C_BAD_ARGUMENT_TYPE_ERROR, "bytevector-length", v);
 5958
 5959  return C_fix(C_header_size(v));
 5960}
 5961
 5962C_regparm C_word C_i_s8vector_length(C_word v)
 5963{
 5964  if(!C_truep(C_i_s8vectorp(v)))
 5965    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s8vector-length", v);
 5966
 5967  return C_fix(C_header_size(C_block_item(v, 1)));
 5968}
 5969
 5970C_regparm C_word C_i_u16vector_length(C_word v)
 5971{
 5972  if(!C_truep(C_i_u16vectorp(v)))
 5973    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u16vector-length", v);
 5974
 5975  return C_fix(C_header_size(C_block_item(v, 1)) >> 1);
 5976}
 5977
 5978C_regparm C_word C_i_s16vector_length(C_word v)
 5979{
 5980  if(!C_truep(C_i_s16vectorp(v)))
 5981    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s16vector-length", v);
 5982
 5983  return C_fix(C_header_size(C_block_item(v, 1)) >> 1);
 5984}
 5985
 5986C_regparm C_word C_i_u32vector_length(C_word v)
 5987{
 5988  if(!C_truep(C_i_u32vectorp(v)))
 5989    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u32vector-length", v);
 5990
 5991  return C_fix(C_header_size(C_block_item(v, 1)) >> 2);
 5992}
 5993
 5994C_regparm C_word C_i_s32vector_length(C_word v)
 5995{
 5996  if(!C_truep(C_i_s32vectorp(v)))
 5997    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s32vector-length", v);
 5998
 5999  return C_fix(C_header_size(C_block_item(v, 1)) >> 2);
 6000}
 6001
 6002C_regparm C_word C_i_u64vector_length(C_word v)
 6003{
 6004  if(!C_truep(C_i_u64vectorp(v)))
 6005    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u64vector-length", v);
 6006
 6007  return C_fix(C_header_size(C_block_item(v, 1)) >> 3);
 6008}
 6009
 6010C_regparm C_word C_i_s64vector_length(C_word v)
 6011{
 6012  if(!C_truep(C_i_s64vectorp(v)))
 6013    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s64vector-length", v);
 6014
 6015  return C_fix(C_header_size(C_block_item(v, 1)) >> 3);
 6016}
 6017
 6018
 6019C_regparm C_word C_i_f32vector_length(C_word v)
 6020{
 6021  if(!C_truep(C_i_f32vectorp(v)))
 6022    barf(C_BAD_ARGUMENT_TYPE_ERROR, "f32vector-length", v);
 6023
 6024  return C_fix(C_header_size(C_block_item(v, 1)) >> 2);
 6025}
 6026
 6027C_regparm C_word C_i_f64vector_length(C_word v)
 6028{
 6029  if(!C_truep(C_i_f64vectorp(v)))
 6030    barf(C_BAD_ARGUMENT_TYPE_ERROR, "f64vector-length", v);
 6031
 6032  return C_fix(C_header_size(C_block_item(v, 1)) >> 3);
 6033}
 6034
 6035
 6036C_regparm C_word C_i_string_length(C_word s)
 6037{
 6038  if(C_immediatep(s) || C_header_bits(s) != C_STRING_TYPE)
 6039    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string-length", s);
 6040
 6041  return C_block_item(s, 1);
 6042}
 6043
 6044
 6045C_regparm C_word C_i_length(C_word lst)
 6046{
 6047  C_word fast = lst, slow = lst;
 6048  int n = 0;
 6049
 6050  while(slow != C_SCHEME_END_OF_LIST) {
 6051    if(fast != C_SCHEME_END_OF_LIST) {
 6052      if(!C_immediatep(fast) && C_header_type(fast) == C_PAIR_TYPE) {
 6053	fast = C_u_i_cdr(fast);
 6054
 6055	if(fast != C_SCHEME_END_OF_LIST) {
 6056	  if(!C_immediatep(fast) && C_header_type(fast) == C_PAIR_TYPE) {
 6057	    fast = C_u_i_cdr(fast);
 6058	  }
 6059	  else barf(C_NOT_A_PROPER_LIST_ERROR, "length", lst);
 6060	}
 6061
 6062	if(fast == slow)
 6063	  barf(C_BAD_ARGUMENT_TYPE_CYCLIC_LIST_ERROR, "length", lst);
 6064      }
 6065    }
 6066
 6067    if(C_immediatep(slow) || C_header_type(slow) != C_PAIR_TYPE)
 6068      barf(C_NOT_A_PROPER_LIST_ERROR, "length", lst);
 6069
 6070    slow = C_u_i_cdr(slow);
 6071    ++n;
 6072  }
 6073
 6074  return C_fix(n);
 6075}
 6076
 6077
 6078C_regparm C_word C_u_i_length(C_word lst)
 6079{
 6080  int n = 0;
 6081
 6082  while(!C_immediatep(lst) && C_header_type(lst) == C_PAIR_TYPE) {
 6083    lst = C_u_i_cdr(lst);
 6084    ++n;
 6085  }
 6086
 6087  return C_fix(n);
 6088}
 6089
 6090C_regparm C_word C_i_set_car(C_word x, C_word val)
 6091{
 6092  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE)
 6093    barf(C_BAD_ARGUMENT_TYPE_ERROR, "set-car!", x);
 6094
 6095  C_mutate(&C_u_i_car(x), val);
 6096  return C_SCHEME_UNDEFINED;
 6097}
 6098
 6099
 6100C_regparm C_word C_i_set_cdr(C_word x, C_word val)
 6101{
 6102  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE)
 6103    barf(C_BAD_ARGUMENT_TYPE_ERROR, "set-cdr!", x);
 6104
 6105  C_mutate(&C_u_i_cdr(x), val);
 6106  return C_SCHEME_UNDEFINED;
 6107}
 6108
 6109
 6110C_regparm C_word C_i_vector_set(C_word v, C_word i, C_word x)
 6111{
 6112  int j;
 6113
 6114  if(C_immediatep(v) || C_header_bits(v) != C_VECTOR_TYPE)
 6115    barf(C_BAD_ARGUMENT_TYPE_ERROR, "vector-set!", v);
 6116
 6117  if(i & C_FIXNUM_BIT) {
 6118    j = C_unfix(i);
 6119
 6120    if(j < 0 || j >= C_header_size(v))
 6121    	barf(C_OUT_OF_BOUNDS_ERROR, "vector-set!", v, i);
 6122
 6123    C_mutate(&C_block_item(v, j), x);
 6124  }
 6125  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "vector-set!", i);
 6126
 6127  return C_SCHEME_UNDEFINED;
 6128}
 6129
 6130C_regparm C_word C_i_bytevector_set(C_word v, C_word i, C_word x)
 6131{
 6132  int j;
 6133  C_word n;
 6134
 6135  if(!C_truep(C_bytevectorp(v)))
 6136    barf(C_BAD_ARGUMENT_TYPE_ERROR, "bytevector-set!", v);
 6137
 6138  if(i & C_FIXNUM_BIT) {
 6139    j = C_unfix(i);
 6140
 6141    if(j < 0 || j >= C_header_size(v))
 6142    	barf(C_OUT_OF_BOUNDS_ERROR, "bytevector-u8-set!", v, i);
 6143
 6144    if(x & C_FIXNUM_BIT) {
 6145      if (C_unfix(C_i_fixnum_length(x)) <= 8) n = C_unfix(x);
 6146      else barf(C_BAD_ARGUMENT_TYPE_NUMERIC_RANGE_ERROR, "bytevector-u8-set!", x);
 6147    }
 6148    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "bytevector-u8-set!", x);
 6149  }
 6150  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "bytevector-u8-set!", i);
 6151
 6152  ((signed char *)C_data_pointer(v))[j] = n;
 6153  return C_SCHEME_UNDEFINED;
 6154}
 6155
 6156C_regparm C_word C_i_s8vector_set(C_word v, C_word i, C_word x)
 6157{
 6158  int j;
 6159  C_word n;
 6160
 6161  if(!C_truep(C_i_s8vectorp(v)))
 6162    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s8vector-set!", v);
 6163
 6164  if(i & C_FIXNUM_BIT) {
 6165    j = C_unfix(i);
 6166
 6167    if(j < 0 || j >= C_header_size(C_block_item(v, 1)))
 6168    	barf(C_OUT_OF_BOUNDS_ERROR, "s8vector-set!", v, i);
 6169
 6170    if(x & C_FIXNUM_BIT) {
 6171      if (C_unfix(C_i_fixnum_length(x)) <= 8) n = C_unfix(x);
 6172      else barf(C_BAD_ARGUMENT_TYPE_NUMERIC_RANGE_ERROR, "s8vector-set!", x);
 6173    }
 6174    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s8vector-set!", x);
 6175  }
 6176  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s8vector-set!", i);
 6177
 6178  ((signed char *)C_data_pointer(C_block_item(v, 1)))[j] = n;
 6179  return C_SCHEME_UNDEFINED;
 6180}
 6181
 6182C_regparm C_word C_i_u16vector_set(C_word v, C_word i, C_word x)
 6183{
 6184  int j;
 6185  C_word n;
 6186
 6187  if(!C_truep(C_i_u16vectorp(v)))
 6188    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u16vector-set!", v);
 6189
 6190  if(i & C_FIXNUM_BIT) {
 6191    j = C_unfix(i);
 6192
 6193    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 1))
 6194    	barf(C_OUT_OF_BOUNDS_ERROR, "u16vector-set!", v, i);
 6195
 6196    if(x & C_FIXNUM_BIT) {
 6197      if (!(x & C_INT_SIGN_BIT) && C_ilen(C_unfix(x)) <= 16) n = C_unfix(x);
 6198      else barf(C_BAD_ARGUMENT_TYPE_NUMERIC_RANGE_ERROR, "u16vector-set!", x);
 6199    }
 6200    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "u16vector-set!", x);
 6201  }
 6202  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "u16vector-set!", i);
 6203
 6204  ((unsigned short *)C_data_pointer(C_block_item(v, 1)))[j] = n;
 6205  return C_SCHEME_UNDEFINED;
 6206}
 6207
 6208C_regparm C_word C_i_s16vector_set(C_word v, C_word i, C_word x)
 6209{
 6210  int j;
 6211  C_word n;
 6212
 6213  if(!C_truep(C_i_s16vectorp(v)))
 6214    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s16vector-set!", v);
 6215
 6216  if(i & C_FIXNUM_BIT) {
 6217    j = C_unfix(i);
 6218
 6219    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 1))
 6220    	barf(C_OUT_OF_BOUNDS_ERROR, "u16vector-set!", v, i);
 6221
 6222    if(x & C_FIXNUM_BIT) {
 6223      if (C_unfix(C_i_fixnum_length(x)) <= 16) n = C_unfix(x);
 6224      else barf(C_BAD_ARGUMENT_TYPE_NUMERIC_RANGE_ERROR, "s16vector-set!", x);
 6225    }
 6226    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s16vector-set!", x);
 6227  }
 6228  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s16vector-set!", i);
 6229
 6230  ((short *)C_data_pointer(C_block_item(v, 1)))[j] = n;
 6231  return C_SCHEME_UNDEFINED;
 6232}
 6233
 6234C_regparm C_word C_i_u32vector_set(C_word v, C_word i, C_word x)
 6235{
 6236  int j;
 6237  C_u32 n;
 6238
 6239  if(!C_truep(C_i_u32vectorp(v)))
 6240    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u32vector-set!", v);
 6241
 6242  if(i & C_FIXNUM_BIT) {
 6243    j = C_unfix(i);
 6244
 6245    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 2))
 6246    	barf(C_OUT_OF_BOUNDS_ERROR, "u32vector-set!", v, i);
 6247
 6248    if(C_truep(C_i_exact_integerp(x))) {
 6249      if (C_unfix(C_i_integer_length(x)) <= 32) n = C_num_to_unsigned_int(x);
 6250      else barf(C_BAD_ARGUMENT_TYPE_NUMERIC_RANGE_ERROR, "u32vector-set!", x);
 6251    }
 6252    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "u32vector-set!", x);
 6253  }
 6254  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "u32vector-set!", i);
 6255
 6256  ((C_u32 *)C_data_pointer(C_block_item(v, 1)))[j] = n;
 6257  return C_SCHEME_UNDEFINED;
 6258}
 6259
 6260C_regparm C_word C_i_s32vector_set(C_word v, C_word i, C_word x)
 6261{
 6262  int j;
 6263  C_s32 n;
 6264
 6265  if(!C_truep(C_i_s32vectorp(v)))
 6266    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s32vector-set!", v);
 6267
 6268  if(i & C_FIXNUM_BIT) {
 6269    j = C_unfix(i);
 6270
 6271    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 2))
 6272    	barf(C_OUT_OF_BOUNDS_ERROR, "s32vector-set!", v, i);
 6273
 6274    if(C_truep(C_i_exact_integerp(x))) {
 6275      if (C_unfix(C_i_integer_length(x)) <= 32) n = C_num_to_int(x);
 6276      else barf(C_BAD_ARGUMENT_TYPE_NUMERIC_RANGE_ERROR, "s32vector-set!", x);
 6277    }
 6278    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s32vector-set!", x);
 6279  }
 6280  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s32vector-set!", i);
 6281
 6282  ((C_s32 *)C_data_pointer(C_block_item(v, 1)))[j] = n;
 6283  return C_SCHEME_UNDEFINED;
 6284}
 6285
 6286C_regparm C_word C_i_u64vector_set(C_word v, C_word i, C_word x)
 6287{
 6288  int j;
 6289  C_u64 n;
 6290
 6291  if(!C_truep(C_i_u64vectorp(v)))
 6292    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u64vector-set!", v);
 6293
 6294  if(i & C_FIXNUM_BIT) {
 6295    j = C_unfix(i);
 6296
 6297    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 3))
 6298    	barf(C_OUT_OF_BOUNDS_ERROR, "u64vector-set!", v, i);
 6299
 6300    if(C_truep(C_i_exact_integerp(x))) {
 6301      if (C_unfix(C_i_integer_length(x)) <= 64) n = C_num_to_uint64(x);
 6302      else barf(C_BAD_ARGUMENT_TYPE_NUMERIC_RANGE_ERROR, "u64vector-set!", x);
 6303    }
 6304    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "u64vector-set!", x);
 6305  }
 6306  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "u64vector-set!", i);
 6307
 6308  ((C_u64 *)C_data_pointer(C_block_item(v, 1)))[j] = n;
 6309  return C_SCHEME_UNDEFINED;
 6310}
 6311
 6312C_regparm C_word C_i_s64vector_set(C_word v, C_word i, C_word x)
 6313{
 6314  int j;
 6315  C_s64 n;
 6316
 6317  if(!C_truep(C_i_s64vectorp(v)))
 6318    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s64vector-set!", v);
 6319
 6320  if(i & C_FIXNUM_BIT) {
 6321    j = C_unfix(i);
 6322
 6323    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 3))
 6324    	barf(C_OUT_OF_BOUNDS_ERROR, "s64vector-set!", v, i);
 6325
 6326    if(C_truep(C_i_exact_integerp(x))) {
 6327      if (C_unfix(C_i_integer_length(x)) <= 64) n = C_num_to_int64(x);
 6328      else barf(C_BAD_ARGUMENT_TYPE_NUMERIC_RANGE_ERROR, "s64vector-set!", x);
 6329    }
 6330    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s64vector-set!", x);
 6331  }
 6332  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s64vector-set!", i);
 6333
 6334  ((C_s64 *)C_data_pointer(C_block_item(v, 1)))[j] = n;
 6335  return C_SCHEME_UNDEFINED;
 6336}
 6337
 6338C_regparm C_word C_i_f32vector_set(C_word v, C_word i, C_word x)
 6339{
 6340  int j;
 6341  double f;
 6342
 6343  if(!C_truep(C_i_f32vectorp(v)))
 6344    barf(C_BAD_ARGUMENT_TYPE_ERROR, "f32vector-set!", v);
 6345
 6346  if(i & C_FIXNUM_BIT) {
 6347    j = C_unfix(i);
 6348
 6349    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 2))
 6350    	barf(C_OUT_OF_BOUNDS_ERROR, "f32vector-set!", v, i);
 6351
 6352    if(C_truep(C_i_flonump(x))) f = C_flonum_magnitude(x);
 6353    else if(x & C_FIXNUM_BIT) f = C_unfix(x);
 6354    else if (C_truep(C_i_bignump(x))) f = C_bignum_to_double(x);
 6355    else barf(C_BAD_ARGUMENT_TYPE_NUMERIC_RANGE_ERROR, "f32vector-set!", x);
 6356  }
 6357  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "f32vector-set!", i);
 6358
 6359  ((float *)C_data_pointer(C_block_item(v, 1)))[j] = (float)f;
 6360  return C_SCHEME_UNDEFINED;
 6361}
 6362
 6363C_regparm C_word C_i_f64vector_set(C_word v, C_word i, C_word x)
 6364{
 6365  int j;
 6366  double f;
 6367
 6368  if(!C_truep(C_i_f64vectorp(v)))
 6369    barf(C_BAD_ARGUMENT_TYPE_ERROR, "f64vector-set!", v);
 6370
 6371  if(i & C_FIXNUM_BIT) {
 6372    j = C_unfix(i);
 6373
 6374    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 3))
 6375    	barf(C_OUT_OF_BOUNDS_ERROR, "f64vector-set!", v, i);
 6376
 6377    if(C_truep(C_i_flonump(x))) f = C_flonum_magnitude(x);
 6378    else if(x & C_FIXNUM_BIT) f = C_unfix(x);
 6379    else if (C_truep(C_i_bignump(x))) f = C_bignum_to_double(x);
 6380    else barf(C_BAD_ARGUMENT_TYPE_NUMERIC_RANGE_ERROR, "f64vector-set!", x);
 6381
 6382  }
 6383  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "f64vector-set!", i);
 6384
 6385  ((double *)C_data_pointer(C_block_item(v, 1)))[j] = f;
 6386  return C_SCHEME_UNDEFINED;
 6387}
 6388
 6389
 6390/* This needs at most C_SIZEOF_FIX_BIGNUM + max(C_SIZEOF_RATNUM, C_SIZEOF_CPLXNUM) so 7 words */
 6391C_regparm C_word
 6392C_s_a_i_abs(C_word **ptr, C_word n, C_word x)
 6393{
 6394  if (x & C_FIXNUM_BIT) {
 6395    return C_a_i_fixnum_abs(ptr, 1, x);
 6396  } else if (C_immediatep(x)) {
 6397    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "abs", x);
 6398  } else if (C_block_header(x) == C_FLONUM_TAG) {
 6399    return C_a_i_flonum_abs(ptr, 1, x);
 6400  } else if (C_truep(C_bignump(x))) {
 6401    return C_s_a_u_i_integer_abs(ptr, 1, x);
 6402  } else if (C_block_header(x) == C_RATNUM_TAG) {
 6403    return C_ratnum(ptr, C_s_a_u_i_integer_abs(ptr, 1, C_u_i_ratnum_num(x)),
 6404                    C_u_i_ratnum_denom(x));
 6405  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 6406    barf(C_BAD_ARGUMENT_TYPE_COMPLEX_ABS, "abs", x);
 6407  } else {
 6408    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "abs", x);
 6409  }
 6410}
 6411
 6412void C_ccall C_signum(C_word c, C_word *av)
 6413{
 6414  C_word k = av[ 1 ], x, y;
 6415
 6416  if (c != 3) C_bad_argc_2(c, 3, av[ 0 ]);
 6417
 6418  x = av[ 2 ];
 6419  y = av[ 3 ];
 6420
 6421  if (x & C_FIXNUM_BIT) {
 6422    C_kontinue(k, C_i_fixnum_signum(x));
 6423  } else if (C_immediatep(x)) {
 6424    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "signum", x);
 6425  } else if (C_block_header(x) == C_FLONUM_TAG) {
 6426    C_word *a = C_alloc(C_SIZEOF_FLONUM);
 6427    C_kontinue(k, C_a_u_i_flonum_signum(&a, 1, x));
 6428  } else if (C_truep(C_bignump(x))) {
 6429    C_kontinue(k, C_bignum_negativep(x) ? C_fix(-1) : C_fix(1));
 6430  } else {
 6431    try_extended_number("##sys#extended-signum", 2, k, x);
 6432  }
 6433}
 6434
 6435
 6436/* The maximum this can allocate is a cplxnum which consists of two
 6437 * ratnums that consist of 2 fix bignums each.  So that's
 6438 * C_SIZEOF_CPLXNUM + C_SIZEOF_RATNUM * 2 + C_SIZEOF_FIX_BIGNUM * 4 = 29 words!
 6439 */
 6440C_regparm C_word
 6441C_s_a_i_negate(C_word **ptr, C_word n, C_word x)
 6442{
 6443  if (x & C_FIXNUM_BIT) {
 6444    return C_a_i_fixnum_negate(ptr, 1, x);
 6445  } else if (C_immediatep(x)) {
 6446    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", x);
 6447  } else if (C_block_header(x) == C_FLONUM_TAG) {
 6448    return C_a_i_flonum_negate(ptr, 1, x);
 6449  } else if (C_truep(C_bignump(x))) {
 6450    return C_s_a_u_i_integer_negate(ptr, 1, x);
 6451  } else if (C_block_header(x) == C_RATNUM_TAG) {
 6452    return C_ratnum(ptr, C_s_a_u_i_integer_negate(ptr, 1, C_u_i_ratnum_num(x)),
 6453                    C_u_i_ratnum_denom(x));
 6454  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 6455    return C_cplxnum(ptr, C_s_a_i_negate(ptr, 1, C_u_i_cplxnum_real(x)),
 6456                     C_s_a_i_negate(ptr, 1, C_u_i_cplxnum_imag(x)));
 6457  } else {
 6458    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", x);
 6459  }
 6460}
 6461
 6462/* Copy all the digits from source to target, obliterating what was
 6463 * there.  If target is larger than source, the most significant
 6464 * digits will remain untouched.
 6465 */
 6466inline static void bignum_digits_destructive_copy(C_word target, C_word source)
 6467{
 6468  C_memcpy(C_bignum_digits(target), C_bignum_digits(source),
 6469           C_wordstobytes(C_bignum_size(source)));
 6470}
 6471
 6472C_regparm C_word
 6473C_s_a_u_i_integer_negate(C_word **ptr, C_word n, C_word x)
 6474{
 6475  if (x & C_FIXNUM_BIT) {
 6476    return C_a_i_fixnum_negate(ptr, 1, x);
 6477  } else {
 6478    if (C_bignum_negated_fitsinfixnump(x)) {
 6479      return C_fix(C_MOST_NEGATIVE_FIXNUM);
 6480    } else {
 6481      C_word res, negp = C_mk_nbool(C_bignum_negativep(x)),
 6482             size = C_fix(C_bignum_size(x));
 6483      res = C_allocate_scratch_bignum(ptr, size, negp, C_SCHEME_FALSE);
 6484      bignum_digits_destructive_copy(res, x);
 6485      return C_bignum_simplify(res);
 6486    }
 6487  }
 6488}
 6489
 6490
 6491/* Faster version that ignores sign */
 6492inline static int integer_length_abs(C_word x)
 6493{
 6494  if (x & C_FIXNUM_BIT) {
 6495    return C_ilen(C_wabs(C_unfix(x)));
 6496  } else {
 6497    C_uword result = (C_bignum_size(x) - 1) * C_BIGNUM_DIGIT_LENGTH,
 6498            *last_digit = C_bignum_digits(x) + C_bignum_size(x) - 1,
 6499            last_digit_length = C_ilen(*last_digit);
 6500    return result + last_digit_length;
 6501  }
 6502}
 6503
 6504C_regparm C_word C_i_integer_length(C_word x)
 6505{
 6506  if (x & C_FIXNUM_BIT) {
 6507    return C_i_fixnum_length(x);
 6508  } else if (C_truep(C_i_bignump(x))) {
 6509    C_uword result = (C_bignum_size(x) - 1) * C_BIGNUM_DIGIT_LENGTH,
 6510            *last_digit = C_bignum_digits(x) + C_bignum_size(x) - 1,
 6511            last_digit_length = C_ilen(*last_digit);
 6512
 6513    /* If *only* the highest bit is set, negating will give one less bit */
 6514    if (C_bignum_negativep(x) &&
 6515        *last_digit == ((C_uword)1 << (last_digit_length-1))) {
 6516      C_uword *startx = C_bignum_digits(x);
 6517      while (startx < last_digit && *startx == 0) ++startx;
 6518      if (startx == last_digit) result--;
 6519    }
 6520    return C_fix(result + last_digit_length);
 6521  } else {
 6522    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "integer-length", x);
 6523  }
 6524}
 6525
 6526/* This is currently only used by Karatsuba multiplication and
 6527 * Burnikel-Ziegler division. */
 6528static C_regparm C_word
 6529bignum_extract_digits(C_word **ptr, C_word n, C_word x, C_word start, C_word end)
 6530{
 6531  if (x & C_FIXNUM_BIT) { /* Needed? */
 6532    if (C_unfix(start) == 0 && (end == C_SCHEME_FALSE || C_unfix(end) > 0))
 6533      return x;
 6534    else
 6535      return C_fix(0);
 6536  } else {
 6537    C_word negp, size;
 6538
 6539    negp = C_mk_bool(C_bignum_negativep(x)); /* Always false */
 6540
 6541    start = C_unfix(start);
 6542    /* We might get passed larger values than actually fits; pad w/ zeroes */
 6543    if (end == C_SCHEME_FALSE) end = C_bignum_size(x);
 6544    else end = nmin(C_unfix(end), C_bignum_size(x));
 6545    assert(start >= 0);
 6546
 6547    size = end - start;
 6548
 6549    if (size == 0 || start >= C_bignum_size(x)) {
 6550      return C_fix(0);
 6551    } else {
 6552      C_uword res, *res_digits, *x_digits;
 6553      res = C_allocate_scratch_bignum(ptr, C_fix(size), negp, C_SCHEME_FALSE);
 6554      res_digits = C_bignum_digits(res);
 6555      x_digits = C_bignum_digits(x);
 6556      /* Can't use bignum_digits_destructive_copy because that assumes
 6557       * target is at least as big as source.
 6558       */
 6559      C_memcpy(res_digits, x_digits + start, C_wordstobytes(end - start));
 6560      return C_bignum_simplify(res);
 6561    }
 6562  }
 6563}
 6564
 6565/* This returns a tmp bignum negated copy of X (must be freed!) when
 6566 * the number is negative, or #f if it doesn't need to be negated.
 6567 * The size can be larger or smaller than X (it may be 1-padded).
 6568 */
 6569inline static C_word maybe_negate_bignum_for_bitwise_op(C_word x, C_word size)
 6570{
 6571  C_word nx = C_SCHEME_FALSE, xsize;
 6572  if (C_bignum_negativep(x)) {
 6573    nx = allocate_tmp_bignum(C_fix(size), C_SCHEME_FALSE, C_SCHEME_FALSE);
 6574    xsize = C_bignum_size(x);
 6575    /* Copy up until requested size, and init any remaining upper digits */
 6576    C_memcpy(C_bignum_digits(nx), C_bignum_digits(x),
 6577             C_wordstobytes(nmin(size, xsize)));
 6578    if (size > xsize)
 6579      C_memset(C_bignum_digits(nx)+xsize, 0, C_wordstobytes(size-xsize));
 6580    bignum_digits_destructive_negate(nx);
 6581  }
 6582  return nx;
 6583}
 6584
 6585/* DEPRECATED */
 6586C_regparm C_word C_i_bit_to_bool(C_word n, C_word i)
 6587{
 6588  if (!C_truep(C_i_exact_integerp(n))) {
 6589    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bit->boolean", n);
 6590  } else if (!(i & C_FIXNUM_BIT)) {
 6591    if (!C_immediatep(i) && C_truep(C_bignump(i)) && !C_bignum_negativep(i)) {
 6592      return C_i_integer_negativep(n); /* A bit silly, but strictly correct */
 6593    } else {
 6594      barf(C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR, "bit->boolean", i);
 6595    }
 6596  } else if (i & C_INT_SIGN_BIT) {
 6597    barf(C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR, "bit->boolean", i);
 6598  } else {
 6599    i = C_unfix(i);
 6600    if (n & C_FIXNUM_BIT) {
 6601      if (i >= C_WORD_SIZE) return C_mk_bool(n & C_INT_SIGN_BIT);
 6602      else return C_mk_bool((C_unfix(n) & ((C_word)1 << i)) != 0);
 6603    } else {
 6604      C_word nn, d;
 6605      d = i / C_BIGNUM_DIGIT_LENGTH;
 6606      if (d >= C_bignum_size(n)) return C_mk_bool(C_bignum_negativep(n));
 6607
 6608      /* TODO: this isn't necessary, is it? */
 6609      if (C_truep(nn = maybe_negate_bignum_for_bitwise_op(n, d))) n = nn;
 6610
 6611      i %= C_BIGNUM_DIGIT_LENGTH;
 6612      d = C_mk_bool((C_bignum_digits(n)[d] & (C_uword)1 << i) != 0);
 6613      if (C_truep(nn)) free_tmp_bignum(nn);
 6614      return d;
 6615    }
 6616  }
 6617}
 6618
 6619C_regparm C_word
 6620C_s_a_i_bitwise_and(C_word **ptr, C_word n, C_word x, C_word y)
 6621{
 6622  if ((x & y) & C_FIXNUM_BIT) {
 6623    return C_u_fixnum_and(x, y);
 6624  } else if (!C_truep(C_i_exact_integerp(x))) {
 6625    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-and", x);
 6626  } else if (!C_truep(C_i_exact_integerp(y))) {
 6627    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-and", y);
 6628  } else {
 6629    C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, negp, size, res, nx, ny;
 6630    C_uword *scanr, *endr, *scans1, *ends1, *scans2;
 6631
 6632    if (x & C_FIXNUM_BIT) x = C_a_u_i_fix_to_big(&a, x);
 6633    if (y & C_FIXNUM_BIT) y = C_a_u_i_fix_to_big(&a, y);
 6634
 6635    negp = C_mk_bool(C_bignum_negativep(x) && C_bignum_negativep(y));
 6636    /* Allow negative 1-bits to propagate */
 6637    if (C_bignum_negativep(x) || C_bignum_negativep(y))
 6638      size = nmax(C_bignum_size(x), C_bignum_size(y)) + 1;
 6639    else
 6640      size = nmin(C_bignum_size(x), C_bignum_size(y));
 6641
 6642    res = C_allocate_scratch_bignum(ptr, C_fix(size), negp, C_SCHEME_FALSE);
 6643    scanr = C_bignum_digits(res);
 6644    endr = scanr + C_bignum_size(res);
 6645
 6646    if (C_truep(nx = maybe_negate_bignum_for_bitwise_op(x, size))) x = nx;
 6647    if (C_truep(ny = maybe_negate_bignum_for_bitwise_op(y, size))) y = ny;
 6648
 6649    if (C_bignum_size(x) < C_bignum_size(y)) {
 6650      scans1 = C_bignum_digits(x); ends1 = scans1 + C_bignum_size(x);
 6651      scans2 = C_bignum_digits(y);
 6652    } else {
 6653      scans1 = C_bignum_digits(y); ends1 = scans1 + C_bignum_size(y);
 6654      scans2 = C_bignum_digits(x);
 6655    }
 6656
 6657    while (scans1 < ends1) *scanr++ = *scans1++ & *scans2++;
 6658    C_memset(scanr, 0, C_wordstobytes(endr - scanr));
 6659
 6660    if (C_truep(nx)) free_tmp_bignum(nx);
 6661    if (C_truep(ny)) free_tmp_bignum(ny);
 6662    if (C_bignum_negativep(res)) bignum_digits_destructive_negate(res);
 6663
 6664    return C_bignum_simplify(res);
 6665  }
 6666}
 6667
 6668void C_ccall C_bitwise_and(C_word c, C_word *av)
 6669{
 6670  /* C_word closure = av[ 0 ]; */
 6671  C_word k = av[ 1 ];
 6672  C_word next_val, result, prev_result;
 6673  C_word ab[2][C_SIZEOF_BIGNUM_WRAPPER], *a;
 6674
 6675  c -= 2;
 6676  av += 2;
 6677
 6678  if (c == 0) C_kontinue(k, C_fix(-1));
 6679
 6680  prev_result = result = *(av++);
 6681
 6682  if (c-- == 1 && !C_truep(C_i_exact_integerp(result)))
 6683    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-and", result);
 6684
 6685  while (c--) {
 6686    next_val = *(av++);
 6687    a = ab[c&1]; /* One may hold last iteration result, the other is unused */
 6688    result = C_s_a_i_bitwise_and(&a, 2, result, next_val);
 6689    result = move_buffer_object(&a, ab[(c+1)&1], result);
 6690    clear_buffer_object(ab[(c+1)&1], prev_result);
 6691    prev_result = result;
 6692  }
 6693
 6694  C_kontinue(k, result);
 6695}
 6696
 6697C_regparm C_word
 6698C_s_a_i_bitwise_ior(C_word **ptr, C_word n, C_word x, C_word y)
 6699{
 6700  if ((x & y) & C_FIXNUM_BIT) {
 6701    return C_u_fixnum_or(x, y);
 6702  } else if (!C_truep(C_i_exact_integerp(x))) {
 6703    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-ior", x);
 6704  } else if (!C_truep(C_i_exact_integerp(y))) {
 6705    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-ior", y);
 6706  } else {
 6707    C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, negp, size, res, nx, ny;
 6708    C_uword *scanr, *endr, *scans1, *ends1, *scans2, *ends2;
 6709
 6710    if (x & C_FIXNUM_BIT) x = C_a_u_i_fix_to_big(&a, x);
 6711    if (y & C_FIXNUM_BIT) y = C_a_u_i_fix_to_big(&a, y);
 6712
 6713    negp = C_mk_bool(C_bignum_negativep(x) || C_bignum_negativep(y));
 6714    size = nmax(C_bignum_size(x), C_bignum_size(y)) + 1;
 6715    res = C_allocate_scratch_bignum(ptr, C_fix(size), negp, C_SCHEME_FALSE);
 6716    scanr = C_bignum_digits(res);
 6717    endr = scanr + C_bignum_size(res);
 6718
 6719    if (C_truep(nx = maybe_negate_bignum_for_bitwise_op(x, size))) x = nx;
 6720    if (C_truep(ny = maybe_negate_bignum_for_bitwise_op(y, size))) y = ny;
 6721
 6722    if (C_bignum_size(x) < C_bignum_size(y)) {
 6723      scans1 = C_bignum_digits(x); ends1 = scans1 + C_bignum_size(x);
 6724      scans2 = C_bignum_digits(y); ends2 = scans2 + C_bignum_size(y);
 6725    } else {
 6726      scans1 = C_bignum_digits(y); ends1 = scans1 + C_bignum_size(y);
 6727      scans2 = C_bignum_digits(x); ends2 = scans2 + C_bignum_size(x);
 6728    }
 6729
 6730    while (scans1 < ends1) *scanr++ = *scans1++ | *scans2++;
 6731    while (scans2 < ends2) *scanr++ = *scans2++;
 6732    if (scanr < endr) *scanr++ = 0; /* Only done when result is positive */
 6733    assert(scanr == endr);
 6734
 6735    if (C_truep(nx)) free_tmp_bignum(nx);
 6736    if (C_truep(ny)) free_tmp_bignum(ny);
 6737    if (C_bignum_negativep(res)) bignum_digits_destructive_negate(res);
 6738
 6739    return C_bignum_simplify(res);
 6740  }
 6741}
 6742
 6743void C_ccall C_bitwise_ior(C_word c, C_word *av)
 6744{
 6745  /* C_word closure = av[ 0 ]; */
 6746  C_word k = av[ 1 ];
 6747  C_word next_val, result, prev_result;
 6748  C_word ab[2][C_SIZEOF_BIGNUM_WRAPPER], *a;
 6749
 6750  c -= 2;
 6751  av += 2;
 6752
 6753  if (c == 0) C_kontinue(k, C_fix(0));
 6754
 6755  prev_result = result = *(av++);
 6756
 6757  if (c-- == 1 && !C_truep(C_i_exact_integerp(result)))
 6758    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-ior", result);
 6759
 6760  while (c--) {
 6761    next_val = *(av++);
 6762    a = ab[c&1]; /* One may hold prev iteration result, the other is unused */
 6763    result = C_s_a_i_bitwise_ior(&a, 2, result, next_val);
 6764    result = move_buffer_object(&a, ab[(c+1)&1], result);
 6765    clear_buffer_object(ab[(c+1)&1], prev_result);
 6766    prev_result = result;
 6767  }
 6768
 6769  C_kontinue(k, result);
 6770}
 6771
 6772C_regparm C_word
 6773C_s_a_i_bitwise_xor(C_word **ptr, C_word n, C_word x, C_word y)
 6774{
 6775  if ((x & y) & C_FIXNUM_BIT) {
 6776    return C_fixnum_xor(x, y);
 6777  } else if (!C_truep(C_i_exact_integerp(x))) {
 6778    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-xor", x);
 6779  } else if (!C_truep(C_i_exact_integerp(y))) {
 6780    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-xor", y);
 6781  } else {
 6782    C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, negp, size, res, nx, ny;
 6783    C_uword *scanr, *endr, *scans1, *ends1, *scans2, *ends2;
 6784
 6785    if (x & C_FIXNUM_BIT) x = C_a_u_i_fix_to_big(&a, x);
 6786    if (y & C_FIXNUM_BIT) y = C_a_u_i_fix_to_big(&a, y);
 6787
 6788    size = nmax(C_bignum_size(x), C_bignum_size(y)) + 1;
 6789    negp = C_mk_bool(C_bignum_negativep(x) != C_bignum_negativep(y));
 6790    res = C_allocate_scratch_bignum(ptr, C_fix(size), negp, C_SCHEME_FALSE);
 6791    scanr = C_bignum_digits(res);
 6792    endr = scanr + C_bignum_size(res);
 6793
 6794    if (C_truep(nx = maybe_negate_bignum_for_bitwise_op(x, size))) x = nx;
 6795    if (C_truep(ny = maybe_negate_bignum_for_bitwise_op(y, size))) y = ny;
 6796
 6797    if (C_bignum_size(x) < C_bignum_size(y)) {
 6798      scans1 = C_bignum_digits(x); ends1 = scans1 + C_bignum_size(x);
 6799      scans2 = C_bignum_digits(y); ends2 = scans2 + C_bignum_size(y);
 6800    } else {
 6801      scans1 = C_bignum_digits(y); ends1 = scans1 + C_bignum_size(y);
 6802      scans2 = C_bignum_digits(x); ends2 = scans2 + C_bignum_size(x);
 6803    }
 6804
 6805    while (scans1 < ends1) *scanr++ = *scans1++ ^ *scans2++;
 6806    while (scans2 < ends2) *scanr++ = *scans2++;
 6807    if (scanr < endr) *scanr++ = 0; /* Only done when result is positive */
 6808    assert(scanr == endr);
 6809
 6810    if (C_truep(nx)) free_tmp_bignum(nx);
 6811    if (C_truep(ny)) free_tmp_bignum(ny);
 6812    if (C_bignum_negativep(res)) bignum_digits_destructive_negate(res);
 6813
 6814    return C_bignum_simplify(res);
 6815  }
 6816}
 6817
 6818void C_ccall C_bitwise_xor(C_word c, C_word *av)
 6819{
 6820  /* C_word closure = av[ 0 ]; */
 6821  C_word k = av[ 1 ];
 6822  C_word next_val, result, prev_result;
 6823  C_word ab[2][C_SIZEOF_BIGNUM_WRAPPER], *a;
 6824
 6825  c -= 2;
 6826  av += 2;
 6827
 6828  if (c == 0) C_kontinue(k, C_fix(0));
 6829
 6830  prev_result = result = *(av++);
 6831
 6832  if (c-- == 1 && !C_truep(C_i_exact_integerp(result)))
 6833    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-xor", result);
 6834
 6835  while (c--) {
 6836    next_val = *(av++);
 6837    a = ab[c&1]; /* One may hold prev iteration result, the other is unused */
 6838    result = C_s_a_i_bitwise_xor(&a, 2, result, next_val);
 6839    result = move_buffer_object(&a, ab[(c+1)&1], result);
 6840    clear_buffer_object(ab[(c+1)&1], prev_result);
 6841    prev_result = result;
 6842  }
 6843
 6844  C_kontinue(k, result);
 6845}
 6846
 6847C_regparm C_word
 6848C_s_a_i_bitwise_not(C_word **ptr, C_word n, C_word x)
 6849{
 6850  if (!C_truep(C_i_exact_integerp(x))) {
 6851    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-not", x);
 6852  } else {
 6853    return C_s_a_u_i_integer_minus(ptr, 2, C_fix(-1), x);
 6854  }
 6855}
 6856
 6857C_regparm C_word
 6858C_s_a_i_arithmetic_shift(C_word **ptr, C_word n, C_word x, C_word y)
 6859{
 6860  C_word ab[C_SIZEOF_FIX_BIGNUM], *a = ab, size, negp, res,
 6861         digit_offset, bit_offset;
 6862
 6863  if (!(y & C_FIXNUM_BIT))
 6864    barf(C_BAD_ARGUMENT_TYPE_NO_FIXNUM_ERROR, "arithmetic-shift", y);
 6865
 6866  y = C_unfix(y);
 6867  if (y == 0 || x == C_fix(0)) { /* Done (no shift) */
 6868    return x;
 6869  } else if (x & C_FIXNUM_BIT) {
 6870    if (y < 0) {
 6871      /* Don't shift more than a word's length (that's undefined in C!) */
 6872      if (-y < C_WORD_SIZE) {
 6873        return C_fix(C_unfix(x) >> -y);
 6874      } else {
 6875        return (x < 0) ? C_fix(-1) : C_fix(0);
 6876      }
 6877    } else if (y > 0 && y < C_WORD_SIZE-2 &&
 6878               /* After shifting, the length still fits a fixnum */
 6879               (C_ilen(C_unfix(x)) + y) < C_WORD_SIZE-2) {
 6880      return C_fix((C_uword)C_unfix(x) << y);
 6881    } else {
 6882      x = C_a_u_i_fix_to_big(&a, x);
 6883    }
 6884  } else if (!C_truep(C_i_bignump(x))) {
 6885    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "arithmetic-shift", x);
 6886  }
 6887
 6888  negp = C_mk_bool(C_bignum_negativep(x));
 6889
 6890  if (y > 0) {                  /* Shift left */
 6891    C_uword *startr, *startx, *endx, *endr;
 6892
 6893    digit_offset = y / C_BIGNUM_DIGIT_LENGTH;
 6894    bit_offset =   y % C_BIGNUM_DIGIT_LENGTH;
 6895
 6896    size = C_fix(C_bignum_size(x) + digit_offset + 1);
 6897    res = C_allocate_scratch_bignum(ptr, size, negp, C_SCHEME_FALSE);
 6898
 6899    startr = C_bignum_digits(res);
 6900    endr = startr + C_bignum_size(res);
 6901
 6902    startx = C_bignum_digits(x);
 6903    endx = startx + C_bignum_size(x);
 6904
 6905    /* Initialize only the lower digits we're skipping and the MSD */
 6906    C_memset(startr, 0, C_wordstobytes(digit_offset));
 6907    *(endr-1) = 0;
 6908    startr += digit_offset;
 6909    /* Can't use bignum_digits_destructive_copy because it assumes
 6910     * we want to copy from the start.
 6911     */
 6912    C_memcpy(startr, startx, C_wordstobytes(endx-startx));
 6913    if(bit_offset > 0)
 6914      bignum_digits_destructive_shift_left(startr, endr, bit_offset);
 6915
 6916    return C_bignum_simplify(res);
 6917  } else if (-y >= C_bignum_size(x) * (C_word)C_BIGNUM_DIGIT_LENGTH) {
 6918    /* All bits are shifted out, just return 0 or -1 */
 6919    return C_truep(negp) ? C_fix(-1) : C_fix(0);
 6920  } else {                      /* Shift right */
 6921    C_uword *startr, *startx, *endr;
 6922    C_word nx;
 6923
 6924    digit_offset = -y / C_BIGNUM_DIGIT_LENGTH;
 6925    bit_offset =   -y % C_BIGNUM_DIGIT_LENGTH;
 6926
 6927    size = C_fix(C_bignum_size(x) - digit_offset);
 6928    res = C_allocate_scratch_bignum(ptr, size, negp, C_SCHEME_FALSE);
 6929
 6930    startr = C_bignum_digits(res);
 6931    endr = startr + C_bignum_size(res);
 6932
 6933    size = C_bignum_size(x) + 1;
 6934    if (C_truep(nx = maybe_negate_bignum_for_bitwise_op(x, size))) {
 6935      startx = C_bignum_digits(nx) + digit_offset;
 6936    } else {
 6937      startx = C_bignum_digits(x) + digit_offset;
 6938    }
 6939    /* Can't use bignum_digits_destructive_copy because that assumes
 6940     * target is at least as big as source.
 6941     */
 6942    C_memcpy(startr, startx, C_wordstobytes(endr-startr));
 6943    if(bit_offset > 0)
 6944      bignum_digits_destructive_shift_right(startr,endr,bit_offset,C_truep(nx));
 6945
 6946    if (C_truep(nx)) {
 6947      free_tmp_bignum(nx);
 6948      bignum_digits_destructive_negate(res);
 6949    }
 6950    return C_bignum_simplify(res);
 6951  }
 6952}
 6953
 6954
 6955C_regparm C_word C_a_i_exp(C_word **a, int c, C_word n)
 6956{
 6957  double f;
 6958
 6959  C_check_real(n, "exp", f);
 6960  return C_flonum(a, C_exp(f));
 6961}
 6962
 6963
 6964C_regparm C_word C_a_i_log(C_word **a, int c, C_word n)
 6965{
 6966  double f;
 6967
 6968  C_check_real(n, "log", f);
 6969  return C_flonum(a, C_log(f));
 6970}
 6971
 6972
 6973C_regparm C_word C_a_i_sin(C_word **a, int c, C_word n)
 6974{
 6975  double f;
 6976
 6977  C_check_real(n, "sin", f);
 6978  return C_flonum(a, C_sin(f));
 6979}
 6980
 6981
 6982C_regparm C_word C_a_i_cos(C_word **a, int c, C_word n)
 6983{
 6984  double f;
 6985
 6986  C_check_real(n, "cos", f);
 6987  return C_flonum(a, C_cos(f));
 6988}
 6989
 6990
 6991C_regparm C_word C_a_i_tan(C_word **a, int c, C_word n)
 6992{
 6993  double f;
 6994
 6995  C_check_real(n, "tan", f);
 6996  return C_flonum(a, C_tan(f));
 6997}
 6998
 6999
 7000C_regparm C_word C_a_i_asin(C_word **a, int c, C_word n)
 7001{
 7002  double f;
 7003
 7004  C_check_real(n, "asin", f);
 7005  return C_flonum(a, C_asin(f));
 7006}
 7007
 7008
 7009C_regparm C_word C_a_i_acos(C_word **a, int c, C_word n)
 7010{
 7011  double f;
 7012
 7013  C_check_real(n, "acos", f);
 7014  return C_flonum(a, C_acos(f));
 7015}
 7016
 7017
 7018C_regparm C_word C_a_i_atan(C_word **a, int c, C_word n)
 7019{
 7020  double f;
 7021
 7022  C_check_real(n, "atan", f);
 7023  return C_flonum(a, C_atan(f));
 7024}
 7025
 7026
 7027C_regparm C_word C_a_i_atan2(C_word **a, int c, C_word n1, C_word n2)
 7028{
 7029  double f1, f2;
 7030
 7031  C_check_real(n1, "atan", f1);
 7032  C_check_real(n2, "atan", f2);
 7033  return C_flonum(a, C_atan2(f1, f2));
 7034}
 7035
 7036
 7037C_regparm C_word C_a_i_sinh(C_word **a, int c, C_word n)
 7038{
 7039  double f;
 7040
 7041  C_check_real(n, "sinh", f);
 7042  return C_flonum(a, C_sinh(f));
 7043}
 7044
 7045
 7046C_regparm C_word C_a_i_cosh(C_word **a, int c, C_word n)
 7047{
 7048  double f;
 7049
 7050  C_check_real(n, "cosh", f);
 7051  return C_flonum(a, C_cosh(f));
 7052}
 7053
 7054
 7055C_regparm C_word C_a_i_tanh(C_word **a, int c, C_word n)
 7056{
 7057  double f;
 7058
 7059  C_check_real(n, "tanh", f);
 7060  return C_flonum(a, C_tanh(f));
 7061}
 7062
 7063
 7064C_regparm C_word C_a_i_asinh(C_word **a, int c, C_word n)
 7065{
 7066  double f;
 7067
 7068  C_check_real(n, "asinh", f);
 7069  return C_flonum(a, C_asinh(f));
 7070}
 7071
 7072
 7073C_regparm C_word C_a_i_acosh(C_word **a, int c, C_word n)
 7074{
 7075  double f;
 7076
 7077  C_check_real(n, "acosh", f);
 7078  return C_flonum(a, C_acosh(f));
 7079}
 7080
 7081
 7082C_regparm C_word C_a_i_atanh(C_word **a, int c, C_word n)
 7083{
 7084  double f;
 7085
 7086  C_check_real(n, "atanh", f);
 7087  return C_flonum(a, C_atanh(f));
 7088}
 7089
 7090
 7091C_regparm C_word C_a_i_sqrt(C_word **a, int c, C_word n)
 7092{
 7093  double f;
 7094
 7095  C_check_real(n, "sqrt", f);
 7096  return C_flonum(a, C_sqrt(f));
 7097}
 7098
 7099
 7100C_regparm C_word C_i_assq(C_word x, C_word lst)
 7101{
 7102  C_word a;
 7103
 7104  while(!C_immediatep(lst) && C_header_type(lst) == C_PAIR_TYPE) {
 7105    a = C_u_i_car(lst);
 7106
 7107    if(!C_immediatep(a) && C_header_type(a) == C_PAIR_TYPE) {
 7108      if(C_u_i_car(a) == x) return a;
 7109    }
 7110    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "assq", a);
 7111
 7112    lst = C_u_i_cdr(lst);
 7113  }
 7114
 7115  if(lst!=C_SCHEME_END_OF_LIST)
 7116    barf(C_BAD_ARGUMENT_TYPE_ERROR, "assq", lst);
 7117
 7118  return C_SCHEME_FALSE;
 7119}
 7120
 7121
 7122C_regparm C_word C_i_assv(C_word x, C_word lst)
 7123{
 7124  C_word a;
 7125
 7126  while(!C_immediatep(lst) && C_header_type(lst) == C_PAIR_TYPE) {
 7127    a = C_u_i_car(lst);
 7128
 7129    if(!C_immediatep(a) && C_header_type(a) == C_PAIR_TYPE) {
 7130      if(C_truep(C_i_eqvp(C_u_i_car(a), x))) return a;
 7131    }
 7132    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "assv", a);
 7133
 7134    lst = C_u_i_cdr(lst);
 7135  }
 7136
 7137  if(lst!=C_SCHEME_END_OF_LIST)
 7138    barf(C_BAD_ARGUMENT_TYPE_ERROR, "assv", lst);
 7139
 7140  return C_SCHEME_FALSE;
 7141}
 7142
 7143
 7144C_regparm C_word C_i_assoc(C_word x, C_word lst)
 7145{
 7146  C_word a;
 7147
 7148  while(!C_immediatep(lst) && C_header_type(lst) == C_PAIR_TYPE) {
 7149    a = C_u_i_car(lst);
 7150
 7151    if(!C_immediatep(a) && C_header_type(a) == C_PAIR_TYPE) {
 7152      if(C_equalp(C_u_i_car(a), x)) return a;
 7153    }
 7154    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "assoc", a);
 7155
 7156    lst = C_u_i_cdr(lst);
 7157  }
 7158
 7159  if(lst!=C_SCHEME_END_OF_LIST)
 7160    barf(C_BAD_ARGUMENT_TYPE_ERROR, "assoc", lst);
 7161
 7162  return C_SCHEME_FALSE;
 7163}
 7164
 7165
 7166C_regparm C_word C_i_memq(C_word x, C_word lst)
 7167{
 7168  while(!C_immediatep(lst) && C_header_type(lst) == C_PAIR_TYPE) {
 7169    if(C_u_i_car(lst) == x) return lst;
 7170    else lst = C_u_i_cdr(lst);
 7171  }
 7172
 7173  if(lst!=C_SCHEME_END_OF_LIST)
 7174    barf(C_BAD_ARGUMENT_TYPE_ERROR, "memq", lst);
 7175
 7176  return C_SCHEME_FALSE;
 7177}
 7178
 7179
 7180C_regparm C_word C_u_i_memq(C_word x, C_word lst)
 7181{
 7182  while(!C_immediatep(lst)) {
 7183    if(C_u_i_car(lst) == x) return lst;
 7184    else lst = C_u_i_cdr(lst);
 7185  }
 7186
 7187  return C_SCHEME_FALSE;
 7188}
 7189
 7190
 7191C_regparm C_word C_i_memv(C_word x, C_word lst)
 7192{
 7193  while(!C_immediatep(lst) && C_header_type(lst) == C_PAIR_TYPE) {
 7194    if(C_truep(C_i_eqvp(C_u_i_car(lst), x))) return lst;
 7195    else lst = C_u_i_cdr(lst);
 7196  }
 7197
 7198  if(lst!=C_SCHEME_END_OF_LIST)
 7199    barf(C_BAD_ARGUMENT_TYPE_ERROR, "memv", lst);
 7200
 7201  return C_SCHEME_FALSE;
 7202}
 7203
 7204
 7205C_regparm C_word C_i_member(C_word x, C_word lst)
 7206{
 7207  while(!C_immediatep(lst) && C_header_type(lst) == C_PAIR_TYPE) {
 7208    if(C_equalp(C_u_i_car(lst), x)) return lst;
 7209    else lst = C_u_i_cdr(lst);
 7210  }
 7211
 7212  if(lst!=C_SCHEME_END_OF_LIST)
 7213    barf(C_BAD_ARGUMENT_TYPE_ERROR, "member", lst);
 7214
 7215  return C_SCHEME_FALSE;
 7216}
 7217
 7218
 7219/* Inline routines for extended bindings: */
 7220
 7221C_regparm C_word C_i_check_closure_2(C_word x, C_word loc)
 7222{
 7223  if(C_immediatep(x) || (C_header_bits(x) != C_CLOSURE_TYPE)) {
 7224    error_location = loc;
 7225    barf(C_BAD_ARGUMENT_TYPE_NO_CLOSURE_ERROR, NULL, x);
 7226  }
 7227
 7228  return C_SCHEME_UNDEFINED;
 7229}
 7230
 7231C_regparm C_word C_i_check_fixnum_2(C_word x, C_word loc)
 7232{
 7233  if(!(x & C_FIXNUM_BIT)) {
 7234    error_location = loc;
 7235    barf(C_BAD_ARGUMENT_TYPE_NO_FIXNUM_ERROR, NULL, x);
 7236  }
 7237
 7238  return C_SCHEME_UNDEFINED;
 7239}
 7240
 7241/* DEPRECATED */
 7242C_regparm C_word C_i_check_exact_2(C_word x, C_word loc)
 7243{
 7244  if(C_u_i_exactp(x) == C_SCHEME_FALSE) {
 7245    error_location = loc;
 7246    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_ERROR, NULL, x);
 7247  }
 7248
 7249  return C_SCHEME_UNDEFINED;
 7250}
 7251
 7252
 7253C_regparm C_word C_i_check_inexact_2(C_word x, C_word loc)
 7254{
 7255  if(C_immediatep(x) || C_block_header(x) != C_FLONUM_TAG) {
 7256    error_location = loc;
 7257    barf(C_BAD_ARGUMENT_TYPE_NO_INEXACT_ERROR, NULL, x);
 7258  }
 7259
 7260  return C_SCHEME_UNDEFINED;
 7261}
 7262
 7263
 7264C_regparm C_word C_i_check_char_2(C_word x, C_word loc)
 7265{
 7266  if((x & C_IMMEDIATE_TYPE_BITS) != C_CHARACTER_BITS) {
 7267    error_location = loc;
 7268    barf(C_BAD_ARGUMENT_TYPE_NO_CHAR_ERROR, NULL, x);
 7269  }
 7270
 7271  return C_SCHEME_UNDEFINED;
 7272}
 7273
 7274
 7275C_regparm C_word C_i_check_number_2(C_word x, C_word loc)
 7276{
 7277  if (C_i_numberp(x) == C_SCHEME_FALSE) {
 7278    error_location = loc;
 7279    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, NULL, x);
 7280  }
 7281
 7282  return C_SCHEME_UNDEFINED;
 7283}
 7284
 7285
 7286C_regparm C_word C_i_check_string_2(C_word x, C_word loc)
 7287{
 7288  if(C_immediatep(x) || C_header_bits(x) != C_STRING_TYPE) {
 7289    error_location = loc;
 7290    barf(C_BAD_ARGUMENT_TYPE_NO_STRING_ERROR, NULL, x);
 7291  }
 7292
 7293  return C_SCHEME_UNDEFINED;
 7294}
 7295
 7296
 7297C_regparm C_word C_i_check_bytevector_2(C_word x, C_word loc)
 7298{
 7299  if(C_immediatep(x) || C_header_bits(x) != C_BYTEVECTOR_TYPE) {
 7300    error_location = loc;
 7301    barf(C_BAD_ARGUMENT_TYPE_NO_BYTEVECTOR_ERROR, NULL, x);
 7302  }
 7303
 7304  return C_SCHEME_UNDEFINED;
 7305}
 7306
 7307
 7308C_regparm C_word C_i_check_vector_2(C_word x, C_word loc)
 7309{
 7310  if(C_immediatep(x) || C_header_bits(x) != C_VECTOR_TYPE) {
 7311    error_location = loc;
 7312    barf(C_BAD_ARGUMENT_TYPE_NO_VECTOR_ERROR, NULL, x);
 7313  }
 7314
 7315  return C_SCHEME_UNDEFINED;
 7316}
 7317
 7318
 7319C_regparm C_word C_i_check_structure_2(C_word x, C_word st, C_word loc)
 7320{
 7321  if(C_immediatep(x) || C_header_bits(x) != C_STRUCTURE_TYPE || C_block_item(x,0) != st) {
 7322    error_location = loc;
 7323    barf(C_BAD_ARGUMENT_TYPE_BAD_STRUCT_ERROR, NULL, x, st);
 7324  }
 7325
 7326  return C_SCHEME_UNDEFINED;
 7327}
 7328
 7329
 7330C_regparm C_word C_i_check_pair_2(C_word x, C_word loc)
 7331{
 7332  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 7333    error_location = loc;
 7334    barf(C_BAD_ARGUMENT_TYPE_NO_PAIR_ERROR, NULL, x);
 7335  }
 7336
 7337  return C_SCHEME_UNDEFINED;
 7338}
 7339
 7340
 7341C_regparm C_word C_i_check_boolean_2(C_word x, C_word loc)
 7342{
 7343  if((x & C_IMMEDIATE_TYPE_BITS) != C_BOOLEAN_BITS) {
 7344    error_location = loc;
 7345    barf(C_BAD_ARGUMENT_TYPE_NO_BOOLEAN_ERROR, NULL, x);
 7346  }
 7347
 7348  return C_SCHEME_UNDEFINED;
 7349}
 7350
 7351
 7352C_regparm C_word C_i_check_locative_2(C_word x, C_word loc)
 7353{
 7354  if(C_immediatep(x) || C_block_header(x) != C_LOCATIVE_TAG) {
 7355    error_location = loc;
 7356    barf(C_BAD_ARGUMENT_TYPE_NO_LOCATIVE_ERROR, NULL, x);
 7357  }
 7358
 7359  return C_SCHEME_UNDEFINED;
 7360}
 7361
 7362
 7363C_regparm C_word C_i_check_symbol_2(C_word x, C_word loc)
 7364{
 7365  if(!C_truep(C_i_symbolp(x))) {
 7366    error_location = loc;
 7367    barf(C_BAD_ARGUMENT_TYPE_NO_SYMBOL_ERROR, NULL, x);
 7368  }
 7369
 7370  return C_SCHEME_UNDEFINED;
 7371}
 7372
 7373
 7374C_regparm C_word C_i_check_keyword_2(C_word x, C_word loc)
 7375{
 7376  if(!C_truep(C_i_keywordp(x))) {
 7377    error_location = loc;
 7378    barf(C_BAD_ARGUMENT_TYPE_NO_KEYWORD_ERROR, NULL, x);
 7379  }
 7380
 7381  return C_SCHEME_UNDEFINED;
 7382}
 7383
 7384C_regparm C_word C_i_check_list_2(C_word x, C_word loc)
 7385{
 7386  if(x != C_SCHEME_END_OF_LIST && (C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE)) {
 7387    error_location = loc;
 7388    barf(C_BAD_ARGUMENT_TYPE_NO_LIST_ERROR, NULL, x);
 7389  }
 7390
 7391  return C_SCHEME_UNDEFINED;
 7392}
 7393
 7394
 7395C_regparm C_word C_i_check_port_2(C_word x, C_word dir, C_word open, C_word loc)
 7396{
 7397
 7398  if(C_immediatep(x) || C_header_bits(x) != C_PORT_TYPE) {
 7399    error_location = loc;
 7400    barf(C_BAD_ARGUMENT_TYPE_NO_PORT_ERROR, NULL, x);
 7401  }
 7402
 7403  if((C_block_item(x, 1) & dir) != dir) {	/* slot #1: I/O direction mask */
 7404    error_location = loc;
 7405    switch (dir) {
 7406    case C_fix(1):
 7407      barf(C_BAD_ARGUMENT_TYPE_PORT_NO_INPUT_ERROR, NULL, x);
 7408    case C_fix(2):
 7409      barf(C_BAD_ARGUMENT_TYPE_PORT_NO_OUTPUT_ERROR, NULL, x);
 7410    default:
 7411      barf(C_BAD_ARGUMENT_TYPE_PORT_DIRECTION_ERROR, NULL, x);
 7412    }
 7413  }
 7414
 7415  if(open == C_SCHEME_TRUE) {
 7416    if(C_block_item(x, 8) == C_FIXNUM_BIT) {	/* slot #8: closed mask */
 7417      error_location = loc;
 7418      barf(C_PORT_CLOSED_ERROR, NULL, x);
 7419    }
 7420  }
 7421
 7422  return C_SCHEME_UNDEFINED;
 7423}
 7424
 7425
 7426C_regparm C_word C_i_check_range_2(C_word i, C_word f, C_word t, C_word loc)
 7427{
 7428  if(!(i & C_FIXNUM_BIT)) {
 7429    error_location = loc;
 7430    barf(C_BAD_ARGUMENT_TYPE_NO_FIXNUM_ERROR, NULL, i);
 7431  }
 7432
 7433  int index = C_unfix(i);
 7434
 7435  if(index < C_unfix(f)) {
 7436    error_location = loc;
 7437    barf(C_OUT_OF_BOUNDS_ERROR, NULL, f, i);
 7438  }
 7439
 7440  if(index >= C_unfix(t)) {
 7441    error_location = loc;
 7442    barf(C_OUT_OF_BOUNDS_ERROR, NULL, t, i);
 7443  }
 7444
 7445  return C_SCHEME_UNDEFINED;
 7446}
 7447
 7448
 7449C_regparm C_word C_i_check_range_including_2(C_word i, C_word f, C_word t, C_word loc)
 7450{
 7451  if(!(i & C_FIXNUM_BIT)) {
 7452    error_location = loc;
 7453    barf(C_BAD_ARGUMENT_TYPE_NO_FIXNUM_ERROR, NULL, i);
 7454  }
 7455
 7456  int index = C_unfix(i);
 7457
 7458  if(index < C_unfix(f)) {
 7459    error_location = loc;
 7460    barf(C_OUT_OF_BOUNDS_ERROR, NULL, f, i);
 7461  }
 7462
 7463  if(index > C_unfix(t)) {
 7464    error_location = loc;
 7465    barf(C_OUT_OF_BOUNDS_ERROR, NULL, t, i);
 7466  }
 7467
 7468  return C_SCHEME_UNDEFINED;
 7469}
 7470
 7471
 7472/*XXX these are not correctly named */
 7473C_regparm C_word C_i_foreign_char_argumentp(C_word x)
 7474{
 7475  if((x & C_IMMEDIATE_TYPE_BITS) != C_CHARACTER_BITS)
 7476    barf(C_BAD_ARGUMENT_TYPE_NO_CHAR_ERROR, NULL, x);
 7477
 7478  return x;
 7479}
 7480
 7481
 7482C_regparm C_word C_i_foreign_fixnum_argumentp(C_word x)
 7483{
 7484  if((x & C_FIXNUM_BIT) == 0)
 7485    barf(C_BAD_ARGUMENT_TYPE_NO_FIXNUM_ERROR, NULL, x);
 7486
 7487  return x;
 7488}
 7489
 7490
 7491C_regparm C_word C_i_foreign_flonum_argumentp(C_word x)
 7492{
 7493  if((x & C_FIXNUM_BIT) != 0) return x;
 7494
 7495  if(C_immediatep(x) || C_block_header(x) != C_FLONUM_TAG)
 7496    barf(C_BAD_ARGUMENT_TYPE_NO_FLONUM_ERROR, NULL, x);
 7497
 7498  return x;
 7499}
 7500
 7501
 7502C_regparm C_word C_i_foreign_cplxnum_argumentp(C_word x)
 7503{
 7504  if((x & C_FIXNUM_BIT) != 0) return x;
 7505
 7506  if(C_immediatep(x) || C_block_header(x) != C_FLONUM_TAG)
 7507    barf(C_BAD_ARGUMENT_TYPE_NO_FLONUM_ERROR, NULL, x);
 7508
 7509  return x;
 7510}
 7511
 7512
 7513C_regparm C_word C_i_foreign_block_argumentp(C_word x)
 7514{
 7515  if(C_immediatep(x))
 7516    barf(C_BAD_ARGUMENT_TYPE_NO_BLOCK_ERROR, NULL, x);
 7517
 7518  return x;
 7519}
 7520
 7521
 7522C_regparm C_word C_i_foreign_struct_wrapper_argumentp(C_word t, C_word x)
 7523{
 7524  if(C_immediatep(x) || C_header_bits(x) != C_STRUCTURE_TYPE || C_block_item(x, 0) != t)
 7525    barf(C_BAD_ARGUMENT_TYPE_BAD_STRUCT_ERROR, NULL, t, x);
 7526
 7527  return x;
 7528}
 7529
 7530
 7531C_regparm C_word C_i_foreign_string_argumentp(C_word x)
 7532{
 7533  if(C_immediatep(x) || C_header_bits(x) != C_STRING_TYPE)
 7534    barf(C_BAD_ARGUMENT_TYPE_NO_STRING_ERROR, NULL, x);
 7535
 7536  return x;
 7537}
 7538
 7539
 7540C_regparm C_word C_i_foreign_symbol_argumentp(C_word x)
 7541{
 7542  if(C_immediatep(x) || C_header_bits(x) != C_SYMBOL_TYPE)
 7543    barf(C_BAD_ARGUMENT_TYPE_NO_SYMBOL_ERROR, NULL, x);
 7544
 7545  return x;
 7546}
 7547
 7548
 7549C_regparm C_word C_i_foreign_pointer_argumentp(C_word x)
 7550{
 7551  if(C_immediatep(x) || (C_header_bits(x) & C_SPECIALBLOCK_BIT) == 0)
 7552    barf(C_BAD_ARGUMENT_TYPE_NO_POINTER_ERROR, NULL, x);
 7553
 7554  return x;
 7555}
 7556
 7557
 7558/* TODO: Is this used? */
 7559C_regparm C_word C_i_foreign_scheme_or_c_pointer_argumentp(C_word x)
 7560{
 7561  if(C_immediatep(x) || (C_header_bits(x) & C_SPECIALBLOCK_BIT) == 0)
 7562    barf(C_BAD_ARGUMENT_TYPE_NO_POINTER_ERROR, NULL, x);
 7563
 7564  return x;
 7565}
 7566
 7567
 7568C_regparm C_word C_i_foreign_tagged_pointer_argumentp(C_word x, C_word t)
 7569{
 7570  if(C_immediatep(x) || (C_header_bits(x) & C_SPECIALBLOCK_BIT) == 0
 7571     || (t != C_SCHEME_FALSE && !C_equalp(C_block_item(x, 1), t)))
 7572    barf(C_BAD_ARGUMENT_TYPE_NO_TAGGED_POINTER_ERROR, NULL, x, t);
 7573
 7574  return x;
 7575}
 7576
 7577C_regparm C_word C_i_foreign_ranged_integer_argumentp(C_word x, C_word bits)
 7578{
 7579  if((x & C_FIXNUM_BIT) != 0) {
 7580    if (C_truep(C_fixnum_lessp(C_i_fixnum_length(x), bits))) return x;
 7581    else barf(C_BAD_ARGUMENT_TYPE_FOREIGN_LIMITATION, NULL, x);
 7582  } else if (C_truep(C_i_bignump(x))) {
 7583    if (C_truep(C_fixnum_lessp(C_i_integer_length(x), bits))) return x;
 7584    else barf(C_BAD_ARGUMENT_TYPE_FOREIGN_LIMITATION, NULL, x);
 7585  } else {
 7586    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, NULL, x);
 7587  }
 7588}
 7589
 7590C_regparm C_word C_i_foreign_unsigned_ranged_integer_argumentp(C_word x, C_word bits)
 7591{
 7592  if((x & C_FIXNUM_BIT) != 0) {
 7593    if(x & C_INT_SIGN_BIT) barf(C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR, NULL, x);
 7594    else if(C_ilen(C_unfix(x)) <= C_unfix(bits)) return x;
 7595    else barf(C_BAD_ARGUMENT_TYPE_FOREIGN_LIMITATION, NULL, x);
 7596  } else if(C_truep(C_i_bignump(x))) {
 7597    if(C_bignum_negativep(x)) barf(C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR, NULL, x);
 7598    else if(integer_length_abs(x) <= C_unfix(bits)) return x;
 7599    else barf(C_BAD_ARGUMENT_TYPE_FOREIGN_LIMITATION, NULL, x);
 7600  } else {
 7601    barf(C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR, NULL, x);
 7602  }
 7603}
 7604
 7605/* I */
 7606C_regparm C_word C_i_not_pair_p_2(C_word x)
 7607{
 7608  return C_mk_bool(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE);
 7609}
 7610
 7611
 7612C_regparm C_word C_i_null_list_p(C_word x)
 7613{
 7614  if(x == C_SCHEME_END_OF_LIST) return C_SCHEME_TRUE;
 7615  else if(!C_immediatep(x) && C_header_type(x) == C_PAIR_TYPE) return C_SCHEME_FALSE;
 7616  else {
 7617    barf(C_BAD_ARGUMENT_TYPE_NO_LIST_ERROR, "null-list?", x);
 7618    return C_SCHEME_FALSE;
 7619  }
 7620}
 7621
 7622
 7623C_regparm C_word C_i_string_null_p(C_word x)
 7624{
 7625  if(!C_immediatep(x) && C_header_bits(x) == C_STRING_TYPE)
 7626    return C_mk_bool(C_unfix(C_block_item(x, 1)) == 0);
 7627  else {
 7628    barf(C_BAD_ARGUMENT_TYPE_NO_STRING_ERROR, "string-null?", x);
 7629    return C_SCHEME_FALSE;
 7630  }
 7631}
 7632
 7633
 7634C_regparm C_word C_i_null_pointerp(C_word x)
 7635{
 7636  if(!C_immediatep(x) && (C_header_bits(x) & C_SPECIALBLOCK_BIT) != 0)
 7637    return C_null_pointerp(x);
 7638
 7639  barf(C_BAD_ARGUMENT_TYPE_ERROR, "null-pointer?", x);
 7640  return C_SCHEME_FALSE;
 7641}
 7642
 7643/* only used here for char comparators below: */
 7644static C_word check_char_internal(C_word x, C_char *loc)
 7645{
 7646  if((x & C_IMMEDIATE_TYPE_BITS) != C_CHARACTER_BITS) {
 7647    error_location = intern0(loc);
 7648    barf(C_BAD_ARGUMENT_TYPE_NO_CHAR_ERROR, NULL, x);
 7649  }
 7650
 7651  return C_SCHEME_UNDEFINED;
 7652}
 7653
 7654C_regparm C_word C_i_char_equalp(C_word x, C_word y)
 7655{
 7656  check_char_internal(x, "char=?");
 7657  check_char_internal(y, "char=?");
 7658  return C_u_i_char_equalp(x, y);
 7659}
 7660
 7661C_regparm C_word C_i_char_greaterp(C_word x, C_word y)
 7662{
 7663  check_char_internal(x, "char>?");
 7664  check_char_internal(y, "char>?");
 7665  return C_u_i_char_greaterp(x, y);
 7666}
 7667
 7668C_regparm C_word C_i_char_lessp(C_word x, C_word y)
 7669{
 7670  check_char_internal(x, "char<?");
 7671  check_char_internal(y, "char<?");
 7672  return C_u_i_char_lessp(x, y);
 7673}
 7674
 7675C_regparm C_word C_i_char_greater_or_equal_p(C_word x, C_word y)
 7676{
 7677  check_char_internal(x, "char>=?");
 7678  check_char_internal(y, "char>=?");
 7679  return C_u_i_char_greater_or_equal_p(x, y);
 7680}
 7681
 7682C_regparm C_word C_i_char_less_or_equal_p(C_word x, C_word y)
 7683{
 7684  check_char_internal(x, "char<=?");
 7685  check_char_internal(y, "char<=?");
 7686  return C_u_i_char_less_or_equal_p(x, y);
 7687}
 7688
 7689
 7690/* Primitives: */
 7691
 7692void C_ccall C_apply(C_word c, C_word *av)
 7693{
 7694  C_word
 7695    /* closure = av[ 0 ] */
 7696    k = av[ 1 ],
 7697    fn = av[ 2 ];
 7698  int av2_size, i, n = c - 3;
 7699  int non_list_args = n - 1;
 7700  C_word lst, len, *ptr, *av2;
 7701
 7702  if(c < 4) C_bad_min_argc(c, 4);
 7703
 7704  if(C_immediatep(fn) || C_header_bits(fn) != C_CLOSURE_TYPE)
 7705    barf(C_NOT_A_CLOSURE_ERROR, "apply", fn);
 7706
 7707  lst = av[ c - 1 ];
 7708  if(lst != C_SCHEME_END_OF_LIST && (C_immediatep(lst) || C_header_type(lst) != C_PAIR_TYPE))
 7709    barf(C_BAD_ARGUMENT_TYPE_ERROR, "apply", lst);
 7710
 7711  len = C_unfix(C_u_i_length(lst));
 7712  av2_size = 2 + non_list_args + len;
 7713
 7714  if(C_demand(av2_size))
 7715    stack_check_demand = 0;
 7716  else if(stack_check_demand)
 7717    C_stack_overflow("apply");
 7718  else {
 7719    stack_check_demand = av2_size;
 7720    C_save_and_reclaim((void *)C_apply, c, av);
 7721  }
 7722
 7723  av2 = ptr = C_alloc(av2_size);
 7724  *(ptr++) = fn;
 7725  *(ptr++) = k;
 7726
 7727  if(non_list_args > 0) {
 7728    C_memcpy(ptr, av + 3, non_list_args * sizeof(C_word));
 7729    ptr += non_list_args;
 7730  }
 7731
 7732  while(len--) {
 7733    *(ptr++) = C_u_i_car(lst);
 7734    lst = C_u_i_cdr(lst);
 7735  }
 7736
 7737  assert((ptr - av2) == av2_size);
 7738
 7739  ((C_proc)(void *)C_block_item(fn, 0))(av2_size, av2);
 7740}
 7741
 7742
 7743void C_ccall C_call_cc(C_word c, C_word *av)
 7744{
 7745  C_word
 7746    /* closure = av[ 0 ] */
 7747    k = av[ 1 ],
 7748    cont = av[ 2 ],
 7749    *a = C_alloc(C_SIZEOF_CLOSURE(2)),
 7750    wrapper;
 7751  void *pr = (void *)C_block_item(cont,0);
 7752  C_word av2[ 3 ];
 7753
 7754  if(C_immediatep(cont) || C_header_bits(cont) != C_CLOSURE_TYPE)
 7755    barf(C_BAD_ARGUMENT_TYPE_ERROR, "call-with-current-continuation", cont);
 7756
 7757  /* Check for values-continuation: */
 7758  if(C_block_item(k, 0) == (C_word)values_continuation)
 7759    wrapper = C_closure(&a, 2, (C_word)call_cc_values_wrapper, k);
 7760  else wrapper = C_closure(&a, 2, (C_word)call_cc_wrapper, k);
 7761
 7762  av2[ 0 ] = cont;
 7763  av2[ 1 ] = k;
 7764  av2[ 2 ] = wrapper;
 7765  ((C_proc)pr)(3, av2);
 7766}
 7767
 7768
 7769void C_ccall call_cc_wrapper(C_word c, C_word *av)
 7770{
 7771  C_word
 7772    closure = av[ 0 ],
 7773    /* av[ 1 ] is current k and ignored */
 7774    result,
 7775    k = C_block_item(closure, 1);
 7776
 7777  if(c != 3) C_bad_argc(c, 3);
 7778
 7779  result = av[ 2 ];
 7780  C_kontinue(k, result);
 7781}
 7782
 7783
 7784void C_ccall call_cc_values_wrapper(C_word c, C_word *av)
 7785{
 7786  C_word
 7787    closure = av[ 0 ],
 7788    /* av[ 1 ] is current k and ignored */
 7789    k = C_block_item(closure, 1),
 7790    x1,
 7791    n = c;
 7792
 7793  av[ 0 ] = k;               /* reuse av */
 7794  C_memmove(av + 1, av + 2, (n - 1) * sizeof(C_word));
 7795  C_do_apply(n - 1, av);
 7796}
 7797
 7798
 7799void C_ccall C_continuation_graft(C_word c, C_word *av)
 7800{
 7801  C_word
 7802    /* self = av[ 0 ] */
 7803    /* k = av[ 1 ] */
 7804    kk = av[ 2 ],
 7805    proc = av[ 3 ];
 7806
 7807  av[ 0 ] = proc;               /* reuse av */
 7808  av[ 1 ] = C_block_item(kk, 1);
 7809  ((C_proc)C_fast_retrieve_proc(proc))(2, av);
 7810}
 7811
 7812
 7813void C_ccall C_values(C_word c, C_word *av)
 7814{
 7815  C_word
 7816    /* closure = av[ 0 ] */
 7817    k = av[ 1 ],
 7818    n = c;
 7819
 7820  if(c < 2) C_bad_min_argc(c, 2);
 7821
 7822  /* Check continuation whether it receives multiple values: */
 7823  if(C_block_item(k, 0) == (C_word)values_continuation) {
 7824    av[ 0 ] = k;                /* reuse av */
 7825    C_memmove(av + 1, av + 2, (c - 2) * sizeof(C_word));
 7826    C_do_apply(c - 1, av);
 7827  }
 7828
 7829  if(c != 3) {
 7830#ifdef RELAX_MULTIVAL_CHECK
 7831    if(c == 2) n = C_SCHEME_UNDEFINED;
 7832    else n = av[ 2 ];
 7833#else
 7834    barf(C_CONTINUATION_CANT_RECEIVE_VALUES_ERROR, "values", k);
 7835#endif
 7836  }
 7837  else n = av[ 2 ];
 7838
 7839  C_kontinue(k, n);
 7840}
 7841
 7842
 7843void C_ccall C_apply_values(C_word c, C_word *av)
 7844{
 7845  C_word
 7846    /* closure = av[ 0 ] */
 7847    k = av[ 1 ],
 7848    lst, len, n;
 7849
 7850  if(c != 3) C_bad_argc(c, 3);
 7851
 7852  lst = av[ 2 ];
 7853
 7854  if(lst != C_SCHEME_END_OF_LIST && (C_immediatep(lst) || C_header_type(lst) != C_PAIR_TYPE))
 7855    barf(C_BAD_ARGUMENT_TYPE_ERROR, "apply", lst);
 7856
 7857  /* Check whether continuation receives multiple values: */
 7858  if(C_block_item(k, 0) == (C_word)values_continuation) {
 7859    C_word *av2, *ptr;
 7860
 7861    len = C_unfix(C_u_i_length(lst));
 7862    n = len + 1;
 7863
 7864    if(C_demand(n))
 7865      stack_check_demand = 0;
 7866    else if(stack_check_demand)
 7867      C_stack_overflow("apply");
 7868    else {
 7869      stack_check_demand = n;
 7870      C_save_and_reclaim((void *)C_apply_values, c, av);
 7871    }
 7872
 7873    av2 = C_alloc(n);
 7874    av2[ 0 ] = k;
 7875    ptr = av2 + 1;
 7876    while(len--) {
 7877      *(ptr++) = C_u_i_car(lst);
 7878      lst = C_u_i_cdr(lst);
 7879    }
 7880
 7881    C_do_apply(n, av2);
 7882  }
 7883
 7884  if(C_immediatep(lst)) {
 7885#ifdef RELAX_MULTIVAL_CHECK
 7886    n = C_SCHEME_UNDEFINED;
 7887#else
 7888    barf(C_CONTINUATION_CANT_RECEIVE_VALUES_ERROR, "values", k);
 7889#endif
 7890  }
 7891  else if(C_header_type(lst) == C_PAIR_TYPE) {
 7892    if(C_u_i_cdr(lst) == C_SCHEME_END_OF_LIST)
 7893      n = C_u_i_car(lst);
 7894    else {
 7895#ifdef RELAX_MULTIVAL_CHECK
 7896      n = C_u_i_car(lst);
 7897#else
 7898      barf(C_CONTINUATION_CANT_RECEIVE_VALUES_ERROR, "values", k);
 7899#endif
 7900    }
 7901  }
 7902  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "apply", lst);
 7903
 7904  C_kontinue(k, n);
 7905}
 7906
 7907
 7908void C_ccall C_call_with_values(C_word c, C_word *av)
 7909{
 7910  C_word
 7911    /* closure = av[ 0 ] */
 7912    k = av[ 1 ],
 7913    thunk,
 7914    kont,
 7915    *a = C_alloc(C_SIZEOF_CLOSURE(3)),
 7916    kk;
 7917
 7918  if(c != 4) C_bad_argc(c, 4);
 7919
 7920  thunk = av[ 2 ];
 7921  kont = av[ 3 ];
 7922
 7923  if(C_immediatep(thunk) || C_header_bits(thunk) != C_CLOSURE_TYPE)
 7924    barf(C_BAD_ARGUMENT_TYPE_ERROR, "call-with-values", thunk);
 7925
 7926  if(C_immediatep(kont) || C_header_bits(kont) != C_CLOSURE_TYPE)
 7927    barf(C_BAD_ARGUMENT_TYPE_ERROR, "call-with-values", kont);
 7928
 7929  kk = C_closure(&a, 3, (C_word)values_continuation, kont, k);
 7930  av[ 0 ] = thunk;              /* reuse av */
 7931  av[ 1 ] = kk;
 7932  C_do_apply(2, av);
 7933}
 7934
 7935
 7936void C_ccall C_u_call_with_values(C_word c, C_word *av)
 7937{
 7938  C_word
 7939    /* closure = av[ 0 ] */
 7940    k = av[ 1 ],
 7941    thunk = av[ 2 ],
 7942    kont = av[ 3 ],
 7943    *a = C_alloc(C_SIZEOF_CLOSURE(3)),
 7944    kk;
 7945
 7946  kk = C_closure(&a, 3, (C_word)values_continuation, kont, k);
 7947  av[ 0 ] = thunk;              /* reuse av */
 7948  av[ 1 ] = kk;
 7949  C_do_apply(2, av);
 7950}
 7951
 7952
 7953void C_ccall values_continuation(C_word c, C_word *av)
 7954{
 7955  C_word
 7956    closure = av[ 0 ],
 7957    kont = C_block_item(closure, 1),
 7958    k = C_block_item(closure, 2),
 7959    *av2 = C_alloc(c + 1);
 7960
 7961  av2[ 0 ] = kont;
 7962  av2[ 1 ] = k;
 7963  C_memcpy(av2 + 2, av + 1, (c - 1) * sizeof(C_word));
 7964  C_do_apply(c + 1, av2);
 7965}
 7966
 7967static C_word rat_times_integer(C_word **ptr, C_word rat, C_word i)
 7968{
 7969  C_word ab[C_SIZEOF_FIX_BIGNUM * 2], *a = ab, num, denom, gcd, a_div_g;
 7970
 7971  switch (i) {
 7972  case C_fix(0): return C_fix(0);
 7973  case C_fix(1): return rat;
 7974  case C_fix(-1):
 7975    num = C_s_a_u_i_integer_negate(ptr, 1, C_u_i_ratnum_num(rat));
 7976    return C_ratnum(ptr, num , C_u_i_ratnum_denom(rat));
 7977  /* default: CONTINUE BELOW */
 7978  }
 7979
 7980  num = C_u_i_ratnum_num(rat);
 7981  denom = C_u_i_ratnum_denom(rat);
 7982
 7983  /* a/b * c/d = a*c / b*d  [with b = 1] */
 7984  /*  =  ((a / g) * c) / (d / g) */
 7985  /* With   g = gcd(a, d)   and  a = x   [Knuth, 4.5.1] */
 7986  gcd = C_s_a_u_i_integer_gcd(&a, 2, i, denom);
 7987
 7988  /* Calculate a/g  (= i/gcd), which will later be multiplied by y */
 7989  a_div_g = C_s_a_u_i_integer_quotient(&a, 2, i, gcd);
 7990  if (a_div_g == C_fix(0)) {
 7991    clear_buffer_object(ab, gcd);
 7992    return C_fix(0); /* Save some work */
 7993  }
 7994
 7995  /* Final numerator = a/g * c  (= a_div_g * num) */
 7996  num = C_s_a_u_i_integer_times(ptr, 2, a_div_g, num);
 7997
 7998  /* Final denominator = d/g  (= denom/gcd) */
 7999  denom = C_s_a_u_i_integer_quotient(ptr, 2, denom, gcd);
 8000
 8001  num = move_buffer_object(ptr, ab, num);
 8002  denom = move_buffer_object(ptr, ab, denom);
 8003
 8004  clear_buffer_object(ab, gcd);
 8005  clear_buffer_object(ab, a_div_g);
 8006
 8007  if (denom == C_fix(1)) return num;
 8008  else return C_ratnum(ptr, num, denom);
 8009}
 8010
 8011static C_word rat_times_rat(C_word **ptr, C_word x, C_word y)
 8012{
 8013  C_word ab[C_SIZEOF_FIX_BIGNUM * 6], *a = ab,
 8014         num, denom, xnum, xdenom, ynum, ydenom,
 8015         g1, g2, a_div_g1, b_div_g2, c_div_g2, d_div_g1;
 8016
 8017  xnum = C_u_i_ratnum_num(x);
 8018  xdenom = C_u_i_ratnum_denom(x);
 8019  ynum = C_u_i_ratnum_num(y);
 8020  ydenom = C_u_i_ratnum_denom(y);
 8021
 8022  /* a/b * c/d = a*c / b*d  [generic] */
 8023  /*   = ((a / g1) * (c / g2)) / ((b / g2) * (d / g1)) */
 8024  /* With  g1 = gcd(a, d)  and   g2 = gcd(b, c) [Knuth, 4.5.1] */
 8025  g1 = C_s_a_u_i_integer_gcd(&a, 2, xnum, ydenom);
 8026  g2 = C_s_a_u_i_integer_gcd(&a, 2, ynum, xdenom);
 8027
 8028  /* Calculate a/g1  (= xnum/g1), which will later be multiplied by c/g2 */
 8029  a_div_g1 = C_s_a_u_i_integer_quotient(&a, 2, xnum, g1);
 8030
 8031  /* Calculate c/g2  (= ynum/g2), which will later be multiplied by a/g1 */
 8032  c_div_g2 = C_s_a_u_i_integer_quotient(&a, 2, ynum, g2);
 8033
 8034  /* Final numerator = a/g1 * c/g2 */
 8035  num = C_s_a_u_i_integer_times(ptr, 2, a_div_g1, c_div_g2);
 8036
 8037  /* Now, do the same for the denominator.... */
 8038
 8039  /* Calculate b/g2  (= xdenom/g2), which will later be multiplied by d/g1 */
 8040  b_div_g2 = C_s_a_u_i_integer_quotient(&a, 2, xdenom, g2);
 8041
 8042  /* Calculate d/g1  (= ydenom/g1), which will later be multiplied by b/g2 */
 8043  d_div_g1 = C_s_a_u_i_integer_quotient(&a, 2, ydenom, g1);
 8044
 8045  /* Final denominator = b/g2 * d/g1 */
 8046  denom = C_s_a_u_i_integer_times(ptr, 2, b_div_g2, d_div_g1);
 8047
 8048  num = move_buffer_object(ptr, ab, num);
 8049  denom = move_buffer_object(ptr, ab, denom);
 8050
 8051  clear_buffer_object(ab, g1);
 8052  clear_buffer_object(ab, g2);
 8053  clear_buffer_object(ab, a_div_g1);
 8054  clear_buffer_object(ab, b_div_g2);
 8055  clear_buffer_object(ab, c_div_g2);
 8056  clear_buffer_object(ab, d_div_g1);
 8057
 8058  if (denom == C_fix(1)) return num;
 8059  else return C_ratnum(ptr, num, denom);
 8060}
 8061
 8062static C_word
 8063cplx_times(C_word **ptr, C_word rx, C_word ix, C_word ry, C_word iy)
 8064{
 8065  /* Allocation here is kind of tricky: Each intermediate result can
 8066   * be at most a ratnum consisting of two bignums (2 digits), so
 8067   * C_SIZEOF_RATNUM + C_SIZEOF_BIGNUM(2) = 9 words
 8068   */
 8069  C_word ab[(C_SIZEOF_RATNUM + C_SIZEOF_BIGNUM(2))*6], *a = ab,
 8070         r1, r2, i1, i2, r, i;
 8071
 8072  /* a+bi * c+di = (a*c - b*d) + (a*d + b*c)i */
 8073  /* We call these:  r1 = a*c, r2 = b*d, i1 = a*d, i2 = b*c */
 8074  r1 = C_s_a_i_times(&a, 2, rx, ry);
 8075  r2 = C_s_a_i_times(&a, 2, ix, iy);
 8076  i1 = C_s_a_i_times(&a, 2, rx, iy);
 8077  i2 = C_s_a_i_times(&a, 2, ix, ry);
 8078
 8079  r = C_s_a_i_minus(ptr, 2, r1, r2);
 8080  i = C_s_a_i_plus(ptr, 2, i1, i2);
 8081
 8082  r = move_buffer_object(ptr, ab, r);
 8083  i = move_buffer_object(ptr, ab, i);
 8084
 8085  clear_buffer_object(ab, r1);
 8086  clear_buffer_object(ab, r2);
 8087  clear_buffer_object(ab, i1);
 8088  clear_buffer_object(ab, i2);
 8089
 8090  if (C_truep(C_u_i_zerop2(i))) return r;
 8091  else return C_cplxnum(ptr, r, i);
 8092}
 8093
 8094/* The maximum size this needs is that required to store a complex
 8095 * number result, where both real and imag parts consist of ratnums.
 8096 * The maximum size of those ratnums is if they consist of two bignums
 8097 * from a fixnum multiplication (2 digits each), so we're looking at
 8098 * C_SIZEOF_RATNUM * 3 + C_SIZEOF_BIGNUM(2) * 4 = 33 words!
 8099 */
 8100C_regparm C_word
 8101C_s_a_i_times(C_word **ptr, C_word n, C_word x, C_word y)
 8102{
 8103  if (x & C_FIXNUM_BIT) {
 8104    if (y & C_FIXNUM_BIT) {
 8105      return C_a_i_fixnum_times(ptr, 2, x, y);
 8106    } else if (C_immediatep(y)) {
 8107      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", y);
 8108    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8109      return C_flonum(ptr, (double)C_unfix(x) * C_flonum_magnitude(y));
 8110    } else if (C_truep(C_bignump(y))) {
 8111      return C_s_a_u_i_integer_times(ptr, 2, x, y);
 8112    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8113      return rat_times_integer(ptr, y, x);
 8114    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8115      return cplx_times(ptr, x, C_fix(0),
 8116                        C_u_i_cplxnum_real(y), C_u_i_cplxnum_imag(y));
 8117    } else {
 8118      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", y);
 8119    }
 8120  } else if (C_immediatep(x)) {
 8121    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", x);
 8122  } else if (C_block_header(x) == C_FLONUM_TAG) {
 8123    if (y & C_FIXNUM_BIT) {
 8124      return C_flonum(ptr, C_flonum_magnitude(x) * (double)C_unfix(y));
 8125    } else if (C_immediatep(y)) {
 8126      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", y);
 8127    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8128      return C_a_i_flonum_times(ptr, 2, x, y);
 8129    } else if (C_truep(C_bignump(y))) {
 8130      return C_flonum(ptr, C_flonum_magnitude(x) * C_bignum_to_double(y));
 8131    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8132      return C_s_a_i_times(ptr, 2, x, C_a_i_exact_to_inexact(ptr, 1, y));
 8133    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8134      C_word ab[C_SIZEOF_FLONUM], *a = ab;
 8135      return cplx_times(ptr, x, C_flonum(&a, 0.0),
 8136                        C_u_i_cplxnum_real(y), C_u_i_cplxnum_imag(y));
 8137    } else {
 8138      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", y);
 8139    }
 8140  } else if (C_truep(C_bignump(x))) {
 8141    if (y & C_FIXNUM_BIT) {
 8142      return C_s_a_u_i_integer_times(ptr, 2, x, y);
 8143    } else if (C_immediatep(y)) {
 8144      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", x);
 8145    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8146      return C_flonum(ptr, C_bignum_to_double(x) * C_flonum_magnitude(y));
 8147    } else if (C_truep(C_bignump(y))) {
 8148      return C_s_a_u_i_integer_times(ptr, 2, x, y);
 8149    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8150      return rat_times_integer(ptr, y, x);
 8151    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8152      return cplx_times(ptr, x, C_fix(0),
 8153                        C_u_i_cplxnum_real(y), C_u_i_cplxnum_imag(y));
 8154    } else {
 8155      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", y);
 8156    }
 8157  } else if (C_block_header(x) == C_RATNUM_TAG) {
 8158    if (y & C_FIXNUM_BIT) {
 8159      return rat_times_integer(ptr, x, y);
 8160    } else if (C_immediatep(y)) {
 8161      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", y);
 8162    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8163      return C_s_a_i_times(ptr, 2, C_a_i_exact_to_inexact(ptr, 1, x), y);
 8164    } else if (C_truep(C_bignump(y))) {
 8165      return rat_times_integer(ptr, x, y);
 8166    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8167        return rat_times_rat(ptr, x, y);
 8168    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8169      return cplx_times(ptr, x, C_fix(0),
 8170                        C_u_i_cplxnum_real(y), C_u_i_cplxnum_imag(y));
 8171    } else {
 8172      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", y);
 8173    }
 8174  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 8175    if (!C_immediatep(y) && C_block_header(y) == C_CPLXNUM_TAG) {
 8176      return cplx_times(ptr, C_u_i_cplxnum_real(x), C_u_i_cplxnum_imag(x),
 8177                        C_u_i_cplxnum_real(y), C_u_i_cplxnum_imag(y));
 8178    } else {
 8179      C_word ab[C_SIZEOF_FLONUM], *a = ab, yi;
 8180      yi = C_truep(C_i_flonump(y)) ? C_flonum(&a,0) : C_fix(0);
 8181      return cplx_times(ptr, C_u_i_ratnum_num(x), C_u_i_ratnum_denom(x), y, yi);
 8182    }
 8183  } else {
 8184    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", x);
 8185  }
 8186}
 8187
 8188
 8189C_regparm C_word
 8190C_s_a_u_i_integer_times(C_word **ptr, C_word n, C_word x, C_word y)
 8191{
 8192  if (x & C_FIXNUM_BIT) {
 8193    if (y & C_FIXNUM_BIT) {
 8194      return C_a_i_fixnum_times(ptr, 2, x, y);
 8195    } else {
 8196      C_word tmp = x; /* swap to ensure x is a bignum and y a fixnum */
 8197      x = y;
 8198      y = tmp;
 8199    }
 8200  }
 8201  /* Here, we know for sure that X is a bignum */
 8202  if (y == C_fix(0)) {
 8203    return C_fix(0);
 8204  } else if (y == C_fix(1)) {
 8205    return x;
 8206  } else if (y == C_fix(-1)) {
 8207    return C_s_a_u_i_integer_negate(ptr, 1, x);
 8208  } else if (y & C_FIXNUM_BIT) { /* Any other fixnum */
 8209    C_word absy = (y & C_INT_SIGN_BIT) ? -C_unfix(y) : C_unfix(y),
 8210           negp = C_mk_bool((y & C_INT_SIGN_BIT) ?
 8211                            !C_bignum_negativep(x) :
 8212                            C_bignum_negativep(x));
 8213
 8214    if (C_fitsinbignumhalfdigitp(absy) ||
 8215        (((C_uword)1 << (C_ilen(absy)-1)) == absy && C_fitsinfixnump(absy))) {
 8216      C_word size, res;
 8217      C_uword *startr, *endr;
 8218      int shift;
 8219      size = C_bignum_size(x) + 1; /* Needs _at most_ one more digit */
 8220      res = C_allocate_scratch_bignum(ptr, C_fix(size), negp, C_SCHEME_FALSE);
 8221
 8222      bignum_digits_destructive_copy(res, x);
 8223
 8224      startr = C_bignum_digits(res);
 8225      endr = startr + size - 1;
 8226      /* Scale up, and sanitise the result. */
 8227      shift = C_ilen(absy) - 1;
 8228      if (((C_uword)1 << shift) == absy) { /* Power of two? */
 8229        *endr = bignum_digits_destructive_shift_left(startr, endr, shift);
 8230      } else {
 8231        *endr = bignum_digits_destructive_scale_up_with_carry(startr, endr,
 8232                                                              absy, 0);
 8233      }
 8234      return C_bignum_simplify(res);
 8235    } else {
 8236      C_word *a = C_alloc(C_SIZEOF_FIX_BIGNUM);
 8237      y = C_a_u_i_fix_to_big(&a, y);
 8238      return bignum_times_bignum_unsigned(ptr, x, y, negp);
 8239    }
 8240  } else {
 8241    C_word negp = C_bignum_negativep(x) ?
 8242                  !C_bignum_negativep(y) :
 8243                  C_bignum_negativep(y);
 8244    return bignum_times_bignum_unsigned(ptr, x, y, C_mk_bool(negp));
 8245  }
 8246}
 8247
 8248static C_regparm C_word
 8249bignum_times_bignum_unsigned(C_word **ptr, C_word x, C_word y, C_word negp)
 8250{
 8251  C_word size, res = C_SCHEME_FALSE;
 8252  if (C_bignum_size(y) < C_bignum_size(x)) { /* Ensure size(x) <= size(y) */
 8253    C_word z = x;
 8254    x = y;
 8255    y = z;
 8256  }
 8257
 8258  if (C_bignum_size(x) >= C_KARATSUBA_THRESHOLD)
 8259    res = bignum_times_bignum_karatsuba(ptr, x, y, negp);
 8260
 8261  if (!C_truep(res)) {
 8262    size = C_bignum_size(x) + C_bignum_size(y);
 8263    res = C_allocate_scratch_bignum(ptr, C_fix(size), negp, C_SCHEME_TRUE);
 8264    bignum_digits_multiply(x, y, res);
 8265    res = C_bignum_simplify(res);
 8266  }
 8267  return res;
 8268}
 8269
 8270/* Karatsuba multiplication: invoked when the two numbers are large
 8271 * enough to make it worthwhile, and we still have enough stack left.
 8272 * Complexity is O(n^log2(3)), where n is max(len(x), len(y)).  The
 8273 * description in [Knuth, 4.3.3] leaves a lot to be desired.  [MCA,
 8274 * 1.3.2] and [MpNT, 3.2] are a bit easier to understand.  We assume
 8275 * that length(x) <= length(y).
 8276 */
 8277static C_regparm C_word
 8278bignum_times_bignum_karatsuba(C_word **ptr, C_word x, C_word y, C_word negp)
 8279{
 8280   C_word kab[C_SIZEOF_FIX_BIGNUM*15+C_SIZEOF_BIGNUM(2)*3], *ka = kab, o[18],
 8281          xhi, xlo, xmid, yhi, ylo, ymid, a, b, c, n, bits;
 8282   int i = 0;
 8283
 8284   /* Ran out of stack?  Fall back to non-recursive multiplication */
 8285   C_stack_check1(return C_SCHEME_FALSE);
 8286
 8287   /* Split |x| in half: <xhi,xlo> and |y|: <yhi,ylo> with len(ylo)=len(xlo) */
 8288   x = o[i++] = C_s_a_u_i_integer_abs(&ka, 1, x);
 8289   y = o[i++] = C_s_a_u_i_integer_abs(&ka, 1, y);
 8290   n = C_fix(C_bignum_size(y) >> 1);
 8291   xhi = o[i++] = bignum_extract_digits(&ka, 3, x, n, C_SCHEME_FALSE);
 8292   xlo = o[i++] = bignum_extract_digits(&ka, 3, x, C_fix(0), n);
 8293   yhi = o[i++] = bignum_extract_digits(&ka, 3, y, n, C_SCHEME_FALSE);
 8294   ylo = o[i++] = bignum_extract_digits(&ka, 3, y, C_fix(0), n);
 8295
 8296   /* a = xhi * yhi, b = xlo * ylo, c = (xhi - xlo) * (yhi - ylo) */
 8297   a = o[i++] = C_s_a_u_i_integer_times(&ka, 2, xhi, yhi);
 8298   b = o[i++] = C_s_a_u_i_integer_times(&ka, 2, xlo, ylo);
 8299   xmid = o[i++] = C_s_a_u_i_integer_minus(&ka, 2, xhi, xlo);
 8300   ymid = o[i++] = C_s_a_u_i_integer_minus(&ka, 2, yhi, ylo);
 8301   c = o[i++] = C_s_a_u_i_integer_times(&ka, 2, xmid, ymid);
 8302
 8303   /* top(x) = a << (bits - 1)  and  bottom(y) = ((b + (a - c)) << bits) + b */
 8304   bits = C_unfix(n) * C_BIGNUM_DIGIT_LENGTH;
 8305   x = o[i++] = C_s_a_i_arithmetic_shift(&ka, 2, a, C_fix((C_uword)bits << 1));
 8306   c = o[i++] = C_s_a_u_i_integer_minus(&ka, 2, a, c);
 8307   c = o[i++] = C_s_a_u_i_integer_plus(&ka, 2, b, c);
 8308   c = o[i++] = C_s_a_i_arithmetic_shift(&ka, 2, c, C_fix(bits));
 8309   y = o[i++] = C_s_a_u_i_integer_plus(&ka, 2, c, b);
 8310   /* Finally, return top + bottom, and correct for negative */
 8311   n = o[i++] = C_s_a_u_i_integer_plus(&ka, 2, x, y);
 8312   if (C_truep(negp)) n = o[i++] = C_s_a_u_i_integer_negate(&ka, 1, n);
 8313
 8314   n = move_buffer_object(ptr, kab, n);
 8315   while(i--) clear_buffer_object(kab, o[i]);
 8316   return n;
 8317}
 8318
 8319void C_ccall C_times(C_word c, C_word *av)
 8320{
 8321  /* C_word closure = av[ 0 ]; */
 8322  C_word k = av[ 1 ];
 8323  C_word next_val,
 8324    result = C_fix(1),
 8325    prev_result = result;
 8326  C_word ab[2][C_SIZEOF_CPLXNUM + C_SIZEOF_RATNUM*2 + C_SIZEOF_BIGNUM(2) * 4], *a;
 8327
 8328  c -= 2;
 8329  av += 2;
 8330
 8331  while (c--) {
 8332    next_val = *(av++);
 8333    a = ab[c&1]; /* One may hold prev iteration result, the other is unused */
 8334    result = C_s_a_i_times(&a, 2, result, next_val);
 8335    result = move_buffer_object(&a, ab[(c+1)&1], result);
 8336    clear_buffer_object(ab[(c+1)&1], prev_result);
 8337    prev_result = result;
 8338  }
 8339
 8340  C_kontinue(k, result);
 8341}
 8342
 8343
 8344static C_word bignum_plus_unsigned(C_word **ptr, C_word x, C_word y, C_word negp)
 8345{
 8346  C_word size, result;
 8347  C_uword sum, digit, *scan_y, *end_y, *scan_r, *end_r;
 8348  int carry = 0;
 8349
 8350  if (C_bignum_size(y) > C_bignum_size(x)) {  /* Ensure size(y) <= size(x) */
 8351    C_word z = x;
 8352    x = y;
 8353    y = z;
 8354  }
 8355
 8356  size = C_fix(C_bignum_size(x) + 1); /* One more digit, for possible carry. */
 8357  result = C_allocate_scratch_bignum(ptr, size, negp, C_SCHEME_FALSE);
 8358
 8359  scan_y = C_bignum_digits(y);
 8360  end_y = scan_y + C_bignum_size(y);
 8361  scan_r = C_bignum_digits(result);
 8362  end_r = scan_r + C_bignum_size(result);
 8363
 8364  /* Copy x into r so we can operate on two pointers, which is faster
 8365   * than three, and we can stop earlier after adding y.  It's slower
 8366   * if x and y have equal length.  On average it's slightly faster.
 8367   */
 8368  bignum_digits_destructive_copy(result, x);
 8369  *(end_r-1) = 0; /* Ensure most significant digit is initialised */
 8370
 8371  /* Move over x and y simultaneously, destructively adding digits w/ carry. */
 8372  while (scan_y < end_y) {
 8373    digit = *scan_r;
 8374    if (carry) {
 8375      sum = digit + *scan_y++ + 1;
 8376      carry = sum <= digit;
 8377    } else {
 8378      sum = digit + *scan_y++;
 8379      carry = sum < digit;
 8380    }
 8381    (*scan_r++) = sum;
 8382  }
 8383
 8384  /* The end of y, the smaller number.  Propagate carry into the rest of x. */
 8385  while (carry) {
 8386    sum = (*scan_r) + 1;
 8387    carry = (sum == 0);
 8388    (*scan_r++) = sum;
 8389  }
 8390  assert(scan_r <= end_r);
 8391
 8392  return C_bignum_simplify(result);
 8393}
 8394
 8395static C_word rat_plusmin_integer(C_word **ptr, C_word rat, C_word i, integer_plusmin_op plusmin_op)
 8396{
 8397  C_word ab[C_SIZEOF_FIX_BIGNUM+C_SIZEOF_BIGNUM(2)], *a = ab,
 8398         num, denom, tmp, res;
 8399
 8400  if (i == C_fix(0)) return rat;
 8401
 8402  num = C_u_i_ratnum_num(rat);
 8403  denom = C_u_i_ratnum_denom(rat);
 8404
 8405  /* a/b [+-] c/d = (a*d [+-] b*c)/(b*d) | d = 1: (num + denom * i) / denom */
 8406  tmp = C_s_a_u_i_integer_times(&a, 2, denom, i);
 8407  res = plusmin_op(&a, 2, num, tmp);
 8408  res = move_buffer_object(ptr, ab, res);
 8409  clear_buffer_object(ab, tmp);
 8410  return C_ratnum(ptr, res, denom);
 8411}
 8412
 8413/* This is needed only for minus: plus is commutative but minus isn't. */
 8414static C_word integer_minus_rat(C_word **ptr, C_word i, C_word rat)
 8415{
 8416  C_word ab[C_SIZEOF_FIX_BIGNUM+C_SIZEOF_BIGNUM(2)], *a = ab,
 8417         num, denom, tmp, res;
 8418
 8419  num = C_u_i_ratnum_num(rat);
 8420  denom = C_u_i_ratnum_denom(rat);
 8421
 8422  if (i == C_fix(0))
 8423    return C_ratnum(ptr, C_s_a_u_i_integer_negate(ptr, 1, num), denom);
 8424
 8425  /* a/b - c/d = (a*d - b*c)/(b*d) | b = 1: (denom * i - num) / denom */
 8426  tmp = C_s_a_u_i_integer_times(&a, 2, denom, i);
 8427  res = C_s_a_u_i_integer_minus(&a, 2, tmp, num);
 8428  res = move_buffer_object(ptr, ab, res);
 8429  clear_buffer_object(ab, tmp);
 8430  return C_ratnum(ptr, res, denom);
 8431}
 8432
 8433/* This is pretty braindead and ugly */
 8434static C_word rat_plusmin_rat(C_word **ptr, C_word x, C_word y, integer_plusmin_op plusmin_op)
 8435{
 8436  C_word ab[C_SIZEOF_FIX_BIGNUM*6 + C_SIZEOF_BIGNUM(2)*2], *a = ab,
 8437         xnum = C_u_i_ratnum_num(x), ynum = C_u_i_ratnum_num(y),
 8438         xdenom = C_u_i_ratnum_denom(x), ydenom = C_u_i_ratnum_denom(y),
 8439         xnorm, ynorm, tmp_r, g1, ydenom_g1, xdenom_g1, norm_sum, g2, len,
 8440         res_num, res_denom;
 8441
 8442  /* Knuth, 4.5.1.  Start with g1 = gcd(xdenom, ydenom) */
 8443  g1 = C_s_a_u_i_integer_gcd(&a, 2, xdenom, ydenom);
 8444
 8445  /* xnorm = xnum * (ydenom/g1) */
 8446  ydenom_g1 = C_s_a_u_i_integer_quotient(&a, 2, ydenom, g1);
 8447  xnorm = C_s_a_u_i_integer_times(&a, 2, xnum, ydenom_g1);
 8448
 8449  /* ynorm = ynum * (xdenom/g1) */
 8450  xdenom_g1 = C_s_a_u_i_integer_quotient(&a, 2, xdenom, g1);
 8451  ynorm = C_s_a_u_i_integer_times(&a, 2, ynum, xdenom_g1);
 8452
 8453  /* norm_sum = xnorm [+-] ynorm */
 8454  norm_sum = plusmin_op(&a, 2, xnorm, ynorm);
 8455
 8456  /* g2 = gcd(norm_sum, g1) */
 8457  g2 = C_s_a_u_i_integer_gcd(&a, 2, norm_sum, g1);
 8458
 8459  /* res_num = norm_sum / g2 */
 8460  res_num = C_s_a_u_i_integer_quotient(ptr, 2, norm_sum, g2);
 8461  if (res_num == C_fix(0)) {
 8462    res_denom = C_fix(0); /* No need to calculate denom: we'll return 0 */
 8463  } else {
 8464    /* res_denom = xdenom_g1 * (ydenom / g2) */
 8465    C_word res_tmp_denom = C_s_a_u_i_integer_quotient(&a, 2, ydenom, g2);
 8466    res_denom = C_s_a_u_i_integer_times(ptr, 2, xdenom_g1, res_tmp_denom);
 8467
 8468    /* Ensure they're allocated in the correct place */
 8469    res_num = move_buffer_object(ptr, ab, res_num);
 8470    res_denom = move_buffer_object(ptr, ab, res_denom);
 8471    clear_buffer_object(ab, res_tmp_denom);
 8472  }
 8473
 8474  clear_buffer_object(ab, xdenom_g1);
 8475  clear_buffer_object(ab, ydenom_g1);
 8476  clear_buffer_object(ab, xnorm);
 8477  clear_buffer_object(ab, ynorm);
 8478  clear_buffer_object(ab, norm_sum);
 8479  clear_buffer_object(ab, g1);
 8480  clear_buffer_object(ab, g2);
 8481
 8482  switch (res_denom) {
 8483  case C_fix(0): return C_fix(0);
 8484  case C_fix(1): return res_num;
 8485  default: return C_ratnum(ptr, res_num, res_denom);
 8486  }
 8487}
 8488
 8489/* The maximum size this needs is that required to store a complex
 8490 * number result, where both real and imag parts consist of ratnums.
 8491 * The maximum size of those ratnums is if they consist of two "fix
 8492 * bignums", so we're looking at C_SIZEOF_CPLXNUM + C_SIZEOF_RATNUM *
 8493 * 2 + C_SIZEOF_FIX_BIGNUM * 4 = 29 words!
 8494 */
 8495C_regparm C_word
 8496C_s_a_i_plus(C_word **ptr, C_word n, C_word x, C_word y)
 8497{
 8498  if (x & C_FIXNUM_BIT) {
 8499    if (y & C_FIXNUM_BIT) {
 8500      return C_a_i_fixnum_plus(ptr, 2, x, y);
 8501    } else if (C_immediatep(y)) {
 8502      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", y);
 8503    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8504      return C_flonum(ptr, (double)C_unfix(x) + C_flonum_magnitude(y));
 8505    } else if (C_truep(C_bignump(y))) {
 8506      return C_s_a_u_i_integer_plus(ptr, 2, x, y);
 8507    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8508      return rat_plusmin_integer(ptr, y, x, C_s_a_u_i_integer_plus);
 8509    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8510      C_word real_sum = C_s_a_i_plus(ptr, 2, x, C_u_i_cplxnum_real(y)),
 8511             imag = C_u_i_cplxnum_imag(y);
 8512      if (C_truep(C_u_i_inexactp(real_sum)))
 8513        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8514      return C_cplxnum(ptr, real_sum, imag);
 8515    } else {
 8516      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", y);
 8517    }
 8518  } else if (C_immediatep(x)) {
 8519    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", x);
 8520  } else if (C_block_header(x) == C_FLONUM_TAG) {
 8521    if (y & C_FIXNUM_BIT) {
 8522      return C_flonum(ptr, C_flonum_magnitude(x) + (double)C_unfix(y));
 8523    } else if (C_immediatep(y)) {
 8524      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", y);
 8525    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8526      return C_a_i_flonum_plus(ptr, 2, x, y);
 8527    } else if (C_truep(C_bignump(y))) {
 8528      return C_flonum(ptr, C_flonum_magnitude(x)+C_bignum_to_double(y));
 8529    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8530      return C_s_a_i_plus(ptr, 2, x, C_a_i_exact_to_inexact(ptr, 1, y));
 8531    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8532      C_word real_sum = C_s_a_i_plus(ptr, 2, x, C_u_i_cplxnum_real(y)),
 8533             imag = C_u_i_cplxnum_imag(y);
 8534      if (C_truep(C_u_i_inexactp(real_sum)))
 8535        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8536      return C_cplxnum(ptr, real_sum, imag);
 8537    } else {
 8538      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", y);
 8539    }
 8540  } else if (C_truep(C_bignump(x))) {
 8541    if (y & C_FIXNUM_BIT) {
 8542      return C_s_a_u_i_integer_plus(ptr, 2, x, y);
 8543    } else if (C_immediatep(y)) {
 8544      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", y);
 8545    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8546      return C_flonum(ptr, C_bignum_to_double(x)+C_flonum_magnitude(y));
 8547    } else if (C_truep(C_bignump(y))) {
 8548      return C_s_a_u_i_integer_plus(ptr, 2, x, y);
 8549    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8550      return rat_plusmin_integer(ptr, y, x, C_s_a_u_i_integer_plus);
 8551    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8552      C_word real_sum = C_s_a_i_plus(ptr, 2, x, C_u_i_cplxnum_real(y)),
 8553             imag = C_u_i_cplxnum_imag(y);
 8554      if (C_truep(C_u_i_inexactp(real_sum)))
 8555        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8556      return C_cplxnum(ptr, real_sum, imag);
 8557    } else {
 8558      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", y);
 8559    }
 8560  } else if (C_block_header(x) == C_RATNUM_TAG) {
 8561    if (y & C_FIXNUM_BIT) {
 8562      return rat_plusmin_integer(ptr, x, y, C_s_a_u_i_integer_plus);
 8563    } else if (C_immediatep(y)) {
 8564      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", y);
 8565    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8566      return C_s_a_i_plus(ptr, 2, C_a_i_exact_to_inexact(ptr, 1, x), y);
 8567    } else if (C_truep(C_bignump(y))) {
 8568      return rat_plusmin_integer(ptr, x, y, C_s_a_u_i_integer_plus);
 8569    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8570      return rat_plusmin_rat(ptr, x, y, C_s_a_u_i_integer_plus);
 8571    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8572      C_word real_sum = C_s_a_i_plus(ptr, 2, x, C_u_i_cplxnum_real(y)),
 8573             imag = C_u_i_cplxnum_imag(y);
 8574      if (C_truep(C_u_i_inexactp(real_sum)))
 8575        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8576      return C_cplxnum(ptr, real_sum, imag);
 8577    } else {
 8578      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", y);
 8579    }
 8580  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 8581    if (!C_immediatep(y) && C_block_header(y) == C_CPLXNUM_TAG) {
 8582      C_word real_sum, imag_sum;
 8583      real_sum = C_s_a_i_plus(ptr, 2, C_u_i_cplxnum_real(x), C_u_i_cplxnum_real(y));
 8584      imag_sum = C_s_a_i_plus(ptr, 2, C_u_i_cplxnum_imag(x), C_u_i_cplxnum_imag(y));
 8585      if (C_truep(C_u_i_zerop2(imag_sum))) return real_sum;
 8586      else return C_cplxnum(ptr, real_sum, imag_sum);
 8587    } else {
 8588      C_word real_sum = C_s_a_i_plus(ptr, 2, C_u_i_cplxnum_real(x), y),
 8589             imag = C_u_i_cplxnum_imag(x);
 8590      if (C_truep(C_u_i_inexactp(real_sum)))
 8591        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8592      return C_cplxnum(ptr, real_sum, imag);
 8593    }
 8594  } else {
 8595    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", x);
 8596  }
 8597}
 8598
 8599C_regparm C_word
 8600C_s_a_u_i_integer_plus(C_word **ptr, C_word n, C_word x, C_word y)
 8601{
 8602  if ((x & y) & C_FIXNUM_BIT) {
 8603    return C_a_i_fixnum_plus(ptr, 2, x, y);
 8604  } else {
 8605    C_word ab[C_SIZEOF_FIX_BIGNUM * 2 + C_SIZEOF_BIGNUM_WRAPPER], *a = ab;
 8606    if (x & C_FIXNUM_BIT) x = C_a_u_i_fix_to_big(&a, x);
 8607    if (y & C_FIXNUM_BIT) y = C_a_u_i_fix_to_big(&a, y);
 8608
 8609    if (C_bignum_negativep(x)) {
 8610      if (C_bignum_negativep(y)) {
 8611        return bignum_plus_unsigned(ptr, x, y, C_SCHEME_TRUE);
 8612      } else {
 8613        return bignum_minus_unsigned(ptr, y, x);
 8614      }
 8615    } else {
 8616      if (C_bignum_negativep(y)) {
 8617        return bignum_minus_unsigned(ptr, x, y);
 8618      } else {
 8619        return bignum_plus_unsigned(ptr, x, y, C_SCHEME_FALSE);
 8620      }
 8621    }
 8622  }
 8623}
 8624
 8625void C_ccall C_plus(C_word c, C_word *av)
 8626{
 8627  /* C_word closure = av[ 0 ]; */
 8628  C_word k = av[ 1 ];
 8629  C_word next_val,
 8630    result = C_fix(0),
 8631    prev_result = result;
 8632  C_word ab[2][C_SIZEOF_CPLXNUM + C_SIZEOF_RATNUM*2 + C_SIZEOF_FIX_BIGNUM * 4], *a;
 8633
 8634  c -= 2;
 8635  av += 2;
 8636
 8637  while (c--) {
 8638    next_val = *(av++);
 8639    a = ab[c&1]; /* One may hold last iteration result, the other is unused */
 8640    result = C_s_a_i_plus(&a, 2, result, next_val);
 8641    result = move_buffer_object(&a, ab[(c+1)&1], result);
 8642    clear_buffer_object(ab[(c+1)&1], prev_result);
 8643    prev_result = result;
 8644  }
 8645
 8646  C_kontinue(k, result);
 8647}
 8648
 8649static C_word bignum_minus_unsigned(C_word **ptr, C_word x, C_word y)
 8650{
 8651  C_word res, size;
 8652  C_uword *scan_r, *end_r, *scan_y, *end_y, difference, digit;
 8653  int borrow = 0;
 8654
 8655  switch(bignum_cmp_unsigned(x, y)) {
 8656  case 0:	      /* x = y, return 0 */
 8657    return C_fix(0);
 8658  case -1:	      /* abs(x) < abs(y), return -(abs(y) - abs(x)) */
 8659    size = C_fix(C_bignum_size(y)); /* Maximum size of result is length of y. */
 8660    res = C_allocate_scratch_bignum(ptr, size, C_SCHEME_TRUE, C_SCHEME_FALSE);
 8661    size = y;
 8662    y = x;
 8663    x = size;
 8664    break;
 8665  case 1:	      /* abs(x) > abs(y), return abs(x) - abs(y) */
 8666  default:
 8667    size = C_fix(C_bignum_size(x)); /* Maximum size of result is length of x. */
 8668    res = C_allocate_scratch_bignum(ptr, size, C_SCHEME_FALSE, C_SCHEME_FALSE);
 8669    break;
 8670  }
 8671
 8672  scan_r = C_bignum_digits(res);
 8673  end_r = scan_r + C_bignum_size(res);
 8674  scan_y = C_bignum_digits(y);
 8675  end_y = scan_y + C_bignum_size(y);
 8676
 8677  bignum_digits_destructive_copy(res, x); /* See bignum_plus_unsigned */
 8678
 8679  /* Destructively subtract y's digits w/ borrow from and back into r. */
 8680  while (scan_y < end_y) {
 8681    digit = *scan_r;
 8682    if (borrow) {
 8683      difference = digit - *scan_y++ - 1;
 8684      borrow = difference >= digit;
 8685    } else {
 8686      difference = digit - *scan_y++;
 8687      borrow = difference > digit;
 8688    }
 8689    (*scan_r++) = difference;
 8690  }
 8691
 8692  /* The end of y, the smaller number.  Propagate borrow into the rest of x. */
 8693  while (borrow) {
 8694    digit = *scan_r;
 8695    difference = digit - borrow;
 8696    borrow = difference >= digit;
 8697    (*scan_r++) = difference;
 8698  }
 8699
 8700  assert(scan_r <= end_r);
 8701
 8702  return C_bignum_simplify(res);
 8703}
 8704
 8705/* Like C_s_a_i_plus, this needs at most 29 words */
 8706C_regparm C_word
 8707C_s_a_i_minus(C_word **ptr, C_word n, C_word x, C_word y)
 8708{
 8709  if (x & C_FIXNUM_BIT) {
 8710    if (y & C_FIXNUM_BIT) {
 8711      return C_a_i_fixnum_difference(ptr, 2, x, y);
 8712    } else if (C_immediatep(y)) {
 8713      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", y);
 8714    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8715      return C_flonum(ptr, (double)C_unfix(x) - C_flonum_magnitude(y));
 8716    } else if (C_truep(C_bignump(y))) {
 8717      return C_s_a_u_i_integer_minus(ptr, 2, x, y);
 8718    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8719      return integer_minus_rat(ptr, x, y);
 8720    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8721      C_word real_diff = C_s_a_i_minus(ptr, 2, x, C_u_i_cplxnum_real(y)),
 8722             imag = C_s_a_i_negate(ptr, 1, C_u_i_cplxnum_imag(y));
 8723      if (C_truep(C_u_i_inexactp(real_diff)))
 8724        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8725      return C_cplxnum(ptr, real_diff, imag);
 8726    } else {
 8727      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", y);
 8728    }
 8729  } else if (C_immediatep(x)) {
 8730    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", x);
 8731  } else if (C_block_header(x) == C_FLONUM_TAG) {
 8732    if (y & C_FIXNUM_BIT) {
 8733      return C_flonum(ptr, C_flonum_magnitude(x) - (double)C_unfix(y));
 8734    } else if (C_immediatep(y)) {
 8735      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", y);
 8736    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8737      return C_a_i_flonum_difference(ptr, 2, x, y);
 8738    } else if (C_truep(C_bignump(y))) {
 8739      return C_flonum(ptr, C_flonum_magnitude(x)-C_bignum_to_double(y));
 8740    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8741      return C_s_a_i_minus(ptr, 2, x, C_a_i_exact_to_inexact(ptr, 1, y));
 8742    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8743      C_word real_diff = C_s_a_i_minus(ptr, 2, x, C_u_i_cplxnum_real(y)),
 8744             imag = C_s_a_i_negate(ptr, 1, C_u_i_cplxnum_imag(y));
 8745      if (C_truep(C_u_i_inexactp(real_diff)))
 8746        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8747      return C_cplxnum(ptr, real_diff, imag);
 8748    } else {
 8749      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", y);
 8750    }
 8751  } else if (C_truep(C_bignump(x))) {
 8752    if (y & C_FIXNUM_BIT) {
 8753      return C_s_a_u_i_integer_minus(ptr, 2, x, y);
 8754    } else if (C_immediatep(y)) {
 8755      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", y);
 8756    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8757      return C_flonum(ptr, C_bignum_to_double(x)-C_flonum_magnitude(y));
 8758    } else if (C_truep(C_bignump(y))) {
 8759      return C_s_a_u_i_integer_minus(ptr, 2, x, y);
 8760    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8761      return integer_minus_rat(ptr, x, y);
 8762    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8763      C_word real_diff = C_s_a_i_minus(ptr, 2, x, C_u_i_cplxnum_real(y)),
 8764             imag = C_s_a_i_negate(ptr, 1, C_u_i_cplxnum_imag(y));
 8765      if (C_truep(C_u_i_inexactp(real_diff)))
 8766        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8767      return C_cplxnum(ptr, real_diff, imag);
 8768    } else {
 8769      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", y);
 8770    }
 8771  } else if (C_block_header(x) == C_RATNUM_TAG) {
 8772    if (y & C_FIXNUM_BIT) {
 8773      return rat_plusmin_integer(ptr, x, y, C_s_a_u_i_integer_minus);
 8774    } else if (C_immediatep(y)) {
 8775      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", y);
 8776    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8777      return C_s_a_i_minus(ptr, 2, C_a_i_exact_to_inexact(ptr, 1, x), y);
 8778    } else if (C_truep(C_bignump(y))) {
 8779      return rat_plusmin_integer(ptr, x, y, C_s_a_u_i_integer_minus);
 8780    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8781      return rat_plusmin_rat(ptr, x, y, C_s_a_u_i_integer_minus);
 8782    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8783      C_word real_diff = C_s_a_i_minus(ptr, 2, x, C_u_i_cplxnum_real(y)),
 8784             imag = C_s_a_i_negate(ptr, 1, C_u_i_cplxnum_imag(y));
 8785      if (C_truep(C_u_i_inexactp(real_diff)))
 8786        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8787      return C_cplxnum(ptr, real_diff, imag);
 8788    } else {
 8789      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", y);
 8790    }
 8791  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 8792    if (!C_immediatep(y) && C_block_header(y) == C_CPLXNUM_TAG) {
 8793      C_word real_diff, imag_diff;
 8794      real_diff = C_s_a_i_minus(ptr,2,C_u_i_cplxnum_real(x),C_u_i_cplxnum_real(y));
 8795      imag_diff = C_s_a_i_minus(ptr,2,C_u_i_cplxnum_imag(x),C_u_i_cplxnum_imag(y));
 8796      if (C_truep(C_u_i_zerop2(imag_diff))) return real_diff;
 8797      else return C_cplxnum(ptr, real_diff, imag_diff);
 8798    } else {
 8799      C_word real_diff = C_s_a_i_minus(ptr, 2, C_u_i_cplxnum_real(x), y),
 8800             imag = C_u_i_cplxnum_imag(x);
 8801      if (C_truep(C_u_i_inexactp(real_diff)))
 8802        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8803      return C_cplxnum(ptr, real_diff, imag);
 8804    }
 8805  } else {
 8806    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", x);
 8807  }
 8808}
 8809
 8810C_regparm C_word
 8811C_s_a_u_i_integer_minus(C_word **ptr, C_word n, C_word x, C_word y)
 8812{
 8813  if ((x & y) & C_FIXNUM_BIT) {
 8814    return C_a_i_fixnum_difference(ptr, 2, x, y);
 8815  } else {
 8816    C_word ab[C_SIZEOF_FIX_BIGNUM * 2 + C_SIZEOF_BIGNUM_WRAPPER], *a = ab;
 8817    if (x & C_FIXNUM_BIT) x = C_a_u_i_fix_to_big(&a, x);
 8818    if (y & C_FIXNUM_BIT) y = C_a_u_i_fix_to_big(&a, y);
 8819
 8820    if (C_bignum_negativep(x)) {
 8821      if (C_bignum_negativep(y)) {
 8822        return bignum_minus_unsigned(ptr, y, x);
 8823      } else {
 8824        return bignum_plus_unsigned(ptr, x, y, C_SCHEME_TRUE);
 8825      }
 8826    } else {
 8827      if (C_bignum_negativep(y)) {
 8828        return bignum_plus_unsigned(ptr, x, y, C_SCHEME_FALSE);
 8829      } else {
 8830        return bignum_minus_unsigned(ptr, x, y);
 8831      }
 8832    }
 8833  }
 8834}
 8835
 8836void C_ccall C_minus(C_word c, C_word *av)
 8837{
 8838  /* C_word closure = av[ 0 ]; */
 8839  C_word k = av[ 1 ];
 8840  C_word next_val, result, prev_result;
 8841  C_word ab[2][C_SIZEOF_CPLXNUM + C_SIZEOF_RATNUM*2 + C_SIZEOF_FIX_BIGNUM * 4], *a;
 8842
 8843  if (c < 3) {
 8844    C_bad_min_argc(c, 3);
 8845  } else if (c == 3) {
 8846    a = ab[0];
 8847    C_kontinue(k, C_s_a_i_negate(&a, 1, av[ 2 ]));
 8848  } else {
 8849    prev_result = result = av[ 2 ];
 8850    c -= 3;
 8851    av += 3;
 8852
 8853    while (c--) {
 8854      next_val = *(av++);
 8855      a = ab[c&1]; /* One may hold last iteration result, the other is unused */
 8856      result = C_s_a_i_minus(&a, 2, result, next_val);
 8857      result = move_buffer_object(&a, ab[(c+1)&1], result);
 8858      clear_buffer_object(ab[(c+1)&1], prev_result);
 8859      prev_result = result;
 8860    }
 8861
 8862    C_kontinue(k, result);
 8863  }
 8864}
 8865
 8866
 8867static C_regparm void
 8868integer_divrem(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r)
 8869{
 8870  if (!(y & C_FIXNUM_BIT)) { /* y is bignum. */
 8871    if (x & C_FIXNUM_BIT) {
 8872      /* abs(x) < abs(y), so it will always be [0, x] except for this case: */
 8873      if (x == C_fix(C_MOST_NEGATIVE_FIXNUM) &&
 8874          C_bignum_negated_fitsinfixnump(y)) {
 8875        if (q != NULL) *q = C_fix(-1);
 8876        if (r != NULL) *r = C_fix(0);
 8877      } else {
 8878        if (q != NULL) *q = C_fix(0);
 8879        if (r != NULL) *r = x;
 8880      }
 8881    } else {
 8882      bignum_divrem(ptr, x, y, q, r);
 8883    }
 8884  } else if (x & C_FIXNUM_BIT) { /* both x and y are fixnum. */
 8885    if (q != NULL) *q = C_a_i_fixnum_quotient_checked(ptr, 2, x, y);
 8886    if (r != NULL) *r = C_i_fixnum_remainder_checked(x, y);
 8887  } else { /* x is bignum, y is fixnum. */
 8888    C_word absy = (y & C_INT_SIGN_BIT) ? -C_unfix(y) : C_unfix(y);
 8889
 8890    if (y == C_fix(1)) {
 8891      if (q != NULL) *q = x;
 8892      if (r != NULL) *r = C_fix(0);
 8893    } else if (y == C_fix(-1)) {
 8894      if (q != NULL) *q = C_s_a_u_i_integer_negate(ptr, 1, x);
 8895      if (r != NULL) *r = C_fix(0);
 8896    } else if (C_fitsinbignumhalfdigitp(absy) ||
 8897               ((((C_uword)1 << (C_ilen(absy)-1)) == absy) &&
 8898                C_fitsinfixnump(absy))) {
 8899      assert(y != C_fix(0)); /* _must_ be checked by caller */
 8900      if (q != NULL) {
 8901        bignum_destructive_divide_unsigned_small(ptr, x, y, q, r);
 8902      } else { /* We assume r isn't NULL here (that makes no sense) */
 8903        C_word rem;
 8904	C_uword next_power = (C_uword)1 << (C_ilen(absy)-1);
 8905
 8906	if (next_power == absy) { /* Is absy a power of two? */
 8907          rem = *(C_bignum_digits(x)) & (next_power - 1);
 8908        } else { /* Too bad, we have to do some real work */
 8909          rem = bignum_remainder_unsigned_halfdigit(x, absy);
 8910	}
 8911        *r = C_bignum_negativep(x) ? C_fix(-rem) : C_fix(rem);
 8912      }
 8913    } else {			/* Just divide it as two bignums */
 8914      C_word ab[C_SIZEOF_FIX_BIGNUM], *a = ab;
 8915      bignum_divrem(ptr, x, C_a_u_i_fix_to_big(&a, y), q, r);
 8916      if (q != NULL) *q = move_buffer_object(ptr, ab, *q);
 8917      if (r != NULL) *r = move_buffer_object(ptr, ab, *r);
 8918    }
 8919  }
 8920}
 8921
 8922/* This _always_ needs two bignum wrappers in ptr! */
 8923static C_regparm void
 8924bignum_divrem(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r)
 8925{
 8926  C_word q_negp = C_mk_bool(C_bignum_negativep(y) != C_bignum_negativep(x)),
 8927         r_negp = C_mk_bool(C_bignum_negativep(x)), res, size;
 8928
 8929  switch(bignum_cmp_unsigned(x, y)) {
 8930  case 0:
 8931    if (q != NULL) *q = C_truep(q_negp) ? C_fix(-1) : C_fix(1);
 8932    if (r != NULL) *r = C_fix(0);
 8933    break;
 8934  case -1:
 8935    if (q != NULL) *q = C_fix(0);
 8936    if (r != NULL) *r = x;
 8937    break;
 8938  case 1:
 8939  default:
 8940    res = C_SCHEME_FALSE;
 8941    size = C_bignum_size(x) - C_bignum_size(y);
 8942    if (C_bignum_size(y) > C_BURNIKEL_ZIEGLER_THRESHOLD &&
 8943        size > C_BURNIKEL_ZIEGLER_THRESHOLD) {
 8944      res = bignum_divide_burnikel_ziegler(ptr, x, y, q, r);
 8945    }
 8946
 8947    if (!C_truep(res)) {
 8948      bignum_divide_unsigned(ptr, x, y, q, q_negp, r, r_negp);
 8949      if (q != NULL) *q = C_bignum_simplify(*q);
 8950      if (r != NULL) *r = C_bignum_simplify(*r);
 8951    }
 8952    break;
 8953  }
 8954}
 8955
 8956/* Burnikel-Ziegler recursive division: Split high number (x) in three
 8957 * or four parts and divide by the lowest number (y), split in two
 8958 * parts.  There are descriptions in [MpNT, 4.2], [MCA, 1.4.3] and the
 8959 * paper "Fast Recursive Division" by Christoph Burnikel & Joachim
 8960 * Ziegler is freely available.  There is also a description in Karl
 8961 * Hasselstrom's thesis "Fast Division of Integers".
 8962 *
 8963 * The complexity of this is supposedly O(r*s^{log(3)-1} + r*log(s)),
 8964 * where s is the length of x, and r is the length of y (in digits).
 8965 *
 8966 * TODO: See if it's worthwhile to implement "division without remainder"
 8967 * from the Burnikel-Ziegler paper.
 8968 */
 8969static C_regparm C_word
 8970bignum_divide_burnikel_ziegler(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r)
 8971{
 8972  C_word ab[C_SIZEOF_FIX_BIGNUM*9], *a = ab,
 8973         lab[2][C_SIZEOF_FIX_BIGNUM*10], *la,
 8974         q_negp = (C_bignum_negativep(y) ? C_mk_nbool(C_bignum_negativep(x)) :
 8975                   C_mk_bool(C_bignum_negativep(x))),
 8976         r_negp = C_mk_bool(C_bignum_negativep(x)), s, m, n, i, j, l, shift,
 8977         yhi, ylo, zi, zi_orig, newx, newy, quot, qi, ri;
 8978
 8979  /* Ran out of stack?  Fall back to non-recursive division */
 8980  C_stack_check1(return C_SCHEME_FALSE);
 8981
 8982  x = C_s_a_u_i_integer_abs(&a, 1, x);
 8983  y = C_s_a_u_i_integer_abs(&a, 1, y);
 8984
 8985  /* Define m as min{2^k|(2^k)*BURNIKEL_ZIEGLER_DIFF_THRESHOLD > s}
 8986   * This ensures we shift as little as possible (less pressure
 8987   * on the GC) while maintaining a power of two until we drop
 8988   * below the threshold, so we can always split N in half.
 8989   */
 8990  s = C_bignum_size(y);
 8991  m = 1 << C_ilen(s / C_BURNIKEL_ZIEGLER_THRESHOLD);
 8992  j = (s+m-1) / m;              /* j = s/m, rounded up */
 8993  n = j * m;
 8994
 8995  shift = (C_BIGNUM_DIGIT_LENGTH * n) - integer_length_abs(y);
 8996  newx = C_s_a_i_arithmetic_shift(&a, 2, x, C_fix(shift));
 8997  newy = C_s_a_i_arithmetic_shift(&a, 2, y, C_fix(shift));
 8998  if (shift != 0) {
 8999    clear_buffer_object(ab, x);
 9000    clear_buffer_object(ab, y);
 9001  }
 9002  x = newx;
 9003  y = newy;
 9004
 9005  /* l needs to be the smallest value so that a < base^{l*n}/2 */
 9006  l = (C_bignum_size(x) + n) / n;
 9007  if ((C_BIGNUM_DIGIT_LENGTH * l) == integer_length_abs(x)) l++;
 9008  l = nmax(l, 2);
 9009
 9010  yhi = bignum_extract_digits(&a, 3, y, C_fix(n >> 1), C_SCHEME_FALSE);
 9011  ylo = bignum_extract_digits(&a, 3, y, C_fix(0), C_fix(n >> 1));
 9012
 9013  s = (l - 2) * n * C_BIGNUM_DIGIT_LENGTH;
 9014  zi_orig = zi = C_s_a_i_arithmetic_shift(&a, 2, x, C_fix(-s));
 9015  quot = C_fix(0);
 9016
 9017  for(i = l - 2; i >= 0; --i) {
 9018    la = lab[i&1];
 9019
 9020    burnikel_ziegler_2n_div_1n(&la, zi, y, yhi, ylo, C_fix(n), &qi, &ri);
 9021
 9022    newx = C_s_a_i_arithmetic_shift(&la, 2, quot, C_fix(n*C_BIGNUM_DIGIT_LENGTH));
 9023    clear_buffer_object(lab, quot);
 9024    quot = C_s_a_u_i_integer_plus(&la, 2, newx, qi);
 9025    move_buffer_object(&la, lab[(i+1)&1], quot);
 9026    clear_buffer_object(lab, newx);
 9027    clear_buffer_object(lab, qi);
 9028
 9029    if (i > 0) {  /* Set z_{i-1} = [r{i}, x{i-1}] */
 9030      newx = bignum_extract_digits(&la, 3, x, C_fix(n * (i-1)), C_fix(n * i));
 9031      newy = C_s_a_i_arithmetic_shift(&la, 2, ri, C_fix(n*C_BIGNUM_DIGIT_LENGTH));
 9032      clear_buffer_object(lab, zi);
 9033      zi = C_s_a_u_i_integer_plus(&la, 2, newx, newy);
 9034      move_buffer_object(&la, lab[(i+1)&1], zi);
 9035      move_buffer_object(&la, lab[(i+1)&1], quot);
 9036      clear_buffer_object(lab, newx);
 9037      clear_buffer_object(lab, newy);
 9038      clear_buffer_object(lab, ri);
 9039    }
 9040  }
 9041  clear_buffer_object(ab, x);
 9042  clear_buffer_object(ab, y);
 9043  clear_buffer_object(ab, yhi);
 9044  clear_buffer_object(ab, ylo);
 9045  clear_buffer_object(ab, zi_orig);
 9046  clear_buffer_object(lab, zi);
 9047
 9048  if (q != NULL) {
 9049    if (C_truep(q_negp)) {
 9050      newx = C_s_a_u_i_integer_negate(&la, 1, quot);
 9051      clear_buffer_object(lab, quot);
 9052      quot = newx;
 9053    }
 9054    *q = move_buffer_object(ptr, lab, quot);
 9055  }
 9056  clear_buffer_object(lab, quot);
 9057
 9058  if (r != NULL) {
 9059    newx = C_s_a_i_arithmetic_shift(&la, 2, ri, C_fix(-shift));
 9060    if (C_truep(r_negp)) {
 9061      newy = C_s_a_u_i_integer_negate(ptr, 1, newx);
 9062      clear_buffer_object(lab, newx);
 9063      newx = newy;
 9064    }
 9065    *r = move_buffer_object(ptr, lab, newx);
 9066  }
 9067  clear_buffer_object(lab, ri);
 9068
 9069  return C_SCHEME_TRUE;
 9070}
 9071
 9072static C_regparm void
 9073burnikel_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)
 9074{
 9075  C_word kab[C_SIZEOF_FIX_BIGNUM*6 + C_SIZEOF_BIGNUM(2)], *ka = kab,
 9076         lab[2][C_SIZEOF_FIX_BIGNUM*4], *la,
 9077         size, tmp, less, qhat, rhat, r1, r1a3, i = 0;
 9078
 9079  size = C_unfix(n) * C_BIGNUM_DIGIT_LENGTH;
 9080  tmp = C_s_a_i_arithmetic_shift(&ka, 2, a12, C_fix(-size));
 9081  less = C_i_integer_lessp(tmp, b1); /* a1 < b1 ? */
 9082  clear_buffer_object(kab, tmp);
 9083
 9084  if (C_truep(less)) {
 9085    C_word atmpb[C_SIZEOF_FIX_BIGNUM*2], *atmp = atmpb, b11, b12, halfn;
 9086
 9087    halfn = C_fix(C_unfix(n) >> 1);
 9088    b11 = bignum_extract_digits(&atmp, 3, b1, halfn, C_SCHEME_FALSE);
 9089    b12 = bignum_extract_digits(&atmp, 3, b1, C_fix(0), halfn);
 9090
 9091    burnikel_ziegler_2n_div_1n(&ka, a12, b1, b11, b12, n, &qhat, &r1);
 9092    qhat = move_buffer_object(&ka, atmpb, qhat);
 9093    r1 = move_buffer_object(&ka, atmpb, r1);
 9094
 9095    clear_buffer_object(atmpb, b11);
 9096    clear_buffer_object(atmpb, b12);
 9097  } else {
 9098    C_word atmpb[C_SIZEOF_FIX_BIGNUM*5], *atmp = atmpb, tmp2;
 9099
 9100    tmp = C_s_a_i_arithmetic_shift(&atmp, 2, C_fix(1), C_fix(size));
 9101    qhat = C_s_a_u_i_integer_minus(&ka, 2, tmp, C_fix(1));  /* B^n - 1 */
 9102    qhat = move_buffer_object(&ka, atmpb, qhat);
 9103    clear_buffer_object(atmpb, tmp);
 9104
 9105    /* r1 = (a12 - b1*B^n) + b1 */
 9106    tmp = C_s_a_i_arithmetic_shift(&atmp, 2, b1, C_fix(size));
 9107    tmp2 = C_s_a_u_i_integer_minus(&atmp, 2, a12, tmp);
 9108    r1 = C_s_a_u_i_integer_plus(&ka, 2, tmp2, b1);
 9109    r1 = move_buffer_object(&ka, atmpb, r1);
 9110    clear_buffer_object(atmpb, tmp);
 9111    clear_buffer_object(atmpb, tmp2);
 9112  }
 9113
 9114  tmp = C_s_a_i_arithmetic_shift(&ka, 2, r1, C_fix(size));
 9115  clear_buffer_object(kab, r1);
 9116  r1a3 = C_s_a_u_i_integer_plus(&ka, 2, tmp, a3);
 9117  b2 = C_s_a_u_i_integer_times(&ka, 2, qhat, b2);
 9118
 9119  la = lab[0];
 9120  rhat = C_s_a_u_i_integer_minus(&la, 2, r1a3, b2);
 9121  rhat = move_buffer_object(&la, kab, rhat);
 9122  qhat = move_buffer_object(&la, kab, qhat);
 9123
 9124  clear_buffer_object(kab, tmp);
 9125  clear_buffer_object(kab, r1a3);
 9126  clear_buffer_object(kab, b2);
 9127
 9128  while(C_truep(C_i_negativep(rhat))) {
 9129    la = lab[(++i)&1];
 9130    /* rhat += b */
 9131    r1 = C_s_a_u_i_integer_plus(&la, 2, rhat, b);
 9132    tmp = move_buffer_object(&la, lab[(i-1)&1], r1);
 9133    clear_buffer_object(lab[(i-1)&1], r1);
 9134    clear_buffer_object(lab[(i-1)&1], rhat);
 9135    clear_buffer_object(kab, rhat);
 9136    rhat = tmp;
 9137
 9138    /* qhat -= 1 */
 9139    r1 = C_s_a_u_i_integer_minus(&la, 2, qhat, C_fix(1));
 9140    tmp = move_buffer_object(&la, lab[(i-1)&1], r1);
 9141    clear_buffer_object(lab[(i-1)&1], r1);
 9142    clear_buffer_object(lab[(i-1)&1], qhat);
 9143    clear_buffer_object(kab, qhat);
 9144    qhat = tmp;
 9145  }
 9146
 9147  if (q != NULL) *q = move_buffer_object(ptr, lab, qhat);
 9148  if (r != NULL) *r = move_buffer_object(ptr, lab, rhat);
 9149  clear_buffer_object(lab, qhat);
 9150  clear_buffer_object(lab, rhat);
 9151}
 9152
 9153static C_regparm void
 9154burnikel_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)
 9155{
 9156  C_word kab[2][C_SIZEOF_FIX_BIGNUM*7], *ka, a12, a3, a4,
 9157         q1 = C_fix(0), r1, q2 = C_fix(0), r2, *qp;
 9158  int stack_full = 0;
 9159
 9160  C_stack_check1(stack_full = 1);
 9161
 9162  n = C_unfix(n);
 9163  if (stack_full || (n & 1) || (n < C_BURNIKEL_ZIEGLER_THRESHOLD)) {
 9164    integer_divrem(ptr, a, b, q, r);
 9165  } else {
 9166    ka = kab[0];
 9167    a12 = bignum_extract_digits(&ka, 3, a, C_fix(n), C_SCHEME_FALSE);
 9168    a3 = bignum_extract_digits(&ka, 3, a, C_fix(n >> 1), C_fix(n));
 9169
 9170    qp = (q == NULL) ? NULL : &q1;
 9171    ka = kab[1];
 9172    burnikel_ziegler_3n_div_2n(&ka, a12, a3, b, b1, b2, C_fix(n >> 1), qp, &r1);
 9173    q1 = move_buffer_object(&ka, kab[0], q1);
 9174    r1 = move_buffer_object(&ka, kab[0], r1);
 9175    clear_buffer_object(kab[0], a12);
 9176    clear_buffer_object(kab[0], a3);
 9177
 9178    a4 = bignum_extract_digits(&ka, 3, a, C_fix(0), C_fix(n >> 1));
 9179
 9180    qp = (q == NULL) ? NULL : &q2;
 9181    ka = kab[0];
 9182    burnikel_ziegler_3n_div_2n(&ka, r1, a4, b, b1, b2, C_fix(n >> 1), qp, r);
 9183    if (r != NULL) *r = move_buffer_object(ptr, kab[0], *r);
 9184    clear_buffer_object(kab[1], r1);
 9185
 9186    if (q != NULL) {
 9187      C_word halfn_bits = (n >> 1) * C_BIGNUM_DIGIT_LENGTH;
 9188      r1 = C_s_a_i_arithmetic_shift(&ka, 2, q1, C_fix(halfn_bits));
 9189      *q = C_s_a_i_plus(ptr, 2, r1, q2); /* q = [q1, q2] */
 9190      *q = move_buffer_object(ptr, kab[0], *q);
 9191      clear_buffer_object(kab[0], r1);
 9192      clear_buffer_object(kab[1], q1);
 9193      clear_buffer_object(kab[0], q2);
 9194    }
 9195    clear_buffer_object(kab[1], a4);
 9196  }
 9197}
 9198
 9199
 9200static C_regparm C_word bignum_remainder_unsigned_halfdigit(C_word x, C_word y)
 9201{
 9202  C_uword *start = C_bignum_digits(x),
 9203          *scan = start + C_bignum_size(x),
 9204          rem = 0, two_digits;
 9205
 9206  assert((y > 1) && (C_fitsinbignumhalfdigitp(y)));
 9207  while (start < scan) {
 9208    two_digits = (*--scan);
 9209    rem = C_BIGNUM_DIGIT_COMBINE(rem, C_BIGNUM_DIGIT_HI_HALF(two_digits)) % y;
 9210    rem = C_BIGNUM_DIGIT_COMBINE(rem, C_BIGNUM_DIGIT_LO_HALF(two_digits)) % y;
 9211  }
 9212  return rem;
 9213}
 9214
 9215/* There doesn't seem to be a way to return two values from inline functions */
 9216void C_ccall C_quotient_and_remainder(C_word c, C_word *av)
 9217{
 9218  C_word ab[C_SIZEOF_FIX_BIGNUM*4+C_SIZEOF_FLONUM*2], *a = ab,
 9219    nx = C_SCHEME_FALSE, ny = C_SCHEME_FALSE,
 9220    q, r, k, x, y;
 9221
 9222  if (c != 4) C_bad_argc_2(c, 4, av[ 0 ]);
 9223
 9224  k = av[ 1 ];
 9225  x = av[ 2 ];
 9226  y = av[ 3 ];
 9227
 9228  if (!C_truep(C_i_integerp(x)))
 9229    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "quotient&remainder", x);
 9230  if (!C_truep(C_i_integerp(y)))
 9231    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "quotient&remainder", y);
 9232  if (C_truep(C_i_zerop(y))) C_div_by_zero_error("quotient&remainder");
 9233
 9234  if (C_truep(C_i_flonump(x))) {
 9235    if C_truep(C_i_flonump(y)) {
 9236      double dx = C_flonum_magnitude(x), dy = C_flonum_magnitude(y), tmp;
 9237
 9238      C_modf(dx / dy, &tmp);
 9239      q = C_flonum(&a, tmp);
 9240      r = C_flonum(&a, dx - tmp * dy);
 9241      /* reuse av */
 9242      av[ 0 ] = C_SCHEME_UNDEFINED;
 9243      /* av[ 1 ] = k; */ /* stays the same */
 9244      av[ 2 ] = q;
 9245      av[ 3 ] = r;
 9246      C_values(4, av);
 9247    }
 9248    x = nx = C_s_a_u_i_flo_to_int(&a, 1, x);
 9249  }
 9250  if (C_truep(C_i_flonump(y))) {
 9251    y = ny = C_s_a_u_i_flo_to_int(&a, 1, y);
 9252  }
 9253
 9254  integer_divrem(&a, x, y, &q, &r);
 9255
 9256  if (C_truep(nx) || C_truep(ny)) {
 9257    C_word newq, newr;
 9258    newq = C_a_i_exact_to_inexact(&a, 1, q);
 9259    newr = C_a_i_exact_to_inexact(&a, 1, r);
 9260    clear_buffer_object(ab, q);
 9261    clear_buffer_object(ab, r);
 9262    q = newq;
 9263    r = newr;
 9264
 9265    clear_buffer_object(ab, nx);
 9266    clear_buffer_object(ab, ny);
 9267  }
 9268  /* reuse av */
 9269  av[ 0 ] = C_SCHEME_UNDEFINED;
 9270  /* av[ 1 ] = k; */ /* stays the same */
 9271  av[ 2 ] = q;
 9272  av[ 3 ] = r;
 9273  C_values(4, av);
 9274}
 9275
 9276void C_ccall C_u_integer_quotient_and_remainder(C_word c, C_word *av)
 9277{
 9278  C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, q, r;
 9279
 9280  if (av[ 3 ] == C_fix(0)) C_div_by_zero_error("quotient&remainder");
 9281
 9282  integer_divrem(&a, av[ 2 ], av[ 3 ], &q, &r);
 9283
 9284  /* reuse av */
 9285  av[ 0 ] = C_SCHEME_UNDEFINED;
 9286  /* av[ 1 ] = k; */ /* stays the same */
 9287  av[ 2 ] = q;
 9288  av[ 3 ] = r;
 9289  C_values(4, av);
 9290}
 9291
 9292C_regparm C_word
 9293C_s_a_i_remainder(C_word **ptr, C_word n, C_word x, C_word y)
 9294{
 9295  C_word ab[C_SIZEOF_FIX_BIGNUM*4+C_SIZEOF_FLONUM*2], *a = ab, r,
 9296         nx = C_SCHEME_FALSE, ny = C_SCHEME_FALSE;
 9297
 9298  if (!C_truep(C_i_integerp(x)))
 9299    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "remainder", x);
 9300  if (!C_truep(C_i_integerp(y)))
 9301    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "remainder", y);
 9302  if (C_truep(C_i_zerop(y))) C_div_by_zero_error("remainder");
 9303
 9304  if (C_truep(C_i_flonump(x))) {
 9305    if C_truep(C_i_flonump(y)) {
 9306      double dx = C_flonum_magnitude(x), dy = C_flonum_magnitude(y), tmp;
 9307
 9308      C_modf(dx / dy, &tmp);
 9309      return C_flonum(ptr, dx - tmp * dy);
 9310    }
 9311    x = nx = C_s_a_u_i_flo_to_int(&a, 1, x);
 9312  }
 9313  if (C_truep(C_i_flonump(y))) {
 9314    y = ny = C_s_a_u_i_flo_to_int(&a, 1, y);
 9315  }
 9316
 9317  integer_divrem(&a, x, y, NULL, &r);
 9318
 9319  if (C_truep(nx) || C_truep(ny)) {
 9320    C_word newr = C_a_i_exact_to_inexact(ptr, 1, r);
 9321    clear_buffer_object(ab, r);
 9322    r = newr;
 9323
 9324    clear_buffer_object(ab, nx);
 9325    clear_buffer_object(ab, ny);
 9326  }
 9327  return move_buffer_object(ptr, ab, r);
 9328}
 9329
 9330C_regparm C_word
 9331C_s_a_u_i_integer_remainder(C_word **ptr, C_word n, C_word x, C_word y)
 9332{
 9333  C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, r;
 9334  if (y == C_fix(0)) C_div_by_zero_error("remainder");
 9335  integer_divrem(&a, x, y, NULL, &r);
 9336  return move_buffer_object(ptr, ab, r);
 9337}
 9338
 9339/* Modulo's sign follows y (whereas remainder's sign follows x) */
 9340C_regparm C_word
 9341C_s_a_i_modulo(C_word **ptr, C_word n, C_word x, C_word y)
 9342{
 9343  C_word ab[C_SIZEOF_FIX_BIGNUM], *a = ab, r,
 9344         nx = C_SCHEME_FALSE, ny = C_SCHEME_FALSE;
 9345
 9346  if (!C_truep(C_i_integerp(x)))
 9347    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "modulo", x);
 9348  if (!C_truep(C_i_integerp(y)))
 9349    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "modulo", y);
 9350  if (C_truep(C_i_zerop(y))) C_div_by_zero_error("modulo");
 9351
 9352  if (C_truep(C_i_flonump(x))) {
 9353    if C_truep(C_i_flonump(y)) {
 9354      double dx = C_flonum_magnitude(x), dy = C_flonum_magnitude(y), tmp;
 9355
 9356      C_modf(dx / dy, &tmp);
 9357      tmp = dx - tmp * dy;
 9358      if ((dx > 0.0) != (dy > 0.0) && tmp != 0.0) {
 9359        return C_flonum(ptr, tmp + dy);
 9360      } else {
 9361        return C_flonum(ptr, tmp);
 9362      }
 9363    }
 9364    x = nx = C_s_a_u_i_flo_to_int(&a, 1, x);
 9365  }
 9366  if (C_truep(C_i_flonump(y))) {
 9367    y = ny = C_s_a_u_i_flo_to_int(&a, 1, y);
 9368  }
 9369
 9370  integer_divrem(&a, x, y, NULL, &r);
 9371  if (C_i_positivep(y) != C_i_positivep(r) && r != C_fix(0)) {
 9372    C_word m = C_s_a_i_plus(ptr, 2, r, y);
 9373    m = move_buffer_object(ptr, ab, m);
 9374    clear_buffer_object(ab, r);
 9375    r = m;
 9376  }
 9377
 9378  if (C_truep(nx) || C_truep(ny)) {
 9379    C_word newr = C_a_i_exact_to_inexact(ptr, 1, r);
 9380    clear_buffer_object(ab, r);
 9381    r = newr;
 9382
 9383    clear_buffer_object(ab, nx);
 9384    clear_buffer_object(ab, ny);
 9385  }
 9386
 9387  return move_buffer_object(ptr, ab, r);
 9388}
 9389
 9390C_regparm C_word
 9391C_s_a_u_i_integer_modulo(C_word **ptr, C_word n, C_word x, C_word y)
 9392{
 9393  C_word ab[C_SIZEOF_FIX_BIGNUM], *a = ab, r;
 9394  if (y == C_fix(0)) C_div_by_zero_error("modulo");
 9395
 9396  integer_divrem(&a, x, y, NULL, &r);
 9397  if (C_i_positivep(y) != C_i_positivep(r) && r != C_fix(0)) {
 9398    C_word m = C_s_a_u_i_integer_plus(ptr, 2, r, y);
 9399    m = move_buffer_object(ptr, ab, m);
 9400    clear_buffer_object(ab, r);
 9401    r = m;
 9402  }
 9403  return move_buffer_object(ptr, ab, r);
 9404}
 9405
 9406C_regparm C_word
 9407C_s_a_i_quotient(C_word **ptr, C_word n, C_word x, C_word y)
 9408{
 9409  C_word ab[C_SIZEOF_FIX_BIGNUM*4+C_SIZEOF_FLONUM*2], *a = ab, q,
 9410         nx = C_SCHEME_FALSE, ny = C_SCHEME_FALSE;
 9411
 9412  if (!C_truep(C_i_integerp(x)))
 9413    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "quotient", x);
 9414  if (!C_truep(C_i_integerp(y)))
 9415    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "quotient", y);
 9416  if (C_truep(C_i_zerop(y))) C_div_by_zero_error("quotient");
 9417
 9418  if (C_truep(C_i_flonump(x))) {
 9419    if C_truep(C_i_flonump(y)) {
 9420      double dx = C_flonum_magnitude(x), dy = C_flonum_magnitude(y), tmp;
 9421
 9422      C_modf(dx / dy, &tmp);
 9423      return C_flonum(ptr, tmp);
 9424    }
 9425    x = nx = C_s_a_u_i_flo_to_int(&a, 1, x);
 9426  }
 9427  if (C_truep(C_i_flonump(y))) {
 9428    y = ny = C_s_a_u_i_flo_to_int(&a, 1, y);
 9429  }
 9430
 9431  integer_divrem(&a, x, y, &q, NULL);
 9432
 9433  if (C_truep(nx) || C_truep(ny)) {
 9434    C_word newq = C_a_i_exact_to_inexact(ptr, 1, q);
 9435    clear_buffer_object(ab, q);
 9436    q = newq;
 9437
 9438    clear_buffer_object(ab, nx);
 9439    clear_buffer_object(ab, ny);
 9440  }
 9441  return move_buffer_object(ptr, ab, q);
 9442}
 9443
 9444C_regparm C_word
 9445C_s_a_u_i_integer_quotient(C_word **ptr, C_word n, C_word x, C_word y)
 9446{
 9447  C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, q;
 9448  if (y == C_fix(0)) C_div_by_zero_error("quotient");
 9449  integer_divrem(&a, x, y, &q, NULL);
 9450  return move_buffer_object(ptr, ab, q);
 9451}
 9452
 9453
 9454/* For help understanding this algorithm, see:
 9455   Knuth, Donald E., "The Art of Computer Programming",
 9456   volume 2, "Seminumerical Algorithms"
 9457   section 4.3.1, "Multiple-Precision Arithmetic".
 9458
 9459   [Yeah, that's a nice book but that particular section is not
 9460   helpful at all, which is also pointed out by P. Brinch Hansen's
 9461   "Multiple-Length Division Revisited: A Tour Of The Minefield".
 9462   That's a more down-to-earth step-by-step explanation of the
 9463   algorithm.  Add to this the C implementation in Hacker's Delight
 9464   (section 9-2, p141--142) and you may be able to grok this...
 9465   ...barely, if you're as math-challenged as I am -- sjamaan]
 9466
 9467   This assumes that numerator >= denominator!
 9468*/
 9469static void
 9470bignum_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)
 9471{
 9472  C_word quotient = C_SCHEME_UNDEFINED, remainder = C_SCHEME_UNDEFINED,
 9473         return_rem = C_mk_nbool(r == NULL), size;
 9474
 9475  if (q != NULL) {
 9476    size = C_fix(C_bignum_size(num) + 1 - C_bignum_size(denom));
 9477    quotient = C_allocate_scratch_bignum(ptr, size, q_negp, C_SCHEME_FALSE);
 9478  }
 9479
 9480  /* An object is always required to receive the remainder */
 9481  size = C_fix(C_bignum_size(num) + 1);
 9482  remainder = C_allocate_scratch_bignum(ptr, size, r_negp, C_SCHEME_FALSE);
 9483  bignum_destructive_divide_full(num, denom, quotient, remainder, return_rem);
 9484
 9485  /* Simplification must be done by the caller, for consistency */
 9486  if (q != NULL) *q = quotient;
 9487  if (r == NULL) {
 9488    C_mutate_scratch_slot(NULL, C_internal_bignum_vector(remainder));
 9489  } else {
 9490    *r = remainder;
 9491  }
 9492}
 9493
 9494/* Compare two numbers as ratnums.  Either may be rat-, fix- or bignums */
 9495static C_word rat_cmp(C_word x, C_word y)
 9496{
 9497  C_word ab[C_SIZEOF_FIX_BIGNUM*4], *a = ab, x1, x2, y1, y2,
 9498         s, t, ssize, tsize, result, negp;
 9499  C_uword *scan;
 9500
 9501  /* Check for 1 or 0; if x or y is this, the other must be the ratnum */
 9502  if (x == C_fix(0)) {	      /* Only the sign of y1 matters */
 9503    return basic_cmp(x, C_u_i_ratnum_num(y), "ratcmp", 0);
 9504  } else if (x == C_fix(1)) { /* x1*y1 <> x2*y2 --> y2 <> y1 | x1/x2 = 1/1 */
 9505    return basic_cmp(C_u_i_ratnum_denom(y), C_u_i_ratnum_num(y), "ratcmp", 0);
 9506  } else if (y == C_fix(0)) { /* Only the sign of x1 matters */
 9507    return basic_cmp(C_u_i_ratnum_num(x), y, "ratcmp", 0);
 9508  } else if (y == C_fix(1)) { /* x1*y1 <> x2*y2 --> x1 <> x2 | y1/y2 = 1/1 */
 9509    return basic_cmp(C_u_i_ratnum_num(x), C_u_i_ratnum_denom(x), "ratcmp", 0);
 9510  }
 9511
 9512  /* Extract components x=x1/x2 and y=y1/y2 */
 9513  if (x & C_FIXNUM_BIT || C_truep(C_bignump(x))) {
 9514    x1 = x;
 9515    x2 = C_fix(1);
 9516  } else {
 9517    x1 = C_u_i_ratnum_num(x);
 9518    x2 = C_u_i_ratnum_denom(x);
 9519  }
 9520
 9521  if (y & C_FIXNUM_BIT || C_truep(C_bignump(y))) {
 9522    y1 = y;
 9523    y2 = C_fix(1);
 9524  } else {
 9525    y1 = C_u_i_ratnum_num(y);
 9526    y2 = C_u_i_ratnum_denom(y);
 9527  }
 9528
 9529  /* We only want to deal with bignums (this is tricky enough) */
 9530  if (x1 & C_FIXNUM_BIT) x1 = C_a_u_i_fix_to_big(&a, x1);
 9531  if (x2 & C_FIXNUM_BIT) x2 = C_a_u_i_fix_to_big(&a, x2);
 9532  if (y1 & C_FIXNUM_BIT) y1 = C_a_u_i_fix_to_big(&a, y1);
 9533  if (y2 & C_FIXNUM_BIT) y2 = C_a_u_i_fix_to_big(&a, y2);
 9534
 9535  /* We multiply using schoolbook method, so this will be very slow in
 9536   * extreme cases.  This is a tradeoff we make so that comparisons
 9537   * are inlineable, which makes a big difference for the common case.
 9538   */
 9539  ssize = C_bignum_size(x1) + C_bignum_size(y2);
 9540  negp = C_mk_bool(C_bignum_negativep(x1));
 9541  s = allocate_tmp_bignum(C_fix(ssize), negp, C_SCHEME_TRUE);
 9542  bignum_digits_multiply(x1, y2, s); /* Swap args if x1 < y2? */
 9543
 9544  tsize = C_bignum_size(y1) + C_bignum_size(x2);
 9545  negp = C_mk_bool(C_bignum_negativep(y1));
 9546  t = allocate_tmp_bignum(C_fix(tsize), negp, C_SCHEME_TRUE);
 9547  bignum_digits_multiply(y1, x2, t); /* Swap args if y1 < x2? */
 9548
 9549  /* Shorten the numbers if needed */
 9550  for (scan = C_bignum_digits(s)+ssize-1; *scan == 0; scan--) ssize--;
 9551  C_bignum_mutate_size(s, ssize);
 9552  for (scan = C_bignum_digits(t)+tsize-1; *scan == 0; scan--) tsize--;
 9553  C_bignum_mutate_size(t, tsize);
 9554
 9555  result = C_i_bignum_cmp(s, t);
 9556
 9557  free_tmp_bignum(t);
 9558  free_tmp_bignum(s);
 9559  return result;
 9560}
 9561
 9562C_regparm double C_bignum_to_double(C_word bignum)
 9563{
 9564  double accumulator = 0;
 9565  C_uword *start = C_bignum_digits(bignum),
 9566          *scan = start + C_bignum_size(bignum);
 9567  while (start < scan) {
 9568    accumulator *= (C_uword)1 << C_BIGNUM_HALF_DIGIT_LENGTH;
 9569    accumulator *= (C_uword)1 << C_BIGNUM_HALF_DIGIT_LENGTH;
 9570    accumulator += (*--scan);
 9571  }
 9572  return(C_bignum_negativep(bignum) ? -accumulator : accumulator);
 9573}
 9574
 9575C_regparm C_word
 9576C_s_a_u_i_flo_to_int(C_word **ptr, C_word n, C_word x)
 9577{
 9578  int exponent;
 9579  double significand = frexp(C_flonum_magnitude(x), &exponent);
 9580
 9581  assert(C_truep(C_u_i_fpintegerp(x)));
 9582
 9583  if (exponent <= 0) {
 9584    return C_fix(0);
 9585  } else if (exponent == 1) { /* TODO: check significand * 2^exp fits fixnum? */
 9586    return significand < 0.0 ? C_fix(-1) : C_fix(1);
 9587  } else {
 9588    C_word size, negp = C_mk_bool(C_flonum_magnitude(x) < 0.0), result;
 9589    C_uword *start, *end;
 9590
 9591    size = C_fix(C_BIGNUM_BITS_TO_DIGITS(exponent));
 9592    result = C_allocate_scratch_bignum(ptr, size, negp, C_SCHEME_FALSE);
 9593
 9594    start = C_bignum_digits(result);
 9595    end = start + C_bignum_size(result);
 9596
 9597    fabs_frexp_to_digits(exponent, fabs(significand), start, end);
 9598    return C_bignum_simplify(result);
 9599  }
 9600}
 9601
 9602static void
 9603fabs_frexp_to_digits(C_uword exp, double sign, C_uword *start, C_uword *scan)
 9604{
 9605  C_uword digit, odd_bits = exp % C_BIGNUM_DIGIT_LENGTH;
 9606
 9607  assert(C_isfinite(sign));
 9608  assert(0.5 <= sign && sign < 1); /* Guaranteed by frexp() and fabs() */
 9609  assert((scan - start) == C_BIGNUM_BITS_TO_DIGITS(exp));
 9610
 9611  if (odd_bits > 0) { /* Handle most significant digit first */
 9612    sign *= (C_uword)1 << odd_bits;
 9613    digit = (C_uword)sign;
 9614    (*--scan) = digit;
 9615    sign -= (double)digit;
 9616  }
 9617
 9618  while (start < scan && sign > 0) {
 9619    sign *= pow(2.0, C_BIGNUM_DIGIT_LENGTH);
 9620    digit = (C_uword)sign;
 9621    (*--scan) = digit;
 9622    sign -= (double)digit;
 9623  }
 9624
 9625  /* Finish up by clearing any remaining, lower, digits */
 9626  while (start < scan)
 9627    (*--scan) = 0;
 9628}
 9629
 9630/* This is a bit weird: We have to compare flonums as bignums due to
 9631 * precision loss on 64-bit platforms.  For simplicity, we convert
 9632 * fixnums to bignums here.
 9633 */
 9634static C_word int_flo_cmp(C_word intnum, C_word flonum)
 9635{
 9636  C_word ab[C_SIZEOF_FIX_BIGNUM + C_SIZEOF_FLONUM], *a = ab, flo_int, res;
 9637  double i, f;
 9638
 9639  f = C_flonum_magnitude(flonum);
 9640
 9641  if (C_isnan(f)) {
 9642    return C_SCHEME_FALSE; /* "mu" */
 9643  } else if (C_isinf(f)) {
 9644    return C_fix((f > 0.0) ? -1 : 1); /* x is smaller if f is +inf.0 */
 9645  } else {
 9646    f = modf(f, &i);
 9647
 9648    flo_int = C_s_a_u_i_flo_to_int(&a, 1, C_flonum(&a, i));
 9649
 9650    res = basic_cmp(intnum, flo_int, "int_flo_cmp", 0);
 9651    clear_buffer_object(ab, flo_int);
 9652
 9653    if (res == C_fix(0)) /* Use fraction to break tie. If f > 0, x is smaller */
 9654      return C_fix((f > 0.0) ? -1 : ((f < 0.0) ? 1 : 0));
 9655    else
 9656      return res;
 9657  }
 9658}
 9659
 9660/* For convenience (ie, to reduce the degree of mindfuck) */
 9661static C_word flo_int_cmp(C_word flonum, C_word intnum)
 9662{
 9663  C_word res = int_flo_cmp(intnum, flonum);
 9664  switch(res) {
 9665  case C_fix(1): return C_fix(-1);
 9666  case C_fix(-1): return C_fix(1);
 9667  default: return res; /* Can be either C_fix(0) or C_SCHEME_FALSE(!) */
 9668  }
 9669}
 9670
 9671/* This code is a bit tedious, but it makes inline comparisons possible! */
 9672static C_word rat_flo_cmp(C_word ratnum, C_word flonum)
 9673{
 9674  C_word ab[C_SIZEOF_FIX_BIGNUM * 4 + C_SIZEOF_FLONUM], *a = ab,
 9675         num, denom, i_int, res, nscaled, iscaled, negp, shift_amount;
 9676  C_uword *scan;
 9677  double i, f;
 9678
 9679  f = C_flonum_magnitude(flonum);
 9680
 9681  if (C_isnan(f)) {
 9682    return C_SCHEME_FALSE; /* "mu" */
 9683  } else if (C_isinf(f)) {
 9684    return C_fix((f > 0.0) ? -1 : 1); /* x is smaller if f is +inf.0 */
 9685  } else {
 9686    /* Scale up the floating-point number to become a whole integer,
 9687     * and remember power of two (# of bits) to shift the numerator.
 9688     */
 9689    shift_amount = 0;
 9690
 9691    /* TODO: This doesn't work for denormalized flonums! */
 9692    while (modf(f, &i) != 0.0) {
 9693      f = ldexp(f, 1);
 9694      shift_amount++;
 9695    }
 9696
 9697    i = f; /* TODO: split i and f so it'll work for denormalized flonums */
 9698
 9699    num = C_u_i_ratnum_num(ratnum);
 9700    negp = C_i_negativep(num);
 9701
 9702    if (C_truep(negp) && i >= 0.0) { /* Save some time if signs differ */
 9703      return C_fix(-1);
 9704    } else if (!C_truep(negp) && i <= 0.0) { /* num is never 0 */
 9705      return C_fix(1);
 9706    } else {
 9707      denom = C_u_i_ratnum_denom(ratnum);
 9708      i_int = C_s_a_u_i_flo_to_int(&a, 1, C_flonum(&a, i));
 9709
 9710      /* Multiply the scaled flonum integer by the denominator, and
 9711       * shift the numerator so that they may be directly compared. */
 9712      iscaled = C_s_a_u_i_integer_times(&a, 2, i_int, denom);
 9713      nscaled = C_s_a_i_arithmetic_shift(&a, 2, num, C_fix(shift_amount));
 9714
 9715      /* Finally, we're ready to compare them! */
 9716      res = basic_cmp(nscaled, iscaled, "rat_flo_cmp", 0);
 9717      clear_buffer_object(ab, nscaled);
 9718      clear_buffer_object(ab, iscaled);
 9719      clear_buffer_object(ab, i_int);
 9720
 9721      return res;
 9722    }
 9723  }
 9724}
 9725
 9726static C_word flo_rat_cmp(C_word flonum, C_word ratnum)
 9727{
 9728  C_word res = rat_flo_cmp(ratnum, flonum);
 9729  switch(res) {
 9730  case C_fix(1): return C_fix(-1);
 9731  case C_fix(-1): return C_fix(1);
 9732  default: return res; /* Can be either C_fix(0) or C_SCHEME_FALSE(!) */
 9733  }
 9734}
 9735
 9736/* The primitive comparison operator.  eqp should be 1 if we're only
 9737 * interested in equality testing (can speed things up and in case of
 9738 * compnums, equality checking is the only available operation).  This
 9739 * may return #f, in case there is no answer (for NaNs) or as a quick
 9740 * and dirty non-zero answer when eqp is true.  Ugly but effective :)
 9741 */
 9742static C_word basic_cmp(C_word x, C_word y, char *loc, int eqp)
 9743{
 9744  if (x & C_FIXNUM_BIT) {
 9745    if (y & C_FIXNUM_BIT) {
 9746      return C_fix((x < y) ? -1 : ((x > y) ? 1 : 0));
 9747    } else if (C_immediatep(y)) {
 9748      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9749    } else if (C_block_header(y) == C_FLONUM_TAG) {
 9750      return int_flo_cmp(x, y);
 9751    } else if (C_truep(C_bignump(y))) {
 9752      C_word ab[C_SIZEOF_FIX_BIGNUM], *a = ab;
 9753      return C_i_bignum_cmp(C_a_u_i_fix_to_big(&a, x), y);
 9754    } else if (C_block_header(y) == C_RATNUM_TAG) {
 9755      if (eqp) return C_SCHEME_FALSE;
 9756      else return rat_cmp(x, y);
 9757    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 9758      if (eqp) return C_SCHEME_FALSE;
 9759      else barf(C_BAD_ARGUMENT_TYPE_COMPLEX_NO_ORDERING_ERROR, loc, y);
 9760    } else {
 9761      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9762    }
 9763  } else if (C_immediatep(x)) {
 9764    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, x);
 9765  } else if (C_block_header(x) == C_FLONUM_TAG) {
 9766    if (y & C_FIXNUM_BIT) {
 9767      return flo_int_cmp(x, y);
 9768    } else if (C_immediatep(y)) {
 9769      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9770    } else if (C_block_header(y) == C_FLONUM_TAG) {
 9771      double a = C_flonum_magnitude(x), b = C_flonum_magnitude(y);
 9772      if (C_isnan(a) || C_isnan(b)) return C_SCHEME_FALSE; /* "mu" */
 9773      else return C_fix((a < b) ? -1 : ((a > b) ? 1 : 0));
 9774    } else if (C_truep(C_bignump(y))) {
 9775      return flo_int_cmp(x, y);
 9776    } else if (C_block_header(y) == C_RATNUM_TAG) {
 9777      return flo_rat_cmp(x, y);
 9778    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 9779      if (eqp) return C_SCHEME_FALSE;
 9780      else barf(C_BAD_ARGUMENT_TYPE_COMPLEX_NO_ORDERING_ERROR, loc, y);
 9781    } else {
 9782      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9783    }
 9784  } else if (C_truep(C_bignump(x))) {
 9785    if (y & C_FIXNUM_BIT) {
 9786      C_word ab[C_SIZEOF_FIX_BIGNUM], *a = ab;
 9787      return C_i_bignum_cmp(x, C_a_u_i_fix_to_big(&a, y));
 9788    } else if (C_immediatep(y)) {
 9789      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9790    } else if (C_block_header(y) == C_FLONUM_TAG) {
 9791      return int_flo_cmp(x, y);
 9792    } else if (C_truep(C_bignump(y))) {
 9793      return C_i_bignum_cmp(x, y);
 9794    } else if (C_block_header(y) == C_RATNUM_TAG) {
 9795      if (eqp) return C_SCHEME_FALSE;
 9796      else return rat_cmp(x, y);
 9797    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 9798      if (eqp) return C_SCHEME_FALSE;
 9799      else barf(C_BAD_ARGUMENT_TYPE_COMPLEX_NO_ORDERING_ERROR, loc, y);
 9800    } else {
 9801      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9802    }
 9803  } else if (C_block_header(x) == C_RATNUM_TAG) {
 9804    if (y & C_FIXNUM_BIT) {
 9805      if (eqp) return C_SCHEME_FALSE;
 9806      else return rat_cmp(x, y);
 9807    } else if (C_immediatep(y)) {
 9808      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9809    } else if (C_block_header(y) == C_FLONUM_TAG) {
 9810      return rat_flo_cmp(x, y);
 9811    } else if (C_truep(C_bignump(y))) {
 9812      if (eqp) return C_SCHEME_FALSE;
 9813      else return rat_cmp(x, y);
 9814    } else if (C_block_header(y) == C_RATNUM_TAG) {
 9815      if (eqp) {
 9816        return C_and(C_and(C_i_integer_equalp(C_u_i_ratnum_num(x),
 9817                                              C_u_i_ratnum_num(y)),
 9818                           C_i_integer_equalp(C_u_i_ratnum_denom(x),
 9819                                              C_u_i_ratnum_denom(y))),
 9820                     C_fix(0));
 9821      } else {
 9822        return rat_cmp(x, y);
 9823      }
 9824    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 9825      if (eqp) return C_SCHEME_FALSE;
 9826      else barf(C_BAD_ARGUMENT_TYPE_COMPLEX_NO_ORDERING_ERROR, loc, y);
 9827    } else {
 9828      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9829    }
 9830  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 9831    if (!eqp) {
 9832      barf(C_BAD_ARGUMENT_TYPE_COMPLEX_NO_ORDERING_ERROR, loc, x);
 9833    } else if (y & C_FIXNUM_BIT) {
 9834      return C_SCHEME_FALSE;
 9835    } else if (C_immediatep(y)) {
 9836      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9837    } else if (C_block_header(y) == C_FLONUM_TAG ||
 9838               C_truep(C_bignump(x)) ||
 9839               C_block_header(y) == C_RATNUM_TAG) {
 9840      return C_SCHEME_FALSE;
 9841    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 9842      return C_and(C_and(C_i_nequalp(C_u_i_cplxnum_real(x), C_u_i_cplxnum_real(y)),
 9843                         C_i_nequalp(C_u_i_cplxnum_imag(x), C_u_i_cplxnum_imag(y))),
 9844                   C_fix(0));
 9845    } else {
 9846      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9847    }
 9848  } else {
 9849    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, x);
 9850  }
 9851}
 9852
 9853static int bignum_cmp_unsigned(C_word x, C_word y)
 9854{
 9855  C_word xlen = C_bignum_size(x), ylen = C_bignum_size(y);
 9856
 9857  if (xlen < ylen) {
 9858    return -1;
 9859  } else if (xlen > ylen) {
 9860    return 1;
 9861  } else if (x == y) {
 9862    return 0;
 9863  } else {
 9864    C_uword *startx = C_bignum_digits(x),
 9865            *scanx = startx + xlen,
 9866            *scany = C_bignum_digits(y) + ylen;
 9867
 9868    while (startx < scanx) {
 9869      C_uword xdigit = (*--scanx), ydigit = (*--scany);
 9870      if (xdigit < ydigit)
 9871        return -1;
 9872      if (xdigit > ydigit)
 9873        return 1;
 9874    }
 9875    return 0;
 9876  }
 9877}
 9878
 9879C_regparm C_word C_i_bignum_cmp(C_word x, C_word y)
 9880{
 9881  if (C_bignum_negativep(x)) {
 9882    if (C_bignum_negativep(y)) { /* Largest negative number is smallest */
 9883      return C_fix(bignum_cmp_unsigned(y, x));
 9884    } else {
 9885      return C_fix(-1);
 9886    }
 9887  } else {
 9888    if (C_bignum_negativep(y)) {
 9889      return C_fix(1);
 9890    } else {
 9891      return C_fix(bignum_cmp_unsigned(x, y));
 9892    }
 9893  }
 9894}
 9895
 9896void C_ccall C_nequalp(C_word c, C_word *av)
 9897{
 9898  /* C_word closure = av[ 0 ]; */
 9899  C_word k = av[ 1 ];
 9900  C_word x, y, result = C_SCHEME_TRUE;
 9901
 9902  c -= 2;
 9903  av += 2;
 9904  if (c == 0) C_kontinue(k, result);
 9905  x = *(av++);
 9906
 9907  if (c == 1 && !C_truep(C_i_numberp(x)))
 9908    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "=", x);
 9909
 9910  while(--c) {
 9911    y = *(av++);
 9912    result = C_i_nequalp(x, y);
 9913    if (result == C_SCHEME_FALSE) break;
 9914  }
 9915
 9916  C_kontinue(k, result);
 9917}
 9918
 9919C_regparm C_word C_i_nequalp(C_word x, C_word y)
 9920{
 9921   return C_mk_bool(basic_cmp(x, y, "=", 1) == C_fix(0));
 9922}
 9923
 9924C_regparm C_word C_i_integer_equalp(C_word x, C_word y)
 9925{
 9926  if (x & C_FIXNUM_BIT)
 9927    return C_mk_bool(x == y);
 9928  else if (y & C_FIXNUM_BIT)
 9929    return C_SCHEME_FALSE;
 9930  else
 9931    return C_mk_bool(C_i_bignum_cmp(x, y) == C_fix(0));
 9932}
 9933
 9934
 9935void C_ccall C_greaterp(C_word c, C_word *av)
 9936{
 9937  C_word x, y,
 9938    /* closure = av[ 0 ] */
 9939    k = av[ 1 ],
 9940    result = C_SCHEME_TRUE;
 9941
 9942  c -= 2;
 9943  av += 2;
 9944  if (c == 0) C_kontinue(k, result);
 9945
 9946  x = *(av++);
 9947
 9948  if (c == 1 && !C_truep(C_i_numberp(x)))
 9949    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, ">", x);
 9950
 9951  while(--c) {
 9952    y = *(av++);
 9953    result = C_i_greaterp(x, y);
 9954    if (result == C_SCHEME_FALSE) break;
 9955    x = y;
 9956  }
 9957
 9958  C_kontinue(k, result);
 9959}
 9960
 9961
 9962C_regparm C_word C_i_greaterp(C_word x, C_word y)
 9963{
 9964   return C_mk_bool(basic_cmp(x, y, ">", 0) == C_fix(1));
 9965}
 9966
 9967C_regparm C_word C_i_integer_greaterp(C_word x, C_word y)
 9968{
 9969  if (x & C_FIXNUM_BIT) {
 9970    if (y & C_FIXNUM_BIT) {
 9971      return C_mk_bool(C_unfix(x) > C_unfix(y));
 9972    } else {
 9973      return C_mk_bool(C_bignum_negativep(y));
 9974    }
 9975  } else if (y & C_FIXNUM_BIT) {
 9976    return C_mk_nbool(C_bignum_negativep(x));
 9977  } else {
 9978    return C_mk_bool(C_i_bignum_cmp(x, y) == C_fix(1));
 9979  }
 9980}
 9981
 9982void C_ccall C_lessp(C_word c, C_word *av)
 9983{
 9984  C_word x, y,
 9985    /* closure = av[ 0 ] */
 9986    k = av[ 1 ],
 9987    result = C_SCHEME_TRUE;
 9988
 9989  c -= 2;
 9990  av += 2;
 9991  if (c == 0) C_kontinue(k, result);
 9992
 9993  x = *(av++);
 9994
 9995  if (c == 1 && !C_truep(C_i_numberp(x)))
 9996    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "<", x);
 9997
 9998  while(--c) {
 9999    y = *(av++);
10000    result = C_i_lessp(x, y);
10001    if (result == C_SCHEME_FALSE) break;
10002    x = y;
10003  }
10004
10005  C_kontinue(k, result);
10006}
10007
10008
10009C_regparm C_word C_i_lessp(C_word x, C_word y)
10010{
10011   return C_mk_bool(basic_cmp(x, y, "<", 0) == C_fix(-1));
10012}
10013
10014C_regparm C_word C_i_integer_lessp(C_word x, C_word y)
10015{
10016  if (x & C_FIXNUM_BIT) {
10017    if (y & C_FIXNUM_BIT) {
10018      return C_mk_bool(C_unfix(x) < C_unfix(y));
10019    } else {
10020      return C_mk_nbool(C_bignum_negativep(y));
10021    }
10022  } else if (y & C_FIXNUM_BIT) {
10023    return C_mk_bool(C_bignum_negativep(x));
10024  } else {
10025    return C_mk_bool(C_i_bignum_cmp(x, y) == C_fix(-1));
10026  }
10027}
10028
10029void C_ccall C_greater_or_equal_p(C_word c, C_word *av)
10030{
10031  C_word x, y,
10032    /* closure = av[ 0 ] */
10033    k = av[ 1 ],
10034    result = C_SCHEME_TRUE;
10035
10036  c -= 2;
10037  av += 2;
10038  if (c == 0) C_kontinue(k, result);
10039
10040  x = *(av++);
10041
10042  if (c == 1 && !C_truep(C_i_numberp(x)))
10043    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, ">=", x);
10044
10045  while(--c) {
10046    y = *(av++);
10047    result = C_i_greater_or_equalp(x, y);
10048    if (result == C_SCHEME_FALSE) break;
10049    x = y;
10050  }
10051
10052  C_kontinue(k, result);
10053}
10054
10055
10056C_regparm C_word C_i_greater_or_equalp(C_word x, C_word y)
10057{
10058   C_word res = basic_cmp(x, y, ">=", 0);
10059   return C_mk_bool(res == C_fix(0) || res == C_fix(1));
10060}
10061
10062C_regparm C_word C_i_integer_greater_or_equalp(C_word x, C_word y)
10063{
10064  if (x & C_FIXNUM_BIT) {
10065    if (y & C_FIXNUM_BIT) {
10066      return C_mk_bool(C_unfix(x) >= C_unfix(y));
10067    } else {
10068      return C_mk_bool(C_bignum_negativep(y));
10069    }
10070  } else if (y & C_FIXNUM_BIT) {
10071    return C_mk_nbool(C_bignum_negativep(x));
10072  } else {
10073    C_word res = C_i_bignum_cmp(x, y);
10074    return C_mk_bool(res == C_fix(0) || res == C_fix(1));
10075  }
10076}
10077
10078void C_ccall C_less_or_equal_p(C_word c, C_word *av)
10079{
10080  C_word x, y,
10081    /* closure = av[ 0 ] */
10082    k = av[ 1 ],
10083    result = C_SCHEME_TRUE;
10084
10085  c -= 2;
10086  av += 2;
10087  if (c == 0) C_kontinue(k, result);
10088
10089  x = *(av++);
10090
10091  if (c == 1 && !C_truep(C_i_numberp(x)))
10092    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "<=", x);
10093
10094  while(--c) {
10095    y = *(av++);
10096    result = C_i_less_or_equalp(x, y);
10097    if (result == C_SCHEME_FALSE) break;
10098    x = y;
10099  }
10100
10101  C_kontinue(k, result);
10102}
10103
10104
10105C_regparm C_word C_i_less_or_equalp(C_word x, C_word y)
10106{
10107   C_word res = basic_cmp(x, y, "<=", 0);
10108   return C_mk_bool(res == C_fix(0) || res == C_fix(-1));
10109}
10110
10111
10112C_regparm C_word C_i_integer_less_or_equalp(C_word x, C_word y)
10113{
10114  if (x & C_FIXNUM_BIT) {
10115    if (y & C_FIXNUM_BIT) {
10116      return C_mk_bool(C_unfix(x) <= C_unfix(y));
10117    } else {
10118      return C_mk_nbool(C_bignum_negativep(y));
10119    }
10120  } else if (y & C_FIXNUM_BIT) {
10121    return C_mk_bool(C_bignum_negativep(x));
10122  } else {
10123    C_word res = C_i_bignum_cmp(x, y);
10124    return C_mk_bool(res == C_fix(0) || res == C_fix(-1));
10125  }
10126}
10127
10128
10129void C_ccall C_gc(C_word c, C_word *av)
10130{
10131  C_word
10132    /* closure = av[ 0 ] */
10133    k = av[ 1 ];
10134  int f;
10135  C_word
10136    arg, *p,
10137    size = 0;
10138
10139  if(c == 3) {
10140    arg = av[ 2 ];
10141    f = C_truep(arg);
10142  }
10143  else if(c != 2) C_bad_min_argc(c, 2);
10144  else f = 1;
10145
10146  C_save(k);
10147  p = C_temporary_stack;
10148
10149  if(c == 3) {
10150    if((arg & C_FIXNUM_BIT) != 0) size = C_unfix(arg);
10151    else if(arg == C_SCHEME_END_OF_LIST) size = percentage(heap_size, C_heap_growth);
10152  }
10153
10154  if(size && !C_heap_size_is_fixed) {
10155    C_rereclaim2(size, 0);
10156    C_temporary_stack = C_temporary_stack_bottom;
10157    gc_2(0, p);
10158  }
10159  else if(f) C_fromspace_top = C_fromspace_limit;
10160
10161  C_reclaim((void *)gc_2, 1);
10162}
10163
10164
10165void C_ccall gc_2(C_word c, C_word *av)
10166{
10167  C_word k = av[ 0 ];
10168  C_kontinue(k, C_fix((C_uword)C_fromspace_limit - (C_uword)C_fromspace_top));
10169}
10170
10171
10172void C_ccall C_open_file_port(C_word c, C_word *av)
10173{
10174  C_word
10175    /* closure = av[ 0 ] */
10176    k = av[ 1 ],
10177    port = av[ 2 ],
10178    channel = av[ 3 ],
10179    mode = av[ 4 ];
10180  C_FILEPTR fp = (C_FILEPTR)NULL;
10181  C_char *fmode;
10182  C_word n, bv, fbv;
10183  C_char *buf;
10184  C_WCHAR *fbuf;
10185
10186  switch(channel) {
10187  case C_fix(0): fp = C_stdin; break;
10188  case C_fix(1): fp = C_stdout; break;
10189  case C_fix(2): fp = C_stderr; break;
10190  default:
10191    bv = C_block_item(channel, 0);
10192    buf = C_c_string(bv);
10193    fbv = C_block_item(mode, 0);
10194    fmode = C_c_string(fbv);
10195    if (C_header_size(C_block_item(channel, 0)) - 1 != strlen(buf))
10196      barf(C_ASCIIZ_REPRESENTATION_ERROR, "open", channel);
10197    if (C_header_size(C_block_item(mode, 0)) - 1 != strlen(fmode))
10198      barf(C_ASCIIZ_REPRESENTATION_ERROR, "open", mode);
10199    fbuf = C_OS_FILENAME(bv, 0);
10200    fp = C_fopen(fbuf, C_OS_FILENAME(fbv, 1));
10201  }
10202
10203  C_set_block_item(port, 0, (C_word)fp);
10204  C_kontinue(k, C_mk_bool(fp != NULL));
10205}
10206
10207
10208void C_ccall C_allocate_vector(C_word c, C_word *av)
10209{
10210  C_word
10211    /* closure = av[ 0 ] */
10212    k = av[ 1 ],
10213    size, init, bytes, n, *p;
10214
10215  if(c != 4) C_bad_argc(c, 4);
10216
10217  size = av[ 2 ];
10218  init = av[ 3 ];
10219  n = C_unfix(size);
10220
10221  if(n > C_HEADER_SIZE_MASK || n < 0)
10222    barf(C_OUT_OF_BOUNDS_ERROR, NULL, size, C_fix(C_HEADER_SIZE_MASK));
10223
10224  bytes = C_wordstobytes(n) + sizeof(C_word);
10225
10226  C_save(k);
10227  C_save(size);
10228  C_save(init);
10229  C_save(C_fix(bytes));
10230
10231  if(!C_demand(C_bytestowords(bytes))) {
10232    /* Allocate on heap: */
10233    if((C_uword)(C_fromspace_limit - C_fromspace_top) < (bytes + stack_size * 2))
10234      C_fromspace_top = C_fromspace_limit; /* trigger major GC */
10235
10236    C_save(C_SCHEME_TRUE);
10237    /* We explicitly pass 5 here, that's the number of things saved.
10238     * That's the arguments, plus one additional thing: the mode.
10239     */
10240    C_reclaim((void *)allocate_vector_2, 5);
10241  }
10242
10243  C_save(C_SCHEME_FALSE);
10244  p = C_temporary_stack;
10245  C_temporary_stack = C_temporary_stack_bottom;
10246  allocate_vector_2(0, p);
10247}
10248
10249
10250void C_ccall allocate_vector_2(C_word c, C_word *av)
10251{
10252  C_word
10253    mode = av[ 0 ],
10254    bytes = C_unfix(av[ 1 ]),
10255    init = av[ 2 ],
10256    size = C_unfix(av[ 3 ]),
10257    k = av[ 4 ],
10258    *v0, v;
10259
10260  if(C_truep(mode)) {
10261    while((C_uword)(C_fromspace_limit - C_fromspace_top) < (bytes + stack_size)) {
10262      if(C_heap_size_is_fixed)
10263	panic(C_text("out of memory - cannot allocate vector (heap resizing disabled)"));
10264
10265      C_save(init);
10266      C_save(k);
10267      C_rereclaim2(percentage(heap_size, C_heap_growth) + (C_uword)bytes, 0);
10268      k = C_restore;
10269      init = C_restore;
10270    }
10271
10272    v0 = (C_word *)C_align((C_word)C_fromspace_top);
10273    C_fromspace_top += C_align(bytes);
10274  }
10275  else v0 = C_alloc(C_bytestowords(bytes));
10276
10277  v = (C_word)v0;
10278  *(v0++) = C_VECTOR_TYPE | size;
10279  while(size--) *(v0++) = init;
10280  C_kontinue(k, v);
10281}
10282
10283void C_ccall C_allocate_bytevector(C_word c, C_word *av)
10284{
10285  C_word
10286    /* closure = av[ 0 ] */
10287    k = av[ 1 ],
10288    size, init, align8, bytes, str, n, *p;
10289
10290  if(c != 4) C_bad_argc(c, 4);
10291
10292  size = av[ 2 ];
10293  init = av[ 3 ];
10294  n = C_unfix(size);
10295
10296  if(n > C_HEADER_SIZE_MASK || n < 0)
10297    barf(C_OUT_OF_BOUNDS_ERROR, NULL, size, C_fix(C_HEADER_SIZE_MASK));
10298
10299  bytes = n + sizeof(C_word) * 2;
10300
10301  C_save(k);
10302  C_save(size);
10303  C_save(init);
10304  C_save(C_fix(bytes));
10305
10306  if(!C_demand(C_bytestowords(bytes))) {
10307    /* Allocate on heap: */
10308    if((C_uword)(C_fromspace_limit - C_fromspace_top) < (bytes + stack_size * 2))
10309      C_fromspace_top = C_fromspace_limit; /* trigger major GC */
10310
10311    C_save(C_SCHEME_TRUE);
10312    /* We explicitly pass 5 here, that's the number of things saved.
10313     * That's the arguments, plus one additional thing: the mode.
10314     */
10315    C_reclaim((void *)allocate_bytevector_2, 5);
10316  }
10317
10318  C_save(C_SCHEME_FALSE);
10319  p = C_temporary_stack;
10320  C_temporary_stack = C_temporary_stack_bottom;
10321  allocate_bytevector_2(0, p);
10322}
10323
10324
10325void C_ccall allocate_bytevector_2(C_word c, C_word *av)
10326{
10327  C_word
10328    mode = av[ 0 ],
10329    bytes = C_unfix(av[ 1 ]),
10330    init = av[ 2 ],
10331    size = C_unfix(av[ 3 ]),
10332    k = av[ 4 ],
10333    *v0, v;
10334  char buf[ 4 ];
10335
10336  if(C_truep(mode)) {
10337    while((C_uword)(C_fromspace_limit - C_fromspace_top) < (bytes + stack_size)) {
10338      if(C_heap_size_is_fixed)
10339	panic(C_text("out of memory - cannot allocate vector (heap resizing disabled)"));
10340
10341      C_save(init);
10342      C_save(k);
10343      C_rereclaim2(percentage(heap_size, C_heap_growth) + (C_uword)bytes, 0);
10344      k = C_restore;
10345      init = C_restore;
10346    }
10347
10348    v0 = (C_word *)C_align((C_word)C_fromspace_top);
10349    C_fromspace_top += C_align(bytes);
10350  }
10351  else v0 = C_alloc(C_bytestowords(bytes));
10352
10353#ifndef C_SIXTY_FOUR
10354  if(C_aligned8(v0)) ++v0;
10355#endif
10356
10357  v = (C_word)v0;
10358  *(v0++) = C_BYTEVECTOR_TYPE | size;
10359
10360  if(C_truep(init)) C_memset(v0, C_unfix(init), size);
10361
10362  C_kontinue(k, v);
10363}
10364
10365static C_word allocate_tmp_bignum(C_word size, C_word negp, C_word initp)
10366{
10367  C_word *mem = C_malloc(C_wordstobytes(C_SIZEOF_BIGNUM(C_unfix(size)))),
10368          bigvec = (C_word)(mem + C_SIZEOF_BIGNUM_WRAPPER);
10369  if (mem == NULL) abort();     /* TODO: panic */
10370
10371  C_block_header_init(bigvec, C_BYTEVECTOR_TYPE | C_wordstobytes(C_unfix(size)+1));
10372  C_set_block_item(bigvec, 0, C_truep(negp));
10373
10374  if (C_truep(initp)) {
10375    C_memset(((C_uword *)C_data_pointer(bigvec))+1,
10376             0, C_wordstobytes(C_unfix(size)));
10377  }
10378
10379  return C_a_i_bignum_wrapper(&mem, bigvec);
10380}
10381
10382C_regparm C_word
10383C_allocate_scratch_bignum(C_word **ptr, C_word size, C_word negp, C_word initp)
10384{
10385  C_word big, bigvec = C_scratch_alloc(C_SIZEOF_INTERNAL_BIGNUM_VECTOR(C_unfix(size)));
10386
10387  C_block_header_init(bigvec, C_BYTEVECTOR_TYPE | C_wordstobytes(C_unfix(size)+1));
10388  C_set_block_item(bigvec, 0, C_truep(negp));
10389
10390  if (C_truep(initp)) {
10391    C_memset(((C_uword *)C_data_pointer(bigvec))+1,
10392             0, C_wordstobytes(C_unfix(size)));
10393  }
10394
10395  big = C_a_i_bignum_wrapper(ptr, bigvec);
10396  C_mutate_scratch_slot(&C_internal_bignum_vector(big), bigvec);
10397  return big;
10398}
10399
10400/* Simplification: scan trailing zeroes, then return a fixnum if the
10401 * value fits, or trim the bignum's length.  If the bignum was stored
10402 * in scratch space, we mark it as reclaimable.  This means any
10403 * references to the original bignum are invalid after simplification!
10404 */
10405C_regparm C_word C_bignum_simplify(C_word big)
10406{
10407  C_uword *start = C_bignum_digits(big),
10408          *last_digit = start + C_bignum_size(big) - 1,
10409          *scan = last_digit, tmp;
10410  int length;
10411
10412  while (scan >= start && *scan == 0)
10413    scan--;
10414  length = scan - start + 1;
10415
10416  switch(length) {
10417  case 0:
10418    if (C_in_scratchspacep(C_internal_bignum_vector(big)))
10419      C_mutate_scratch_slot(NULL, C_internal_bignum_vector(big));
10420    return C_fix(0);
10421  case 1:
10422    tmp = *start;
10423    if (C_bignum_negativep(big) ?
10424        !(tmp & C_INT_SIGN_BIT) && C_fitsinfixnump(-(C_word)tmp) :
10425        C_ufitsinfixnump(tmp)) {
10426      if (C_in_scratchspacep(C_internal_bignum_vector(big)))
10427        C_mutate_scratch_slot(NULL, C_internal_bignum_vector(big));
10428      return C_bignum_negativep(big) ? C_fix(-(C_word)tmp) : C_fix(tmp);
10429    }
10430    /* FALLTHROUGH */
10431  default:
10432    if (scan < last_digit) C_bignum_mutate_size(big, length);
10433    return big;
10434  }
10435}
10436
10437static void bignum_digits_destructive_negate(C_word result)
10438{
10439  C_uword *scan, *end, digit, sum;
10440
10441  scan = C_bignum_digits(result);
10442  end = scan + C_bignum_size(result);
10443
10444  do {
10445    digit = ~*scan;
10446    sum = digit + 1;
10447    *scan++ = sum;
10448  } while (sum == 0 && scan < end);
10449
10450  for (; scan < end; scan++) {
10451    *scan = ~*scan;
10452  }
10453}
10454
10455static C_uword
10456bignum_digits_destructive_scale_up_with_carry(C_uword *start, C_uword *end, C_uword factor, C_uword carry)
10457{
10458  C_uword digit, p;
10459
10460  assert(C_fitsinbignumhalfdigitp(carry));
10461  assert(C_fitsinbignumhalfdigitp(factor));
10462
10463  /* See fixnum_times.  Substitute xlo = factor, xhi = 0, y = digit
10464   * and simplify the result to reduce variable usage.
10465   */
10466  while (start < end) {
10467    digit = (*start);
10468
10469    p = factor * C_BIGNUM_DIGIT_LO_HALF(digit) + carry;
10470    carry = C_BIGNUM_DIGIT_LO_HALF(p);
10471
10472    p = factor * C_BIGNUM_DIGIT_HI_HALF(digit) + C_BIGNUM_DIGIT_HI_HALF(p);
10473    (*start++) = C_BIGNUM_DIGIT_COMBINE(C_BIGNUM_DIGIT_LO_HALF(p), carry);
10474    carry = C_BIGNUM_DIGIT_HI_HALF(p);
10475  }
10476  return carry;
10477}
10478
10479static C_uword
10480bignum_digits_destructive_scale_down(C_uword *start, C_uword *end, C_uword denominator)
10481{
10482  C_uword digit, k = 0;
10483  C_uhword q_j_hi, q_j_lo;
10484
10485  /* Single digit divisor case from Hacker's Delight, Figure 9-1,
10486   * adapted to modify u[] in-place instead of writing to q[].
10487   */
10488  while (start < end) {
10489    digit = (*--end);
10490
10491    k = C_BIGNUM_DIGIT_COMBINE(k, C_BIGNUM_DIGIT_HI_HALF(digit)); /* j */
10492    q_j_hi = k / denominator;
10493    k -= q_j_hi * denominator;
10494
10495    k = C_BIGNUM_DIGIT_COMBINE(k, C_BIGNUM_DIGIT_LO_HALF(digit)); /* j-1 */
10496    q_j_lo = k / denominator;
10497    k -= q_j_lo * denominator;
10498
10499    *end = C_BIGNUM_DIGIT_COMBINE(q_j_hi, q_j_lo);
10500  }
10501  return k;
10502}
10503
10504static C_uword
10505bignum_digits_destructive_shift_right(C_uword *start, C_uword *end, int shift_right, int negp)
10506{
10507  int shift_left = C_BIGNUM_DIGIT_LENGTH - shift_right;
10508  C_uword digit, carry = negp ? ((~(C_uword)0) << shift_left) : 0;
10509
10510  assert(shift_right < C_BIGNUM_DIGIT_LENGTH);
10511
10512  while (start < end) {
10513    digit = *(--end);
10514    *end = (digit >> shift_right) | carry;
10515    carry = digit << shift_left;
10516  }
10517  return carry >> shift_left; /* The bits that were shifted out to the right */
10518}
10519
10520static C_uword
10521bignum_digits_destructive_shift_left(C_uword *start, C_uword *end, int shift_left)
10522{
10523  C_uword carry = 0, digit;
10524  int shift_right = C_BIGNUM_DIGIT_LENGTH - shift_left;
10525
10526  assert(shift_left < C_BIGNUM_DIGIT_LENGTH);
10527
10528  while (start < end) {
10529    digit = *start;
10530    (*start++) = (digit << shift_left) | carry;
10531    carry = digit >> shift_right;
10532  }
10533  return carry;	 /* This would end up as most significant digit if it fit */
10534}
10535
10536static C_regparm void
10537bignum_digits_multiply(C_word x, C_word y, C_word result)
10538{
10539  C_uword product,
10540          *xd = C_bignum_digits(x),
10541          *yd = C_bignum_digits(y),
10542          *rd = C_bignum_digits(result);
10543  C_uhword carry, yj;
10544  /* Lengths in halfwords */
10545  int i, j, length_x = C_bignum_size(x) * 2, length_y = C_bignum_size(y) * 2;
10546
10547  /* From Hacker's Delight, Figure 8-1 (top part) */
10548  for (j = 0; j < length_y; ++j) {
10549    yj = C_uhword_ref(yd, j);
10550    if (yj == 0) continue;
10551    carry = 0;
10552    for (i = 0; i < length_x; ++i) {
10553      product = (C_uword)C_uhword_ref(xd, i) * yj +
10554                (C_uword)C_uhword_ref(rd, i + j) + carry;
10555      C_uhword_set(rd, i + j, product);
10556      carry = C_BIGNUM_DIGIT_HI_HALF(product);
10557    }
10558    C_uhword_set(rd, j + length_x, carry);
10559  }
10560}
10561
10562
10563/* "small" is either a number that fits a halfdigit, or a power of two */
10564static C_regparm void
10565bignum_destructive_divide_unsigned_small(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r)
10566{
10567  C_word size, quotient, q_negp = C_mk_bool((y & C_INT_SIGN_BIT) ?
10568                                            !(C_bignum_negativep(x)) :
10569                                            C_bignum_negativep(x)),
10570         r_negp = C_mk_bool(C_bignum_negativep(x));
10571  C_uword *start, *end, remainder;
10572  int shift_amount;
10573
10574  size = C_fix(C_bignum_size(x));
10575  quotient = C_allocate_scratch_bignum(ptr, size, q_negp, C_SCHEME_FALSE);
10576  bignum_digits_destructive_copy(quotient, x);
10577
10578  start = C_bignum_digits(quotient);
10579  end = start + C_bignum_size(quotient);
10580
10581  y = (y & C_INT_SIGN_BIT) ? -C_unfix(y) : C_unfix(y);
10582
10583  shift_amount = C_ilen(y) - 1;
10584  if (((C_uword)1 << shift_amount) == y) { /* Power of two?  Shift! */
10585    remainder = bignum_digits_destructive_shift_right(start,end,shift_amount,0);
10586    assert(C_ufitsinfixnump(remainder));
10587  } else {
10588    remainder = bignum_digits_destructive_scale_down(start, end, y);
10589    assert(C_fitsinbignumhalfdigitp(remainder));
10590  }
10591
10592  if (r != NULL) *r = C_truep(r_negp) ? C_fix(-remainder) : C_fix(remainder);
10593  /* Calling this function only makes sense if quotient is needed */
10594  *q = C_bignum_simplify(quotient);
10595}
10596
10597static C_regparm void
10598bignum_destructive_divide_full(C_word numerator, C_word denominator, C_word quotient, C_word remainder, C_word return_remainder)
10599{
10600  C_word length = C_bignum_size(denominator);
10601  C_uword d1 = *(C_bignum_digits(denominator) + length - 1),
10602          *startr = C_bignum_digits(remainder),
10603          *endr = startr + C_bignum_size(remainder);
10604  int shift;
10605
10606  shift = C_BIGNUM_DIGIT_LENGTH - C_ilen(d1); /* nlz */
10607
10608  /* We have to work on halfdigits, so we shift out only the necessary
10609   * amount in order fill out that halfdigit (base is halved).
10610   * This trick is shamelessly stolen from Gauche :)
10611   * See below for part 2 of the trick.
10612   */
10613  if (shift >= C_BIGNUM_HALF_DIGIT_LENGTH)
10614    shift -= C_BIGNUM_HALF_DIGIT_LENGTH;
10615
10616  /* Code below won't always set high halfdigit of quotient, so do it here. */
10617  if (quotient != C_SCHEME_UNDEFINED)
10618    C_bignum_digits(quotient)[C_bignum_size(quotient)-1] = 0;
10619
10620  bignum_digits_destructive_copy(remainder, numerator);
10621  *(endr-1) = 0;    /* Ensure most significant digit is initialised */
10622  if (shift == 0) { /* Already normalized */
10623    bignum_destructive_divide_normalized(remainder, denominator, quotient);
10624  } else { /* Requires normalisation; allocate scratch denominator for this */
10625    C_uword *startnd;
10626    C_word ndenom;
10627
10628    bignum_digits_destructive_shift_left(startr, endr, shift);
10629
10630    ndenom = allocate_tmp_bignum(C_fix(length), C_SCHEME_FALSE, C_SCHEME_FALSE);
10631    startnd = C_bignum_digits(ndenom);
10632    bignum_digits_destructive_copy(ndenom, denominator);
10633    bignum_digits_destructive_shift_left(startnd, startnd+length, shift);
10634
10635    bignum_destructive_divide_normalized(remainder, ndenom, quotient);
10636    if (C_truep(return_remainder)) /* Otherwise, don't bother shifting back */
10637      bignum_digits_destructive_shift_right(startr, endr, shift, 0);
10638
10639    free_tmp_bignum(ndenom);
10640  }
10641}
10642
10643static C_regparm void
10644bignum_destructive_divide_normalized(C_word big_u, C_word big_v, C_word big_q)
10645{
10646  C_uword *v = C_bignum_digits(big_v),
10647          *u = C_bignum_digits(big_u),
10648          *q = big_q == C_SCHEME_UNDEFINED ? NULL : C_bignum_digits(big_q),
10649           p,               /* product of estimated quotient & "denominator" */
10650           hat, qhat, rhat, /* estimated quotient and remainder digit */
10651           vn_1, vn_2;      /* "cached" values v[n-1], v[n-2] */
10652  C_word t, k;              /* Two helpers: temp/final remainder and "borrow" */
10653  /* We use plain ints here, which theoretically may not be enough on
10654   * 64-bit for an insanely huge number, but it is a _lot_ faster.
10655   */
10656  int n = C_bignum_size(big_v) * 2,       /* in halfwords */
10657      m = (C_bignum_size(big_u) * 2) - 2; /* Correct for extra digit */
10658  int i, j;		   /* loop  vars */
10659
10660  /* Part 2 of Gauche's aforementioned trick: */
10661  if (C_uhword_ref(v, n-1) == 0) n--;
10662
10663  /* These won't change during the loop, but are used in every step. */
10664  vn_1 = C_uhword_ref(v, n-1);
10665  vn_2 = C_uhword_ref(v, n-2);
10666
10667  /* See also Hacker's Delight, Figure 9-1.  This is almost exactly that. */
10668  for (j = m - n; j >= 0; j--) {
10669    hat = C_BIGNUM_DIGIT_COMBINE(C_uhword_ref(u, j+n), C_uhword_ref(u, j+n-1));
10670    if (hat == 0) {
10671      if (q != NULL) C_uhword_set(q, j, 0);
10672      continue;
10673    }
10674    qhat = hat / vn_1;
10675    rhat = hat % vn_1;
10676
10677    /* Two whiles is faster than one big check with an OR.  Thanks, Gauche! */
10678    while(qhat >= ((C_uword)1 << C_BIGNUM_HALF_DIGIT_LENGTH)) { qhat--; rhat += vn_1; }
10679    while(qhat * vn_2 > C_BIGNUM_DIGIT_COMBINE(rhat, C_uhword_ref(u, j+n-2))
10680	  && rhat < ((C_uword)1 << C_BIGNUM_HALF_DIGIT_LENGTH)) {
10681      qhat--;
10682      rhat += vn_1;
10683    }
10684
10685    /* Multiply and subtract */
10686    k = 0;
10687    for (i = 0; i < n; i++) {
10688      p = qhat * C_uhword_ref(v, i);
10689      t = C_uhword_ref(u, i+j) - k - C_BIGNUM_DIGIT_LO_HALF(p);
10690      C_uhword_set(u, i+j, t);
10691      k = C_BIGNUM_DIGIT_HI_HALF(p) - (t >> C_BIGNUM_HALF_DIGIT_LENGTH);
10692    }
10693    t = C_uhword_ref(u,j+n) - k;
10694    C_uhword_set(u, j+n, t);
10695
10696    if (t < 0) {		/* Subtracted too much? */
10697      qhat--;
10698      k = 0;
10699      for (i = 0; i < n; i++) {
10700        t = (C_uword)C_uhword_ref(u, i+j) + C_uhword_ref(v, i) + k;
10701        C_uhword_set(u, i+j, t);
10702	k = t >> C_BIGNUM_HALF_DIGIT_LENGTH;
10703      }
10704      C_uhword_set(u, j+n, (C_uhword_ref(u, j+n) + k));
10705    }
10706    if (q != NULL) C_uhword_set(q, j, qhat);
10707  } /* end j */
10708}
10709
10710
10711/* XXX this should be an inline_allocate routine */
10712void C_ccall C_string_to_symbol(C_word c, C_word *av)
10713{
10714  C_word
10715    /* closure = av[ 0 ] */
10716    k = av[ 1 ];
10717  int len, key;
10718  C_word s, *a = C_alloc(C_SIZEOF_SYMBOL + C_SIZEOF_PAIR), b;
10719  C_char *name;
10720
10721  b = av[ 2 ];
10722  len = C_header_size(b) - 1;
10723  name = C_c_string(b);
10724
10725  key = hash_string(len, name, symbol_table->size, symbol_table->rand);
10726  if(!C_truep(s = lookup(key, len, name, symbol_table)))
10727    s = add_symbol(&a, key, b, symbol_table);
10728
10729  C_kontinue(k, s);
10730}
10731
10732/* XXX this should be an inline_allocate routine */
10733void C_ccall C_string_to_keyword(C_word c, C_word *av)
10734{
10735  C_word
10736    /* closure = av[ 0 ] */
10737    k = av[ 1 ];
10738  int len, key;
10739  C_word s, *a = C_alloc(C_SIZEOF_SYMBOL + C_SIZEOF_PAIR), b;
10740  C_char *name;
10741
10742  b = av[ 2 ];
10743  len = C_header_size(b) - 1;
10744  name = C_c_string(b);
10745  key = hash_string(len, name, keyword_table->size, keyword_table->rand);
10746
10747  if(!C_truep(s = lookup(key, len, name, keyword_table))) {
10748    s = add_symbol(&a, key, b, keyword_table);
10749    C_set_block_item(s, 0, s); /* Keywords evaluate to themselves */
10750    C_set_block_item(s, 2, C_SCHEME_FALSE); /* Keywords have no plists */
10751  }
10752  C_kontinue(k, s);
10753}
10754
10755/* This will usually return a flonum, but it may also return a cplxnum
10756 * consisting of two flonums, making for a total of 11 words.
10757 */
10758C_regparm C_word
10759C_a_i_exact_to_inexact(C_word **ptr, int c, C_word n)
10760{
10761  if (n & C_FIXNUM_BIT) {
10762    return C_flonum(ptr, (double)C_unfix(n));
10763  } else if (C_immediatep(n)) {
10764    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "exact->inexact", n);
10765  } else if (C_block_header(n) == C_FLONUM_TAG) {
10766    return n;
10767  } else if (C_truep(C_bignump(n))) {
10768    return C_a_u_i_big_to_flo(ptr, c, n);
10769  } else if (C_block_header(n) == C_CPLXNUM_TAG) {
10770    return C_cplxnum(ptr, C_a_i_exact_to_inexact(ptr, 1, C_u_i_cplxnum_real(n)),
10771                     C_a_i_exact_to_inexact(ptr, 1, C_u_i_cplxnum_imag(n)));
10772  /* The horribly painful case: ratnums */
10773  } else if (C_block_header(n) == C_RATNUM_TAG) {
10774    /* This tries to keep the numbers within representable ranges and
10775     * tries to drop as few significant digits as possible by bringing
10776     * the two numbers to within the same powers of two.  See
10777     * algorithms M & N in Knuth, 4.2.1.
10778     */
10779     C_word num = C_u_i_ratnum_num(n), denom = C_u_i_ratnum_denom(n),
10780             /* e = approx. distance between the numbers in powers of 2.
10781              * ie, 2^e-1 < n/d < 2^e+1 (e is the *un*biased value of
10782              * e_w in M2.  TODO: What if b!=2 (ie, flonum-radix isn't 2)?
10783              */
10784             e = integer_length_abs(num) - integer_length_abs(denom),
10785             ab[C_SIZEOF_FIX_BIGNUM*5+C_SIZEOF_FLONUM], *a = ab, tmp, q, r, len,
10786             shift_amount, negp = C_i_integer_negativep(num);
10787     C_uword *d;
10788     double res, fraction;
10789
10790     /* Align by shifting the smaller to the size of the larger */
10791     if (e < 0)      num = C_s_a_i_arithmetic_shift(&a, 2, num, C_fix(-e));
10792     else if (e > 0) denom = C_s_a_i_arithmetic_shift(&a, 2, denom, C_fix(e));
10793
10794     /* Here, 1/2 <= n/d < 2 [N3] */
10795     if (C_truep(C_i_integer_lessp(num, denom))) { /* n/d < 1? */
10796       tmp = C_s_a_i_arithmetic_shift(&a, 2, num, C_fix(1));
10797       clear_buffer_object(ab, num); /* "knows" shift creates fresh numbers */
10798       num = tmp;
10799       e--;
10800     }
10801
10802     /* Here, 1 <= n/d < 2 (normalized) [N5] */
10803     shift_amount = nmin(DBL_MANT_DIG-1, e - (DBL_MIN_EXP - DBL_MANT_DIG));
10804
10805     tmp = C_s_a_i_arithmetic_shift(&a, 2, num, C_fix(shift_amount));
10806     clear_buffer_object(ab, num); /* "knows" shift creates fresh numbers */
10807     num = tmp;
10808
10809     /* Now, calculate round(num/denom).  We start with a quotient&remainder */
10810     integer_divrem(&a, num, denom, &q, &r);
10811
10812     /* We multiply the remainder by two to simulate adding 1/2 for
10813      * round.  However, we don't do it if num = denom (q=1,r=0) */
10814     if (!((q == C_fix(1) || q == C_fix(-1)) && r == C_fix(0))) {
10815       tmp = C_s_a_i_arithmetic_shift(&a, 2, r, C_fix(1));
10816       clear_buffer_object(ab, r); /* "knows" shift creates fresh numbers */
10817       r = tmp;
10818     }
10819
10820     /* Now q is the quotient, but to "round" result we need to
10821      * adjust.  This follows the semantics of the "round" procedure:
10822      * Round away from zero on positive numbers (ignoring sign).  In
10823      * case of exactly halfway, we round up if odd.
10824      */
10825     tmp = C_a_i_exact_to_inexact(&a, 1, q);
10826     fraction = fabs(C_flonum_magnitude(tmp));
10827     switch (basic_cmp(r, denom, "", 0)) {
10828     case C_fix(0):
10829       if (C_truep(C_i_oddp(q))) fraction += 1.0;
10830       break;
10831     case C_fix(1):
10832       fraction += 1.0;
10833       break;
10834     default: /* if r <= denom, we're done */ break;
10835     }
10836
10837     clear_buffer_object(ab, num);
10838     clear_buffer_object(ab, denom);
10839     clear_buffer_object(ab, q);
10840     clear_buffer_object(ab, r);
10841
10842     shift_amount = nmin(DBL_MANT_DIG-1, e - (DBL_MIN_EXP - DBL_MANT_DIG));
10843     res = ldexp(fraction, e - shift_amount);
10844     return C_flonum(ptr, C_truep(negp) ? -res : res);
10845  } else {
10846    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "exact->inexact", n);
10847  }
10848}
10849
10850
10851/* this is different from C_a_i_flonum_round, for R5RS compatibility */
10852C_regparm C_word C_a_i_flonum_round_proper(C_word **ptr, int c, C_word n)
10853{
10854  double fn, i, f, i2, r;
10855
10856  fn = C_flonum_magnitude(n);
10857  if(fn < 0.0) {
10858    f = modf(-fn, &i);
10859    if(f < 0.5 || (f == 0.5 && modf(i * 0.5, &i2) == 0.0))
10860      r = -i;
10861    else
10862      r = -(i + 1.0);
10863  }
10864  else if(fn == 0.0/* || fn == -0.0*/)
10865    r = fn;
10866  else {
10867    f = modf(fn, &i);
10868    if(f < 0.5 || (f == 0.5 && modf(i * 0.5, &i2) == 0.0))
10869      r = i;
10870    else
10871      r = i + 1.0;
10872  }
10873
10874  return C_flonum(ptr, r);
10875}
10876
10877C_regparm C_word
10878C_a_i_flonum_gcd(C_word **p, C_word n, C_word x, C_word y)
10879{
10880   double xub, yub, r;
10881
10882   if (!C_truep(C_u_i_fpintegerp(x)))
10883     barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "gcd", x);
10884   if (!C_truep(C_u_i_fpintegerp(y)))
10885     barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "gcd", y);
10886
10887   xub = C_flonum_magnitude(x);
10888   yub = C_flonum_magnitude(y);
10889
10890   if (xub < 0.0) xub = -xub;
10891   if (yub < 0.0) yub = -yub;
10892
10893   while(yub != 0.0) {
10894     r = fmod(xub, yub);
10895     xub = yub;
10896     yub = r;
10897   }
10898   return C_flonum(p, xub);
10899}
10900
10901/* This is Lehmer's GCD algorithm with Jebelean's quotient test, as
10902 * it is presented in the paper "An Analysis of Lehmer’s Euclidean
10903 * GCD Algorithm", by J. Sorenson.  Fuck the ACM and their goddamn
10904 * paywall; you can currently find the paper here:
10905 * http://www.csie.nuk.edu.tw/~cychen/gcd/An%20analysis%20of%20Lehmer%27s%20Euclidean%20GCD%20algorithm.pdf
10906 * If that URI fails, it's also explained in [MpNT, 5.2]
10907 *
10908 * The basic idea is to avoid divisions which yield only small
10909 * quotients, in which the remainder won't reduce the numbers by
10910 * much.  This can be detected by dividing only the leading k bits.
10911 * In our case, k = C_WORD_SIZE - 2.
10912 */
10913inline static void lehmer_gcd(C_word **ptr, C_word u, C_word v, C_word *x, C_word *y)
10914{
10915  int i_even = 1, done = 0;
10916  C_word shift_amount = integer_length_abs(u) - (C_WORD_SIZE - 2),
10917         ab[C_SIZEOF_BIGNUM(2)*2+C_SIZEOF_FIX_BIGNUM*2], *a = ab,
10918         uhat, vhat, qhat, xnext, ynext,
10919         xprev = 1, yprev = 0, xcurr = 0, ycurr = 1;
10920
10921  uhat = C_s_a_i_arithmetic_shift(&a, 2, u, C_fix(-shift_amount));
10922  vhat = C_s_a_i_arithmetic_shift(&a, 2, v, C_fix(-shift_amount));
10923  assert(uhat & C_FIXNUM_BIT); uhat = C_unfix(uhat);
10924  assert(vhat & C_FIXNUM_BIT); vhat = C_unfix(vhat);
10925
10926  do {
10927    qhat = uhat / vhat;         /* Estimated quotient for this step */
10928    xnext = xprev - qhat * xcurr;
10929    ynext = yprev - qhat * ycurr;
10930
10931    /* Euclidean GCD swap on uhat and vhat (shift_amount is not needed): */
10932    shift_amount = vhat;
10933    vhat = uhat - qhat * vhat;
10934    uhat = shift_amount;
10935
10936    i_even = !i_even;
10937    if (i_even)
10938      done = (vhat < -xnext) || ((uhat - vhat) < (ynext - ycurr));
10939    else
10940      done = (vhat < -ynext) || ((uhat - vhat) < (xnext - xcurr));
10941
10942    if (!done) {
10943      xprev = xcurr; yprev = ycurr;
10944      xcurr = xnext; ycurr = ynext;
10945    }
10946  } while (!done);
10947
10948  /* x = xprev * u + yprev * v */
10949  uhat = C_s_a_u_i_integer_times(&a, 2, C_fix(xprev), u);
10950  vhat = C_s_a_u_i_integer_times(&a, 2, C_fix(yprev), v);
10951  *x = C_s_a_u_i_integer_plus(ptr, 2, uhat, vhat);
10952  *x = move_buffer_object(ptr, ab, *x);
10953  clear_buffer_object(ab, uhat);
10954  clear_buffer_object(ab, vhat);
10955
10956  /* y = xcurr * u + ycurr * v */
10957  uhat = C_s_a_u_i_integer_times(&a, 2, C_fix(xcurr), u);
10958  vhat = C_s_a_u_i_integer_times(&a, 2, C_fix(ycurr), v);
10959  *y = C_s_a_u_i_integer_plus(ptr, 2, uhat, vhat);
10960  *y = move_buffer_object(ptr, ab, *y);
10961  clear_buffer_object(ab, uhat);
10962  clear_buffer_object(ab, vhat);
10963}
10964
10965/* Because this must be inlineable (due to + and - using this for
10966 * ratnums), we can't use burnikel-ziegler division here, until we
10967 * have a C implementation that doesn't consume stack.  However,
10968 * we *can* use Lehmer's GCD.
10969 */
10970C_regparm C_word
10971C_s_a_u_i_integer_gcd(C_word **ptr, C_word n, C_word x, C_word y)
10972{
10973   C_word ab[2][C_SIZEOF_BIGNUM(2) * 2], *a, newx, newy, size, i = 0;
10974
10975   if (x & C_FIXNUM_BIT && y & C_FIXNUM_BIT) return C_i_fixnum_gcd(x, y);
10976
10977   a = ab[i++];
10978   x = C_s_a_u_i_integer_abs(&a, 1, x);
10979   y = C_s_a_u_i_integer_abs(&a, 1, y);
10980
10981   if (!C_truep(C_i_integer_greaterp(x, y))) {
10982     newx = y; y = x; x = newx; /* Ensure loop invariant: abs(x) >= abs(y) */
10983   }
10984
10985   while(y != C_fix(0)) {
10986     assert(integer_length_abs(x) >= integer_length_abs(y));
10987     /* x and y are stored in the same buffer, as well as a result */
10988     a = ab[i++];
10989     if (i == 2) i = 0;
10990
10991     if (x & C_FIXNUM_BIT) return C_i_fixnum_gcd(x, y);
10992
10993     /* First, see if we should run a Lehmer step */
10994     if ((integer_length_abs(x) - integer_length_abs(y)) < C_HALF_WORD_SIZE) {
10995       lehmer_gcd(&a, x, y, &newx, &newy);
10996       newx = move_buffer_object(&a, ab[i], newx);
10997       newy = move_buffer_object(&a, ab[i], newy);
10998       clear_buffer_object(ab[i], x);
10999       clear_buffer_object(ab[i], y);
11000       x = newx;
11001       y = newy;
11002       a = ab[i++]; /* Ensure x and y get cleared correctly below */
11003       if (i == 2) i = 0;
11004     }
11005
11006     newy = C_s_a_u_i_integer_remainder(&a, 2, x, y);
11007     newy = move_buffer_object(&a, ab[i], newy);
11008     newx = move_buffer_object(&a, ab[i], y);
11009     clear_buffer_object(ab[i], x);
11010     clear_buffer_object(ab[i], y);
11011     x = newx;
11012     y = newy;
11013   }
11014
11015   newx = C_s_a_u_i_integer_abs(ptr, 1, x);
11016   newx = move_buffer_object(ptr, ab, newx);
11017   clear_buffer_object(ab, x);
11018   clear_buffer_object(ab, y);
11019   return newx;
11020}
11021
11022
11023C_regparm C_word
11024C_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)
11025{
11026  if (start == end) {
11027    return C_SCHEME_FALSE;
11028  } else {
11029    size_t nbits;
11030    char *s = C_c_string(C_block_item(str, 0));
11031    C_word result, size;
11032    end = C_unfix(end);
11033    start = C_unfix(start);
11034    radix = C_unfix(radix);
11035
11036    assert((radix > 1) && C_fitsinbignumhalfdigitp(radix));
11037
11038    nbits = (end - start) * C_ilen(radix - 1);
11039    size = C_BIGNUM_BITS_TO_DIGITS(nbits);
11040    if (size == 1) {
11041      result = C_bignum1(ptr, C_truep(negp), 0);
11042    } else if (size == 2) {
11043      result = C_bignum2(ptr, C_truep(negp), 0, 0);
11044    } else {
11045      size = C_fix(size);
11046      result = C_allocate_scratch_bignum(ptr, size, negp, C_SCHEME_FALSE);
11047    }
11048
11049    return str_to_bignum(result, s + start, s + end, radix);
11050  }
11051}
11052
11053inline static int hex_char_to_digit(int ch)
11054{
11055  if (ch == (int)'#') return 0; /* Hash characters in numbers are mapped to 0 */
11056  else if (ch >= (int)'a') return ch - (int)'a' + 10; /* lower hex */
11057  else if (ch >= (int)'A') return ch - (int)'A' + 10; /* upper hex */
11058  else return ch - (int)'0'; /* decimal (OR INVALID; handled elsewhere) */
11059}
11060
11061/* Write from digit character stream to bignum.  Bignum does not need
11062 * to be initialised.  Returns the bignum, or a fixnum.  Assumes the
11063 * string contains only digits that fit within radix (checked by
11064 * string->number).
11065 */
11066static C_regparm C_word
11067str_to_bignum(C_word bignum, char *str, char *str_end, int radix)
11068{
11069  int radix_shift, str_digit;
11070  C_uword *digits = C_bignum_digits(bignum),
11071          *end_digits = digits + C_bignum_size(bignum), big_digit = 0;
11072
11073  /* Below, we try to save up as much as possible in big_digit, and
11074   * only when it exceeds what we would be able to multiply easily, we
11075   * scale up the bignum and add what we saved up.
11076   */
11077  radix_shift = C_ilen(radix) - 1;
11078  if (((C_uword)1 << radix_shift) == radix) { /* Power of two? */
11079    int n = 0; /* Number of bits read so far into current big digit */
11080
11081    /* Read from least to most significant digit to avoid shifting or scaling */
11082    while (str_end > str) {
11083      str_digit = hex_char_to_digit((int)*--str_end);
11084
11085      big_digit |= (C_uword)str_digit << n;
11086      n += radix_shift;
11087
11088      if (n >= C_BIGNUM_DIGIT_LENGTH) {
11089	n -= C_BIGNUM_DIGIT_LENGTH;
11090	*digits++ = big_digit;
11091	big_digit = str_digit >> (radix_shift - n);
11092      }
11093    }
11094    assert(n < C_BIGNUM_DIGIT_LENGTH);
11095    /* If radix isn't an exact divisor of digit length, write final digit */
11096    if (n > 0) *digits++ = big_digit;
11097    assert(digits == end_digits);
11098  } else {			  /* Not a power of two */
11099    C_uword *last_digit = digits, factor;  /* bignum starts as zero */
11100
11101    do {
11102      factor = radix;
11103      while (str < str_end && C_fitsinbignumhalfdigitp(factor)) {
11104        str_digit = hex_char_to_digit((int)*str++);
11105	factor *= radix;
11106	big_digit = radix * big_digit + str_digit;
11107      }
11108
11109      big_digit = bignum_digits_destructive_scale_up_with_carry(
11110                   digits, last_digit, factor / radix, big_digit);
11111
11112      if (big_digit) {
11113	(*last_digit++) = big_digit; /* Move end */
11114        big_digit = 0;
11115      }
11116    } while (str < str_end);
11117
11118    /* Set remaining digits to zero so bignum_simplify can do its work */
11119    assert(last_digit <= end_digits);
11120    while (last_digit < end_digits) *last_digit++ = 0;
11121  }
11122
11123  return C_bignum_simplify(bignum);
11124}
11125
11126
11127static C_regparm double decode_flonum_literal(C_char *str)
11128{
11129  C_char *eptr;
11130  double flo;
11131  int len = C_strlen(str);
11132
11133  /* We only need to be able to parse what C_flonum_to_string() emits,
11134   * so we avoid too much error checking.
11135   */
11136  if (len == 6) { /* Only perform comparisons when necessary */
11137    if (!C_strcmp(str, "-inf.0")) return -1.0 / 0.0;
11138    if (!C_strcmp(str, "+inf.0")) return 1.0 / 0.0;
11139    if (!C_strcmp(str, "+nan.0")) return 0.0 / 0.0;
11140  }
11141
11142  errno = 0;
11143  flo = C_strtod(str, &eptr);
11144
11145  if((flo == HUGE_VAL && errno != 0) ||
11146     (flo == -HUGE_VAL && errno != 0) ||
11147     (*eptr != '\0' && C_strcmp(eptr, ".0") != 0)) {
11148    panic(C_text("could not decode flonum literal"));
11149  }
11150
11151  return flo;
11152}
11153
11154
11155static char *to_n_nary(C_uword num, C_uword base, int negp, int as_flonum)
11156{
11157  static char *digits = "0123456789abcdef";
11158  char *p;
11159  C_uword shift = C_ilen(base) - 1;
11160  int mask = (1 << shift) - 1;
11161  if (as_flonum) {
11162    buffer[68] = '\0';
11163    buffer[67] = '0';
11164    buffer[66] = '.';
11165  } else {
11166    buffer[66] = '\0';
11167  }
11168  p = buffer + 66;
11169  if (mask == base - 1) {
11170    do {
11171      *(--p) = digits [ num & mask ];
11172      num >>= shift;
11173    } while (num);
11174  } else {
11175    do {
11176      *(--p) = digits [ num % base ];
11177      num /= base;
11178    } while (num);
11179  }
11180  if (negp) *(--p) = '-';
11181  return p;
11182}
11183
11184
11185void C_ccall C_number_to_string(C_word c, C_word *av)
11186{
11187  C_word radix, num;
11188
11189  if(c == 3) {
11190    radix = C_fix(10);
11191  } else if(c == 4) {
11192    radix = av[ 3 ];
11193    if(!(radix & C_FIXNUM_BIT))
11194      barf(C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR, "number->string", radix);
11195  } else {
11196    C_bad_argc(c, 3);
11197  }
11198
11199  num = av[ 2 ];
11200
11201  if(num & C_FIXNUM_BIT) {
11202    C_fixnum_to_string(c, av); /* reuse av */
11203  } else if (C_immediatep(num)) {
11204    barf(C_BAD_ARGUMENT_TYPE_ERROR, "number->string", num);
11205  } else if(C_block_header(num) == C_FLONUM_TAG) {
11206    C_flonum_to_string(c, av); /* reuse av */
11207  } else if (C_truep(C_bignump(num))) {
11208    C_integer_to_string(c, av); /* reuse av */
11209  } else {
11210    C_word k = av[ 1 ];
11211    try_extended_number("##sys#extended-number->string", 3, k, num, radix);
11212  }
11213}
11214
11215void C_ccall C_fixnum_to_string(C_word c, C_word *av)
11216{
11217  C_char *p;
11218  C_word *a,
11219    /* self = av[ 0 ] */
11220    k = av[ 1 ],
11221    num = av[ 2 ],
11222    radix = ((c == 3) ? 10 : C_unfix(av[ 3 ])),
11223    neg = ((num & C_INT_SIGN_BIT) ? 1 : 0);
11224
11225  if (radix < 2 || radix > 16) {
11226    barf(C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR, "number->string", C_fix(radix));
11227  }
11228
11229  num = neg ? -C_unfix(num) : C_unfix(num);
11230  p = to_n_nary(num, radix, neg, 0);
11231
11232  num = C_strlen(p);
11233  a = C_alloc(C_SIZEOF_STRING(num));
11234  C_kontinue(k, C_string(&a, num, p));
11235}
11236
11237void C_ccall C_flonum_to_string(C_word c, C_word *av)
11238{
11239  C_char *p;
11240  double f, fa, m;
11241  C_word *a,
11242    /* self = av[ 0 ] */
11243    k = av[ 1 ],
11244    num = av[ 2 ],
11245    radix = ((c == 3) ? 10 : C_unfix(av[ 3 ]));
11246
11247  f = C_flonum_magnitude(num);
11248  fa = fabs(f);
11249
11250  /* XXX TODO: Should inexacts be printable in other bases than 10?
11251   * Perhaps output a string starting with #i?
11252   * Right now something like (number->string 1e40 16) results in
11253   * a string that can't be read back using string->number.
11254   */
11255  if((radix < 2) || (radix > 16)){
11256    barf(C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR, "number->string", C_fix(radix));
11257  }
11258
11259  if(f == 0.0 || (C_modf(f, &m) == 0.0 && log2(fa) < C_WORD_SIZE)) { /* Use fast int code */
11260    if(signbit(f)) {
11261      p = to_n_nary((C_uword)-f, radix, 1, 1);
11262    } else {
11263      p = to_n_nary((C_uword)f, radix, 0, 1);
11264    }
11265  } else if(C_isnan(f)) {
11266    p = "+nan.0";
11267  } else if(C_isinf(f)) {
11268    p = f > 0 ? "+inf.0" : "-inf.0";
11269  } else { /* Doesn't fit an unsigned int and not "special"; use system libc */
11270    C_snprintf(buffer, STRING_BUFFER_SIZE, C_text("%.*g"),
11271               /* XXX: flonum_print_precision */
11272               (int)C_unfix(C_get_print_precision()), f);
11273    buffer[STRING_BUFFER_SIZE-1] = '\0';
11274
11275    if((p = C_strpbrk(buffer, C_text(".eE"))) == NULL) {
11276      /* Already checked for these, so shouldn't happen */
11277      assert(*buffer != 'i'); /* "inf" */
11278      assert(*buffer != 'n'); /* "nan" */
11279      /* Ensure integral flonums w/o expt are always terminated by .0 */
11280#if defined(HAVE_STRLCAT) || !defined(C_strcat)
11281      C_strlcat(buffer, C_text(".0"), sizeof(buffer));
11282#else
11283      C_strcat(buffer, C_text(".0"));
11284#endif
11285    }
11286    p = buffer;
11287  }
11288
11289  radix = C_strlen(p);
11290  a = C_alloc(C_SIZEOF_STRING(radix));
11291  radix = C_string(&a, radix, p);
11292  C_kontinue(k, radix);
11293}
11294
11295void C_ccall C_integer_to_string(C_word c, C_word *av)
11296{
11297  C_word
11298    /* self = av[ 0 ] */
11299    k = av[ 1 ],
11300    num = av[ 2 ],
11301    radix = ((c == 3) ? 10 : C_unfix(av[ 3 ]));
11302
11303  if (num & C_FIXNUM_BIT) {
11304    C_fixnum_to_string(4, av); /* reuse av */
11305  } else {
11306    int len, radix_shift;
11307    size_t nbits;
11308
11309    if ((radix < 2) || (radix > 16)) {
11310      barf(C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR, "number->string", C_fix(radix));
11311    }
11312
11313    /* Approximation of the number of radix digits we'll need.  We try
11314     * to be as precise as possible to avoid memmove overhead at the end
11315     * of the non-powers of two part of the conversion procedure, which
11316     * we may need to do because we write strings back-to-front, and
11317     * pointers must be aligned (even for byte blocks).
11318     */
11319    len = C_bignum_size(num)-1;
11320
11321    nbits  = (size_t)len * C_BIGNUM_DIGIT_LENGTH;
11322    nbits += C_ilen(C_bignum_digits(num)[len]);
11323
11324    len = C_ilen(radix)-1;
11325    len = (nbits + len - 1) / len;
11326    len += C_bignum_negativep(num) ? 1 : 0; /* Add space for negative sign */
11327
11328    radix_shift = C_ilen(radix) - 1;
11329    if (len > C_RECURSIVE_TO_STRING_THRESHOLD &&
11330        /* The power of two fast path is much faster than recursion */
11331        ((C_uword)1 << radix_shift) != radix) {
11332      try_extended_number("##sys#integer->string/recursive",
11333                          4, k, num, C_fix(radix), C_fix(len));
11334    } else {
11335      C_word kab[C_SIZEOF_CLOSURE(4)], *ka = kab, kav[4];
11336
11337      kav[ 0 ] = (C_word)NULL;   /* No "self" closure */
11338      kav[ 1 ] = C_closure(&ka, 4, (C_word)bignum_to_str_2,
11339                           k, num, C_fix(radix));
11340      kav[ 2 ] = C_fix(len + 1);
11341      kav[ 3 ] = C_SCHEME_FALSE; /* No initialization */
11342      C_allocate_bytevector(4, kav);
11343    }
11344  }
11345}
11346
11347static void bignum_to_str_2(C_word c, C_word *av)
11348{
11349  static char *characters = "0123456789abcdef";
11350  C_word
11351    self = av[ 0 ],
11352    string = av[ 1 ],
11353    k = C_block_item(self, 1),
11354    bignum = C_block_item(self, 2),
11355    radix = C_unfix(C_block_item(self, 3));
11356  char
11357    *buf = C_c_string(string),
11358    *index = buf + C_header_size(string) - 2;
11359  int radix_shift,
11360    negp = (C_bignum_negativep(bignum) ? 1 : 0);
11361  C_word us[ 5 ], *a = us;
11362
11363  *(index + 1) = '\0';
11364  radix_shift = C_ilen(radix) - 1;
11365  if (((C_uword)1 << radix_shift) == radix) { /* Power of two? */
11366    int radix_mask = radix - 1, big_digit_len = 0, radix_digit;
11367    C_uword *scan, *end, big_digit = 0;
11368
11369    scan = C_bignum_digits(bignum);
11370    end = scan + C_bignum_size(bignum);
11371
11372    while (scan < end) {
11373      /* If radix isn't an exact divisor of digit length, handle overlap */
11374      if (big_digit_len == 0) {
11375        big_digit = *scan++;
11376        big_digit_len = C_BIGNUM_DIGIT_LENGTH;
11377      } else {
11378        assert(index >= buf);
11379	radix_digit = big_digit;
11380        big_digit = *scan++;
11381	radix_digit |= ((unsigned int)big_digit << big_digit_len) & radix_mask;
11382        *index-- = characters[radix_digit];
11383	big_digit >>= (radix_shift - big_digit_len);
11384        big_digit_len = C_BIGNUM_DIGIT_LENGTH - (radix_shift - big_digit_len);
11385      }
11386
11387      while(big_digit_len >= radix_shift && index >= buf) {
11388	radix_digit = big_digit & radix_mask;
11389        *index-- = characters[radix_digit];
11390	big_digit >>= radix_shift;
11391	big_digit_len -= radix_shift;
11392      }
11393    }
11394
11395    assert(big_digit < radix);
11396
11397    /* Final digit (like overlap at start of while loop) */
11398    if (big_digit) *index-- = characters[big_digit];
11399
11400    if (negp) {
11401      /* Loop above might've overwritten sign position with a zero */
11402      if (*(index+1) == '0') *(index+1) = '-';
11403      else *index-- = '-';
11404    }
11405
11406    /* Length calculation is always precise for radix powers of two. */
11407    assert(index == buf-1);
11408  } else {
11409    C_uword base, *start, *scan, big_digit;
11410    C_word working_copy;
11411    int steps, i;
11412
11413    working_copy = allocate_tmp_bignum(C_fix(C_bignum_size(bignum)),
11414                                       C_mk_bool(negp), C_SCHEME_FALSE);
11415    bignum_digits_destructive_copy(working_copy, bignum);
11416
11417    start = C_bignum_digits(working_copy);
11418
11419    scan = start + C_bignum_size(bignum);
11420    /* Calculate the largest power of radix that fits a halfdigit:
11421     * steps = log10(2^halfdigit_bits), base = 10^steps
11422     */
11423    for(steps = 0, base = radix; C_fitsinbignumhalfdigitp(base); base *= radix)
11424      steps++;
11425
11426    base /= radix; /* Back down: we overshot in the loop */
11427
11428    while (scan > start) {
11429      big_digit = bignum_digits_destructive_scale_down(start, scan, base);
11430
11431      if (*(scan-1) == 0) scan--; /* Adjust if we exhausted the highest digit */
11432
11433      for(i = 0; i < steps && index >= buf; ++i) {
11434	C_word tmp = big_digit / radix;
11435        *index-- = characters[big_digit - (tmp*radix)]; /* big_digit % radix */
11436        big_digit = tmp;
11437      }
11438    }
11439    assert(index >= buf-1);
11440    free_tmp_bignum(working_copy);
11441
11442    /* Move index onto first nonzero digit.  We're writing a bignum
11443       here: it can't consist of only zeroes. */
11444    while(*++index == '0');
11445
11446    if (negp) *--index = '-';
11447
11448    /* Shorten with distance between start and index. */
11449    if (buf != index) {
11450      i = C_header_size(string) - (index - buf);
11451      C_memmove(buf, index, i); /* Move start of number to beginning. */
11452      buf[ i ] = '\0'; /* terminating 0 */
11453      C_block_header(string) = C_BYTEVECTOR_TYPE | i; /* Mutate strlength. */
11454    }
11455  }
11456
11457  C_kontinue(k, C_a_ustring(&a, 0, string, C_fix(C_header_size(string) - 1)));
11458}
11459
11460
11461/* XXX replace with inline routine */
11462void C_ccall C_make_structure(C_word c, C_word *av)
11463{
11464  C_word
11465    /* closure = av[ 0 ] */
11466    k = av[ 1 ],
11467    type = av[ 2 ],
11468    size = c - 3,
11469    *s, s0;
11470
11471  if(!C_demand(size + 2))
11472    C_save_and_reclaim((void *)C_make_structure, c, av);
11473
11474  s = C_alloc(C_SIZEOF_STRUCTURE(size + 1)),
11475  s0 = (C_word)s;
11476  *(s++) = C_STRUCTURE_TYPE | (size + 1);
11477  *(s++) = type;
11478  av += 3;
11479
11480  while(size--)
11481    *(s++) = *(av++);
11482
11483  C_kontinue(k, s0);
11484}
11485
11486
11487/* XXX replace with inline routine */
11488void C_ccall C_make_symbol(C_word c, C_word *av)
11489{
11490  C_word
11491    /* closure = av[ 0 ] */
11492    k = av[ 1 ],
11493    name = av[ 2 ],
11494    ab[ C_SIZEOF_SYMBOL ],
11495    *a = ab,
11496    s0 = (C_word)a;
11497
11498  *(a++) = C_SYMBOL_TYPE | (C_SIZEOF_SYMBOL - 1);
11499  *(a++) = C_SCHEME_UNBOUND;
11500  *(a++) = name;
11501  *a = C_SCHEME_END_OF_LIST;
11502  C_kontinue(k, s0);
11503}
11504
11505
11506/* XXX replace with inline routine */
11507void C_ccall C_make_pointer(C_word c, C_word *av)
11508{
11509  C_word
11510    /* closure = av[ 0 ] */
11511    k = av[ 1 ],
11512    ab[ 2 ],
11513    *a = ab,
11514    p;
11515
11516  p = C_mpointer(&a, NULL);
11517  C_kontinue(k, p);
11518}
11519
11520
11521/* XXX replace with inline routine */
11522void C_ccall C_make_tagged_pointer(C_word c, C_word *av)
11523{
11524  C_word
11525    /* closure = av[ 0 ] */
11526    k = av[ 1 ],
11527    tag = av[ 2 ],
11528    ab[ 3 ],
11529    *a = ab,
11530    p;
11531
11532  p = C_taggedmpointer(&a, tag, NULL);
11533  C_kontinue(k, p);
11534}
11535
11536
11537void C_ccall C_ensure_heap_reserve(C_word c, C_word *av)
11538{
11539  C_word
11540    /* closure = av[ 0 ] */
11541    k = av[ 1 ],
11542    n = av[ 2 ],
11543    *p;
11544
11545  C_save(k);
11546
11547  if(!C_demand(C_bytestowords(C_unfix(n))))
11548    C_reclaim((void *)generic_trampoline, 1);
11549
11550  p = C_temporary_stack;
11551  C_temporary_stack = C_temporary_stack_bottom;
11552  generic_trampoline(0, p);
11553}
11554
11555
11556void C_ccall generic_trampoline(C_word c, C_word *av)
11557{
11558  C_word k = av[ 0 ];
11559
11560  C_kontinue(k, C_SCHEME_UNDEFINED);
11561}
11562
11563
11564void C_ccall C_return_to_host(C_word c, C_word *av)
11565{
11566  C_word
11567    /* closure = av[ 0 ] */
11568    k = av[ 1 ];
11569
11570  return_to_host = 1;
11571  C_save(k);
11572  C_reclaim((void *)generic_trampoline, 1);
11573}
11574
11575
11576void C_ccall C_get_symbol_table_info(C_word c, C_word *av)
11577{
11578  C_word
11579    /* closure = av[ 0 ] */
11580    k = av[ 1 ];
11581  double d1, d2;
11582  int n = 0, total;
11583  C_SYMBOL_TABLE *stp;
11584  C_word
11585    x, y,
11586    ab[ WORDS_PER_FLONUM * 2 + C_SIZEOF_VECTOR(4) ],
11587    *a = ab;
11588
11589  for(stp = symbol_table_list; stp != NULL; stp = stp->next)
11590    ++n;
11591
11592  d1 = compute_symbol_table_load(&d2, &total);
11593  x = C_flonum(&a, d1);		/* load */
11594  y = C_flonum(&a, d2);		/* avg bucket length */
11595  C_kontinue(k, C_vector(&a, 4, x, y, C_fix(total), C_fix(n)));
11596}
11597
11598
11599void C_ccall C_get_memory_info(C_word c, C_word *av)
11600{
11601  C_word
11602    /* closure = av[ 0 ] */
11603    k = av[ 1 ],
11604    ab[ C_SIZEOF_VECTOR(2) ],
11605    *a = ab;
11606
11607  C_kontinue(k, C_vector(&a, 2, C_fix(heap_size), C_fix(stack_size)));
11608}
11609
11610
11611void C_ccall C_context_switch(C_word c, C_word *av)
11612{
11613  C_word
11614    /* closure = av[ 0 ] */
11615    state = av[ 2 ],
11616    n = C_header_size(state) - 1,
11617    adrs = C_block_item(state, 0),
11618    *av2;
11619  C_proc tp = (C_proc)C_block_item(adrs,0);
11620
11621  /* Copy argvector because it may be mutated in-place.  The state
11622   * vector should not be re-invoked(?), but it can be kept alive
11623   * during GC, so the mutated argvector/state slots may turn stale.
11624   */
11625  av2 = C_alloc(n);
11626  C_memcpy(av2, (C_word *)state + 2, n * sizeof(C_word));
11627  tp(n, av2);
11628}
11629
11630
11631void C_ccall C_peek_signed_integer(C_word c, C_word *av)
11632{
11633  C_word
11634    /* closure = av[ 0 ] */
11635    k = av[ 1 ],
11636    v = av[ 2 ],
11637    index = av[ 3 ],
11638    x = C_block_item(v, C_unfix(index)),
11639    ab[C_SIZEOF_BIGNUM(1)], *a = ab;
11640
11641  C_uword num = ((C_word *)C_data_pointer(v))[ C_unfix(index) ];
11642
11643  C_kontinue(k, C_int_to_num(&a, num));
11644}
11645
11646
11647void C_ccall C_peek_unsigned_integer(C_word c, C_word *av)
11648{
11649  C_word
11650    /* closure = av[ 0 ] */
11651    k = av[ 1 ],
11652    v = av[ 2 ],
11653    index = av[ 3 ],
11654    x = C_block_item(v, C_unfix(index)),
11655    ab[C_SIZEOF_BIGNUM(1)], *a = ab;
11656
11657  C_uword num = ((C_word *)C_data_pointer(v))[ C_unfix(index) ];
11658
11659  C_kontinue(k, C_unsigned_int_to_num(&a, num));
11660}
11661
11662void C_ccall C_peek_int64(C_word c, C_word *av)
11663{
11664  C_word
11665    /* closure = av[ 0 ] */
11666    k = av[ 1 ],
11667    v = av[ 2 ],
11668    index = av[ 3 ],
11669    x = C_block_item(v, C_unfix(index)),
11670    ab[C_SIZEOF_BIGNUM(2)], *a = ab;
11671
11672  C_s64 num = ((C_s64 *)C_data_pointer(v))[ C_unfix(index) ];
11673
11674  C_kontinue(k, C_int64_to_num(&a, num));
11675}
11676
11677
11678void C_ccall C_peek_uint64(C_word c, C_word *av)
11679{
11680  C_word
11681    /* closure = av[ 0 ] */
11682    k = av[ 1 ],
11683    v = av[ 2 ],
11684    index = av[ 3 ],
11685    x = C_block_item(v, C_unfix(index)),
11686    ab[C_SIZEOF_BIGNUM(2)], *a = ab;
11687
11688  C_u64 num = ((C_u64 *)C_data_pointer(v))[ C_unfix(index) ];
11689
11690  C_kontinue(k, C_uint64_to_num(&a, num));
11691}
11692
11693
11694void C_ccall C_decode_seconds(C_word c, C_word *av)
11695{
11696  C_word
11697    /* closure = av[ 0 ] */
11698    k = av[ 1 ],
11699    secs = av[ 2 ],
11700    mode = av[ 3 ];
11701  time_t tsecs;
11702  struct tm *tmt;
11703  C_word
11704    ab[ C_SIZEOF_VECTOR(10) ],
11705    *a = ab,
11706    info;
11707
11708  tsecs = (time_t)C_num_to_int64(secs);
11709
11710  if(mode == C_SCHEME_FALSE) tmt = C_localtime(&tsecs);
11711  else tmt = C_gmtime(&tsecs);
11712
11713  if(tmt  == NULL)
11714    C_kontinue(k, C_SCHEME_FALSE);
11715
11716  info = C_vector(&a, 10, C_fix(tmt->tm_sec), C_fix(tmt->tm_min), C_fix(tmt->tm_hour),
11717		  C_fix(tmt->tm_mday), C_fix(tmt->tm_mon), C_fix(tmt->tm_year),
11718		  C_fix(tmt->tm_wday), C_fix(tmt->tm_yday),
11719		  tmt->tm_isdst > 0 ? C_SCHEME_TRUE : C_SCHEME_FALSE,
11720#ifdef C_GNU_ENV
11721                  /* negative for west of UTC, but we want positive */
11722		  C_fix(-tmt->tm_gmtoff)
11723#elif defined(__CYGWIN__) || defined(__MINGW32__) || defined(_WIN32) || defined(__WINNT__)
11724                  C_fix(mode == C_SCHEME_FALSE ? _timezone : 0) /* does not account for DST */
11725#else
11726                  C_fix(mode == C_SCHEME_FALSE ? timezone : 0)  /* does not account for DST */
11727#endif
11728		  );
11729  C_kontinue(k, info);
11730}
11731
11732
11733void C_ccall C_machine_byte_order(C_word c, C_word *av)
11734{
11735  C_word
11736    /* closure = av[ 0 ] */
11737    k = av[ 1 ];
11738  char *str;
11739  C_word *a, s;
11740
11741  if(c != 2) C_bad_argc(c, 2);
11742
11743#if defined(C_MACHINE_BYTE_ORDER)
11744  str = C_MACHINE_BYTE_ORDER;
11745#else
11746  C_cblock
11747    static C_word one_two_three = 123;
11748    str = (*((C_char *)&one_two_three) != 123) ? "big-endian" : "little-endian";
11749  C_cblockend;
11750#endif
11751
11752  a = C_alloc(C_SIZEOF_STRING(strlen(str)));
11753  s = C_string2(&a, str);
11754
11755  C_kontinue(k, s);
11756}
11757
11758
11759void C_ccall C_machine_type(C_word c, C_word *av)
11760{
11761  C_word
11762    /* closure = av[ 0 ] */
11763    k = av[ 1 ],
11764    *a, s;
11765
11766  if(c != 2) C_bad_argc(c, 2);
11767
11768  a = C_alloc(C_SIZEOF_STRING(C_strlen(C_MACHINE_TYPE)));
11769  s = C_string2(&a, C_MACHINE_TYPE);
11770
11771  C_kontinue(k, s);
11772}
11773
11774
11775void C_ccall C_software_type(C_word c, C_word *av)
11776{
11777  C_word
11778    /* closure = av[ 0 ] */
11779    k = av[ 1 ],
11780    *a, s;
11781
11782  if(c != 2) C_bad_argc(c, 2);
11783
11784  a = C_alloc(C_SIZEOF_STRING(C_strlen(C_SOFTWARE_TYPE)));
11785  s = C_string2(&a, C_SOFTWARE_TYPE);
11786
11787 C_kontinue(k, s);
11788}
11789
11790
11791void C_ccall C_build_platform(C_word c, C_word *av)
11792{
11793  C_word
11794    /* closure = av[ 0 ] */
11795    k = av[ 1 ],
11796    *a, s;
11797
11798  if(c != 2) C_bad_argc(c, 2);
11799
11800  a = C_alloc(C_SIZEOF_STRING(C_strlen(C_BUILD_PLATFORM)));
11801  s = C_string2(&a, C_BUILD_PLATFORM);
11802
11803 C_kontinue(k, s);
11804}
11805
11806
11807void C_ccall C_software_version(C_word c, C_word *av)
11808{
11809  C_word
11810    /* closure = av[ 0 ] */
11811    k = av[ 1 ],
11812    *a, s;
11813
11814  if(c != 2) C_bad_argc(c, 2);
11815
11816  a = C_alloc(C_SIZEOF_STRING(C_strlen(C_SOFTWARE_VERSION)));
11817  s = C_string2(&a, C_SOFTWARE_VERSION);
11818
11819 C_kontinue(k, s);
11820}
11821
11822
11823/* Register finalizer: */
11824
11825void C_ccall C_register_finalizer(C_word c, C_word *av)
11826{
11827  C_word
11828    /* closure = av[ 0 ]) */
11829    k = av[ 1 ],
11830    x = av[ 2 ],
11831    proc = av[ 3 ];
11832
11833  if(C_immediatep(x) ||
11834     (!C_in_stackp(x) && !C_in_heapp(x) && !C_in_scratchspacep(x)))
11835    C_kontinue(k, x); /* not GCable */
11836
11837  C_do_register_finalizer(x, proc);
11838  C_kontinue(k, x);
11839}
11840
11841
11842/*XXX could this be made static? is it used in eggs somewhere?
11843  if not, declare as fcall/regparm (and static, remove from chicken.h)
11844 */
11845void C_ccall C_do_register_finalizer(C_word x, C_word proc)
11846{
11847  C_word *ptr;
11848  int n, i;
11849  FINALIZER_NODE *flist;
11850
11851  if(finalizer_free_list == NULL) {
11852    if((flist = (FINALIZER_NODE *)C_malloc(sizeof(FINALIZER_NODE))) == NULL)
11853      panic(C_text("out of memory - cannot allocate finalizer node"));
11854
11855    ++allocated_finalizer_count;
11856  }
11857  else {
11858    flist = finalizer_free_list;
11859    finalizer_free_list = flist->next;
11860  }
11861
11862  if(finalizer_list != NULL) finalizer_list->previous = flist;
11863
11864  flist->previous = NULL;
11865  flist->next = finalizer_list;
11866  finalizer_list = flist;
11867
11868  if(C_in_stackp(x)) C_mutate_slot(&flist->item, x);
11869  else flist->item = x;
11870
11871  if(C_in_stackp(proc)) C_mutate_slot(&flist->finalizer, proc);
11872  else flist->finalizer = proc;
11873
11874  ++live_finalizer_count;
11875}
11876
11877
11878/*XXX same here */
11879int C_do_unregister_finalizer(C_word x)
11880{
11881  int n;
11882  FINALIZER_NODE *flist;
11883
11884  for(flist = finalizer_list; flist != NULL; flist = flist->next) {
11885    if(flist->item == x) {
11886      if(flist->previous == NULL) finalizer_list = flist->next;
11887      else flist->previous->next = flist->next;
11888
11889      return 1;
11890    }
11891  }
11892
11893  return 0;
11894}
11895
11896
11897/* Dynamic loading of shared objects: */
11898
11899void C_ccall C_set_dlopen_flags(C_word c, C_word *av)
11900{
11901  C_word
11902    /* closure = av[ 0 ] */
11903    k = av[ 1 ],
11904    now = av[ 2 ],
11905    global = av[ 3 ];
11906
11907#if !defined(NO_DLOAD2) && defined(HAVE_DLFCN_H)
11908  dlopen_flags = (C_truep(now) ? RTLD_NOW : RTLD_LAZY) | (C_truep(global) ? RTLD_GLOBAL : RTLD_LOCAL);
11909#endif
11910  C_kontinue(k, C_SCHEME_UNDEFINED);
11911}
11912
11913
11914void C_ccall C_dload(C_word c, C_word *av)
11915{
11916  C_word
11917    /* closure = av[ 0 ] */
11918    k = av[ 1 ],
11919    name = av[ 2 ],
11920    entry = av[ 3 ];
11921
11922#if !defined(NO_DLOAD2) && (defined(HAVE_DLFCN_H) || defined(HAVE_DL_H) || (defined(HAVE_LOADLIBRARY) && defined(HAVE_GETPROCADDRESS)))
11923  /* Force minor GC: otherwise the lf may contain pointers to stack-data
11924     (stack allocated interned symbols, for example) */
11925  C_save_and_reclaim_args((void *)dload_2, 3, k, name, entry);
11926#endif
11927
11928  C_kontinue(k, C_SCHEME_FALSE);
11929}
11930
11931
11932#ifdef DLOAD_2_DEFINED
11933# undef DLOAD_2_DEFINED
11934#endif
11935
11936#if !defined(NO_DLOAD2) && defined(HAVE_DL_H) && !defined(DLOAD_2_DEFINED)
11937# ifdef __hpux__
11938#  define DLOAD_2_DEFINED
11939void C_ccall dload_2(C_word c, C_word *av0)
11940{
11941  void *handle, *p;
11942  C_word
11943    entry = av0[ 0 ],
11944    name = av0[ 1 ],
11945    k = av0[ 2 ],,
11946    av[ 2 ];
11947  C_char *mname = C_c_string(name);
11948
11949  /*
11950   * C_fprintf(C_stderr,
11951   *   "shl_loading %s : %s\n",
11952   *   (char *) C_c_string(name),
11953   *   (char *) C_c_string(entry));
11954   */
11955
11956  if ((handle = (void *) shl_load(mname,
11957				  BIND_IMMEDIATE | DYNAMIC_PATH,
11958				  0L)) != NULL) {
11959    shl_t shl_handle = (shl_t) handle;
11960
11961    /*** This version does not check for C_dynamic_and_unsafe. Fix it. */
11962    if (shl_findsym(&shl_handle, (char *) C_c_string(entry), TYPE_PROCEDURE, &p) == 0) {
11963      current_module_name = C_strdup(mname);
11964      current_module_handle = handle;
11965
11966      if(debug_mode) {
11967	C_dbg(C_text("debug"), C_text("loading compiled library %s (" UWORD_FORMAT_STRING ")\n"),
11968	      current_module_name, (C_uword)current_module_handle);
11969      }
11970
11971      av[ 0 ] = C_SCHEME_UNDEFINED;
11972      av[ 1 ] = k;
11973      ((C_proc)p)(2, av);       /* doesn't return */
11974    } else {
11975      C_dlerror = (char *) C_strerror(errno);
11976      shl_unload(shl_handle);
11977    }
11978  } else {
11979    C_dlerror = (char *) C_strerror(errno);
11980  }
11981
11982  C_kontinue(k, C_SCHEME_FALSE);
11983}
11984# endif
11985#endif
11986
11987
11988#if !defined(NO_DLOAD2) && defined(HAVE_DLFCN_H) && !defined(DLOAD_2_DEFINED)
11989# ifndef __hpux__
11990#  define DLOAD_2_DEFINED
11991void C_ccall dload_2(C_word c, C_word *av0)
11992{
11993  void *handle, *p, *p2;
11994  C_word
11995    entry = av0[ 0 ],
11996    name = av0[ 1 ],
11997    k = av0[ 2 ],
11998    av[ 2 ];
11999  C_char *topname = (C_char *)C_c_string(entry);
12000  C_char *mname = (C_char *)C_c_string(name);
12001  C_char *tmp;
12002  int tmp_len = 0;
12003
12004  if((handle = C_dlopen(mname, dlopen_flags)) != NULL) {
12005    if((p = C_dlsym(handle, topname)) == NULL) {
12006      tmp_len = C_strlen(topname) + 2;
12007      tmp = (C_char *)C_malloc(tmp_len);
12008
12009      if(tmp == NULL)
12010	panic(C_text("out of memory - cannot allocate toplevel name string"));
12011
12012      C_strlcpy(tmp, C_text("_"), tmp_len);
12013      C_strlcat(tmp, topname, tmp_len);
12014      p = C_dlsym(handle, tmp);
12015      C_free(tmp);
12016    }
12017
12018    if(p != NULL) {
12019      current_module_name = C_strdup(mname);
12020      current_module_handle = handle;
12021
12022      if(debug_mode) {
12023	C_dbg(C_text("debug"), C_text("loading compiled library %s (" UWORD_FORMAT_STRING ")\n"),
12024	      current_module_name, (C_uword)current_module_handle);
12025      }
12026
12027      av[ 0 ] = C_SCHEME_UNDEFINED;
12028      av[ 1 ] = k;
12029      ((C_proc)p)(2, av); /* doesn't return */
12030    }
12031
12032    C_dlclose(handle);
12033  }
12034
12035  C_dlerror = (char *)dlerror();
12036  C_kontinue(k, C_SCHEME_FALSE);
12037}
12038# endif
12039#endif
12040
12041
12042#if !defined(NO_DLOAD2) && (defined(HAVE_LOADLIBRARY) && defined(HAVE_GETPROCADDRESS)) && !defined(DLOAD_2_DEFINED)
12043# define DLOAD_2_DEFINED
12044void C_ccall dload_2(C_word c, C_word *av0)
12045{
12046  HINSTANCE handle;
12047  FARPROC p = NULL, p2;
12048  C_word
12049    entry = av0[ 0 ],
12050    name = av0[ 1 ],
12051    k = av0[ 2 ],
12052    av[ 2 ];
12053  C_char *topname = (C_char *)C_c_string(entry);
12054  C_char *mname = (C_char *)C_c_string(name);
12055
12056  /* cannot use LoadLibrary on non-DLLs, so we use extension checking */
12057  if (C_strlen(mname) >= 5) {
12058    C_char *n = mname;
12059    int l = C_strlen(mname);
12060    if (C_strncmp(".dll", n+l-4, 4) &&
12061        C_strncmp(".DLL", n+l-4, 4) &&
12062        C_strncmp(".so", n+l-3, 3) &&
12063	C_strncmp(".SO", n+l-3, 3))
12064      C_kontinue(k, C_SCHEME_FALSE);
12065  }
12066
12067  if((handle = LoadLibrary(mname)) != NULL) {
12068    if ((p = GetProcAddress(handle, topname)) != NULL) {
12069      current_module_name = C_strdup(mname);
12070      current_module_handle = handle;
12071
12072      if(debug_mode) {
12073	C_dbg(C_text("debug"), C_text("loading compiled library %s (" UWORD_FORMAT_STRING ")\n"),
12074	      current_module_name, (C_uword)current_module_handle);
12075      }
12076
12077      av[ 0 ] = C_SCHEME_UNDEFINED;
12078      av[ 1 ] = k;
12079      ((C_proc)p)(2, av);       /* doesn't return */
12080    }
12081    else FreeLibrary(handle);
12082  }
12083
12084  C_dlerror = (char *) C_strerror(errno);
12085  C_kontinue(k, C_SCHEME_FALSE);
12086}
12087#endif
12088
12089
12090void C_ccall C_become(C_word c, C_word *av)
12091{
12092  C_word
12093    /* closure = av[ 0 ] */
12094    k = av[ 1 ],
12095    table = av[ 2 ],
12096    tp, x, old, neu, i, *p;
12097
12098  i = forwarding_table_size;
12099  p = forwarding_table;
12100
12101  for(tp = table; tp != C_SCHEME_END_OF_LIST; tp = C_u_i_cdr(tp)) {
12102    x = C_u_i_car(tp);
12103    old = C_u_i_car(x);
12104    neu = C_u_i_cdr(x);
12105
12106    if(i == 0) {
12107      if((forwarding_table = (C_word *)realloc(forwarding_table, (forwarding_table_size + 1) * 4 * sizeof(C_word))) == NULL)
12108	panic(C_text("out of memory - cannot re-allocate forwarding table"));
12109
12110      i = forwarding_table_size;
12111      p = forwarding_table + forwarding_table_size * 2;
12112      forwarding_table_size *= 2;
12113    }
12114
12115    *(p++) = old;
12116    *(p++) = neu;
12117    --i;
12118  }
12119
12120  *p = 0;
12121  C_fromspace_top = C_fromspace_limit;
12122  C_save_and_reclaim_args((void *)become_2, 1, k);
12123}
12124
12125
12126void C_ccall become_2(C_word c, C_word *av)
12127{
12128  C_word k = av[ 0 ];
12129
12130  *forwarding_table = 0;
12131  C_kontinue(k, C_SCHEME_UNDEFINED);
12132}
12133
12134
12135C_regparm C_word
12136C_a_i_cpu_time(C_word **a, int c, C_word buf)
12137{
12138  C_word u, s = C_fix(0);
12139
12140#if defined(C_NONUNIX) || defined(__CYGWIN__)
12141  if(CLOCKS_PER_SEC == 1000) u = clock();
12142  else u = C_uint64_to_num(a, ((C_u64)clock() / CLOCKS_PER_SEC) * 1000);
12143#else
12144  struct rusage ru;
12145
12146  if(C_getrusage(RUSAGE_SELF, &ru) == -1) u = 0;
12147  else {
12148    u = C_uint64_to_num(a, (C_u64)ru.ru_utime.tv_sec * 1000 + ru.ru_utime.tv_usec / 1000);
12149    s = C_uint64_to_num(a, (C_u64)ru.ru_stime.tv_sec * 1000 + ru.ru_stime.tv_usec / 1000);
12150  }
12151#endif
12152
12153  /* buf must not be in nursery */
12154  C_set_block_item(buf, 0, u);
12155  C_set_block_item(buf, 1, s);
12156  return buf;
12157}
12158
12159
12160C_regparm C_word C_a_i_make_locative(C_word **a, int c, C_word type, C_word object, C_word index, C_word weak)
12161{
12162  C_word *loc = *a;
12163  int offset, i, in = C_unfix(index);
12164  *a = loc + C_SIZEOF_LOCATIVE;
12165
12166  loc[ 0 ] = C_LOCATIVE_TAG;
12167
12168  switch(C_unfix(type)) {
12169  case C_SLOT_LOCATIVE: in *= sizeof(C_word); break;
12170  case C_U16_LOCATIVE:
12171  case C_S16_LOCATIVE: in *= 2; break;
12172  case C_U32_LOCATIVE:
12173  case C_F32_LOCATIVE:
12174  case C_S32_LOCATIVE: in *= 4; break;
12175  case C_U64_LOCATIVE:
12176  case C_S64_LOCATIVE:
12177  case C_F64_LOCATIVE: in *= 8; break;
12178  }
12179
12180  offset = in + sizeof(C_header);
12181  loc[ 1 ] = object + offset;
12182  loc[ 2 ] = C_fix(offset);
12183  loc[ 3 ] = type;
12184  loc[ 4 ] = C_truep(weak) ? C_SCHEME_FALSE : object;
12185
12186  return (C_word)loc;
12187}
12188
12189C_regparm C_word C_a_i_locative_ref(C_word **a, int c, C_word loc)
12190{
12191  C_word *ptr;
12192
12193  if(C_immediatep(loc) || C_block_header(loc) != C_LOCATIVE_TAG)
12194    barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-ref", loc);
12195
12196  ptr = (C_word *)C_block_item(loc, 0);
12197
12198  if(ptr == NULL) barf(C_LOST_LOCATIVE_ERROR, "locative-ref", loc);
12199
12200  switch(C_unfix(C_block_item(loc, 2))) {
12201  case C_SLOT_LOCATIVE: return *ptr;
12202  case C_CHAR_LOCATIVE: return C_utf_decode_ptr((C_char *)ptr);
12203  case C_U8_LOCATIVE: return C_fix(*((unsigned char *)ptr));
12204  case C_S8_LOCATIVE: return C_fix(*((char *)ptr));
12205  case C_U16_LOCATIVE: return C_fix(*((unsigned short *)ptr));
12206  case C_S16_LOCATIVE: return C_fix(*((short *)ptr));
12207  case C_U32_LOCATIVE: return C_unsigned_int_to_num(a, *((C_u32 *)ptr));
12208  case C_S32_LOCATIVE: return C_int_to_num(a, *((C_s32 *)ptr));
12209  case C_U64_LOCATIVE: return C_uint64_to_num(a, *((C_u64 *)ptr));
12210  case C_S64_LOCATIVE: return C_int64_to_num(a, *((C_s64 *)ptr));
12211  case C_F32_LOCATIVE: return C_flonum(a, *((float *)ptr));
12212  case C_F64_LOCATIVE: return C_flonum(a, *((double *)ptr));
12213  default: panic(C_text("bad locative type"));
12214  }
12215}
12216
12217C_regparm C_word C_i_locative_set(C_word loc, C_word x)
12218{
12219  C_word *ptr, val;
12220
12221  if(C_immediatep(loc) || C_block_header(loc) != C_LOCATIVE_TAG)
12222    barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", loc);
12223
12224  ptr = (C_word *)C_block_item(loc, 0);
12225
12226  if(ptr == NULL)
12227    barf(C_LOST_LOCATIVE_ERROR, "locative-set!", loc);
12228
12229  switch(C_unfix(C_block_item(loc, 2))) {
12230  case C_SLOT_LOCATIVE: C_mutate(ptr, x); break;
12231
12232  case C_CHAR_LOCATIVE:
12233    if((x & C_IMMEDIATE_TYPE_BITS) != C_CHARACTER_BITS)
12234      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12235
12236    /* does not check for exceeded buffer length! */
12237    C_utf_encode((C_char *)ptr, C_character_code(x));
12238    break;
12239
12240  case C_U8_LOCATIVE:
12241    if((x & C_FIXNUM_BIT) == 0)
12242      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12243
12244    *((unsigned char *)ptr) = C_unfix(x);
12245    break;
12246
12247  case C_S8_LOCATIVE:
12248    if((x & C_FIXNUM_BIT) == 0)
12249      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12250
12251    *((char *)ptr) = C_unfix(x);
12252    break;
12253
12254  case C_U16_LOCATIVE:
12255    if((x & C_FIXNUM_BIT) == 0)
12256      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12257
12258    *((unsigned short *)ptr) = C_unfix(x);
12259    break;
12260
12261  case C_S16_LOCATIVE:
12262    if((x & C_FIXNUM_BIT) == 0)
12263      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12264
12265    *((short *)ptr) = C_unfix(x);
12266    break;
12267
12268  case C_U32_LOCATIVE:
12269    if(!C_truep(C_i_exact_integerp(x)))
12270      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12271
12272    *((C_u32 *)ptr) = C_num_to_unsigned_int(x);
12273    break;
12274
12275  case C_S32_LOCATIVE:
12276    if(!C_truep(C_i_exact_integerp(x)))
12277      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12278
12279    *((C_s32 *)ptr) = C_num_to_int(x);
12280    break;
12281
12282  case C_U64_LOCATIVE:
12283    if(!C_truep(C_i_exact_integerp(x)))
12284      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12285
12286    *((C_u64 *)ptr) = C_num_to_uint64(x);
12287    break;
12288
12289  case C_S64_LOCATIVE:
12290    if(!C_truep(C_i_exact_integerp(x)))
12291      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12292
12293    *((C_s64 *)ptr) = C_num_to_int64(x);
12294    break;
12295
12296  case C_F32_LOCATIVE:
12297    if(C_immediatep(x) || C_block_header(x) != C_FLONUM_TAG)
12298      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12299
12300    *((float *)ptr) = C_flonum_magnitude(x);
12301    break;
12302
12303  case C_F64_LOCATIVE:
12304    if(C_immediatep(x) || C_block_header(x) != C_FLONUM_TAG)
12305      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12306
12307    *((double *)ptr) = C_flonum_magnitude(x);
12308    break;
12309
12310  default: panic(C_text("bad locative type"));
12311  }
12312
12313  return C_SCHEME_UNDEFINED;
12314}
12315
12316
12317C_regparm C_word C_i_locative_to_object(C_word loc)
12318{
12319  C_word *ptr;
12320
12321  if(C_immediatep(loc) || C_block_header(loc) != C_LOCATIVE_TAG)
12322    barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative->object", loc);
12323
12324  ptr = (C_word *)C_block_item(loc, 0);
12325
12326  if(ptr == NULL) return C_SCHEME_FALSE;
12327  else return (C_word)ptr - C_unfix(C_block_item(loc, 1));
12328}
12329
12330
12331C_regparm C_word C_i_locative_index(C_word loc)
12332{
12333  int bytes;
12334
12335  if(C_immediatep(loc) || C_block_header(loc) != C_LOCATIVE_TAG)
12336    barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-index", loc);
12337
12338  bytes = C_unfix(C_block_item(loc, 1)) - sizeof(C_header);
12339
12340  switch(C_unfix(C_block_item(loc, 2))) {
12341  case C_SLOT_LOCATIVE: return C_fix(bytes/sizeof(C_word)); break;
12342
12343  case C_CHAR_LOCATIVE:
12344    { C_word x = C_i_locative_to_object(loc);
12345      if(x == C_SCHEME_FALSE)
12346        barf(C_LOST_LOCATIVE_ERROR, "locative-index", loc);
12347      return C_fix(C_utf_char_position(x, bytes)); }
12348
12349  case C_U8_LOCATIVE:
12350  case C_S8_LOCATIVE: return C_fix(bytes); break;
12351
12352  case C_U16_LOCATIVE:
12353  case C_S16_LOCATIVE: return C_fix(bytes/2); break;
12354
12355  case C_U32_LOCATIVE:
12356  case C_S32_LOCATIVE:
12357  case C_F32_LOCATIVE: return C_fix(bytes/4); break;
12358
12359  case C_U64_LOCATIVE:
12360  case C_S64_LOCATIVE:
12361  case C_F64_LOCATIVE: return C_fix(bytes/8); break;
12362
12363  default: panic(C_text("bad locative type"));
12364  }
12365}
12366
12367
12368/* GC protection of user-variables: */
12369
12370C_regparm void C_gc_protect(C_word **addr, int n)
12371{
12372  int k;
12373
12374  if(collectibles_top + n >= collectibles_limit) {
12375    k = collectibles_limit - collectibles;
12376    collectibles = (C_word **)C_realloc(collectibles, sizeof(C_word *) * k * 2);
12377
12378    if(collectibles == NULL)
12379      panic(C_text("out of memory - cannot allocate GC protection vector"));
12380
12381    collectibles_top = collectibles + k;
12382    collectibles_limit = collectibles + k * 2;
12383  }
12384
12385  C_memcpy(collectibles_top, addr, n * sizeof(C_word *));
12386  collectibles_top += n;
12387}
12388
12389
12390C_regparm void C_gc_unprotect(int n)
12391{
12392  collectibles_top -= n;
12393}
12394
12395
12396/* Map procedure-ptr to id or id to ptr: */
12397
12398C_char *C_lookup_procedure_id(void *ptr)
12399{
12400  LF_LIST *lfl;
12401  C_PTABLE_ENTRY *pt;
12402
12403  for(lfl = lf_list; lfl != NULL; lfl = lfl->next) {
12404    pt = lfl->ptable;
12405
12406    if(pt != NULL) {
12407      while(pt->id != NULL) {
12408	if(pt->ptr == ptr) return pt->id;
12409	else ++pt;
12410      }
12411    }
12412  }
12413
12414  return NULL;
12415}
12416
12417
12418void *C_lookup_procedure_ptr(C_char *id)
12419{
12420  LF_LIST *lfl;
12421  C_PTABLE_ENTRY *pt;
12422
12423  for(lfl = lf_list; lfl != NULL; lfl = lfl->next) {
12424    pt = lfl->ptable;
12425
12426    if(pt != NULL) {
12427      while(pt->id != NULL) {
12428	if(!C_strcmp(id, pt->id)) return pt->ptr;
12429	else ++pt;
12430      }
12431    }
12432  }
12433
12434  return NULL;
12435}
12436
12437
12438void C_ccall C_copy_closure(C_word c, C_word *av)
12439{
12440  C_word
12441    /* closure = av[ 0 ] */
12442    k = av[ 1 ],
12443    proc = av[ 2 ],
12444    *p;
12445  int n = C_header_size(proc);
12446
12447  if(!C_demand(n + 1))
12448    C_save_and_reclaim_args((void *)copy_closure_2, 2, proc, k);
12449  else {
12450    C_save(proc);
12451    C_save(k);
12452    p = C_temporary_stack;
12453    C_temporary_stack = C_temporary_stack_bottom;
12454    copy_closure_2(0, p);
12455  }
12456}
12457
12458
12459static void C_ccall copy_closure_2(C_word c, C_word *av)
12460{
12461  C_word
12462    k = av[ 0 ],
12463    proc = av[ 1 ];
12464  int cells = C_header_size(proc);
12465  C_word
12466    *ptr = C_alloc(C_SIZEOF_CLOSURE(cells)),
12467    *p = ptr;
12468
12469  *(p++) = C_CLOSURE_TYPE | cells;
12470  /* this is only allowed because the storage is freshly allocated: */
12471  C_memcpy_slots(p, C_data_pointer(proc), cells);
12472  C_kontinue(k, (C_word)ptr);
12473}
12474
12475
12476/* Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn */
12477
12478void C_ccall C_call_with_cthulhu(C_word c, C_word *av)
12479{
12480  C_word
12481    proc = av[ 2 ],
12482    *a = C_alloc(C_SIZEOF_CLOSURE(1)),
12483    av2[ 2 ];
12484
12485  av2[ 0 ] = proc;
12486  av2[ 1 ] = C_closure(&a, 1, (C_word)termination_continuation); /* k */
12487  C_do_apply(2, av2);
12488}
12489
12490
12491/* fixnum arithmetic with overflow detection (from "Hacker's Delight" by Hank Warren)
12492   These routines return #f if the operation failed due to overflow.
12493 */
12494
12495C_regparm C_word C_i_o_fixnum_plus(C_word n1, C_word n2)
12496{
12497  C_word x1, x2, s;
12498
12499  if((n1 & C_FIXNUM_BIT) == 0 || (n2 & C_FIXNUM_BIT) == 0) return C_SCHEME_FALSE;
12500
12501  x1 = C_unfix(n1);
12502  x2 = C_unfix(n2);
12503  s = x1 + x2;
12504
12505#ifdef C_SIXTY_FOUR
12506  if((((s ^ x1) & (s ^ x2)) >> 62) != 0) return C_SCHEME_FALSE;
12507#else
12508  if((((s ^ x1) & (s ^ x2)) >> 30) != 0) return C_SCHEME_FALSE;
12509#endif
12510  else return C_fix(s);
12511}
12512
12513
12514C_regparm C_word C_i_o_fixnum_difference(C_word n1, C_word n2)
12515{
12516  C_word x1, x2, s;
12517
12518  if((n1 & C_FIXNUM_BIT) == 0 || (n2 & C_FIXNUM_BIT) == 0) return C_SCHEME_FALSE;
12519
12520  x1 = C_unfix(n1);
12521  x2 = C_unfix(n2);
12522  s = x1 - x2;
12523
12524#ifdef C_SIXTY_FOUR
12525  if((((s ^ x1) & ~(s ^ x2)) >> 62) != 0) return C_SCHEME_FALSE;
12526#else
12527  if((((s ^ x1) & ~(s ^ x2)) >> 30) != 0) return C_SCHEME_FALSE;
12528#endif
12529  else return C_fix(s);
12530}
12531
12532
12533C_regparm C_word C_i_o_fixnum_times(C_word n1, C_word n2)
12534{
12535  C_word x1, x2;
12536  C_uword x1u, x2u;
12537#ifdef C_SIXTY_FOUR
12538# ifdef C_LLP
12539  C_uword c = 1ULL<<63ULL;
12540# else
12541  C_uword c = 1UL<<63UL;
12542# endif
12543#else
12544  C_uword c = 1UL<<31UL;
12545#endif
12546
12547  if((n1 & C_FIXNUM_BIT) == 0 || (n2 & C_FIXNUM_BIT) == 0) return C_SCHEME_FALSE;
12548
12549  if((n1 & C_INT_SIGN_BIT) == (n2 & C_INT_SIGN_BIT)) --c;
12550
12551  x1 = C_unfix(n1);
12552  x2 = C_unfix(n2);
12553  x1u = x1 < 0 ? -x1 : x1;
12554  x2u = x2 < 0 ? -x2 : x2;
12555
12556  if(x2u != 0 && x1u > (c / x2u)) return C_SCHEME_FALSE;
12557
12558  x1 = x1 * x2;
12559
12560  if(C_fitsinfixnump(x1)) return C_fix(x1);
12561  else return C_SCHEME_FALSE;
12562}
12563
12564
12565C_regparm C_word C_i_o_fixnum_quotient(C_word n1, C_word n2)
12566{
12567  C_word x1, x2;
12568
12569  if((n1 & C_FIXNUM_BIT) == 0 || (n2 & C_FIXNUM_BIT) == 0) return C_SCHEME_FALSE;
12570
12571  x1 = C_unfix(n1);
12572  x2 = C_unfix(n2);
12573
12574  if(x2 == 0)
12575    barf(C_DIVISION_BY_ZERO_ERROR, "fx/?");
12576
12577#ifdef C_SIXTY_FOUR
12578  if(x1 == 0x8000000000000000L && x2 == -1) return C_SCHEME_FALSE;
12579#else
12580  if(x1 == 0x80000000L && x2 == -1) return C_SCHEME_FALSE;
12581#endif
12582
12583  x1 = x1 / x2;
12584
12585  if(C_fitsinfixnump(x1)) return C_fix(x1);
12586  else return C_SCHEME_FALSE;
12587}
12588
12589
12590C_regparm C_word C_i_o_fixnum_and(C_word n1, C_word n2)
12591{
12592  C_uword x1, x2, r;
12593
12594  if((n1 & C_FIXNUM_BIT) == 0 || (n2 & C_FIXNUM_BIT) == 0) return C_SCHEME_FALSE;
12595
12596  x1 = C_unfix(n1);
12597  x2 = C_unfix(n2);
12598  r = x1 & x2;
12599
12600  if(((r & C_INT_SIGN_BIT) >> 1) != (r & C_INT_TOP_BIT)) return C_SCHEME_FALSE;
12601  else return C_fix(r);
12602}
12603
12604
12605C_regparm C_word C_i_o_fixnum_ior(C_word n1, C_word n2)
12606{
12607  C_uword x1, x2, r;
12608
12609  if((n1 & C_FIXNUM_BIT) == 0 || (n2 & C_FIXNUM_BIT) == 0) return C_SCHEME_FALSE;
12610
12611  x1 = C_unfix(n1);
12612  x2 = C_unfix(n2);
12613  r = x1 | x2;
12614
12615  if(((r & C_INT_SIGN_BIT) >> 1) != (r & C_INT_TOP_BIT)) return C_SCHEME_FALSE;
12616  else return C_fix(r);
12617}
12618
12619
12620C_regparm C_word C_i_o_fixnum_xor(C_word n1, C_word n2)
12621{
12622  C_uword x1, x2, r;
12623
12624  if((n1 & C_FIXNUM_BIT) == 0 || (n2 & C_FIXNUM_BIT) == 0) return C_SCHEME_FALSE;
12625
12626  x1 = C_unfix(n1);
12627  x2 = C_unfix(n2);
12628  r = x1 ^ x2;
12629
12630  if(((r & C_INT_SIGN_BIT) >> 1) != (r & C_INT_TOP_BIT)) return C_SCHEME_FALSE;
12631  else return C_fix(r);
12632}
12633
12634
12635/* decoding of literals in compressed format */
12636
12637static C_regparm C_uword decode_size(C_char **str)
12638{
12639  C_uchar **ustr = (C_uchar **)str;
12640  C_uword size = (*((*ustr)++) & 0xff) << 16; /* always big endian */
12641
12642  size |= (*((*ustr)++) & 0xff) << 8;
12643  size |= (*((*ustr)++) & 0xff);
12644  return size;
12645}
12646
12647
12648static C_regparm C_word decode_literal2(C_word **ptr, C_char **str,
12649						C_word *dest)
12650{
12651  C_ulong bits = *((*str)++) & 0xff;
12652  C_word *data, *dptr, val;
12653  C_uword size;
12654
12655  /* vvv this can be taken out at a later stage (once it works reliably) vvv */
12656  if(bits != 0xfe)
12657    panic(C_text("invalid encoded literal format"));
12658
12659  bits = *((*str)++) & 0xff;
12660  /* ^^^ */
12661
12662#ifdef C_SIXTY_FOUR
12663  bits <<= 24 + 32;
12664#else
12665  bits <<= 24;
12666#endif
12667
12668  if(bits == C_HEADER_BITS_MASK) {		/* special/immediate */
12669    switch(0xff & *((*str)++)) {
12670    case C_BOOLEAN_BITS:
12671      return C_mk_bool(*((*str)++));
12672
12673    case C_CHARACTER_BITS:
12674      return C_make_character(decode_size(str));
12675
12676    case C_SCHEME_END_OF_LIST:
12677    case C_SCHEME_UNDEFINED:
12678    case C_SCHEME_END_OF_FILE:
12679    case C_SCHEME_BROKEN_WEAK_PTR:
12680      return (C_word)(*(*str - 1));
12681
12682    case C_FIXNUM_BIT:
12683      val = (C_uword)(signed char)*((*str)++) << 24; /* always big endian */
12684      val |= ((C_uword)*((*str)++) & 0xff) << 16;
12685      val |= ((C_uword)*((*str)++) & 0xff) << 8;
12686      val |= ((C_uword)*((*str)++) & 0xff);
12687      return C_fix(val);
12688
12689/* XXX Handle legacy bignum encoding */
12690#ifdef C_SIXTY_FOUR
12691    case ((C_STRING_TYPE | C_GC_FORWARDING_BIT) >> (24 + 32)) & 0xff:
12692#else
12693    case ((C_STRING_TYPE | C_GC_FORWARDING_BIT) >> 24) & 0xff:
12694#endif
12695      bits = (C_STRING_TYPE | C_GC_FORWARDING_BIT);
12696      break;
12697/* XXX */
12698
12699#ifdef C_SIXTY_FOUR
12700    case ((C_BYTEVECTOR_TYPE | C_GC_FORWARDING_BIT) >> (24 + 32)) & 0xff:
12701#else
12702    case ((C_BYTEVECTOR_TYPE | C_GC_FORWARDING_BIT) >> 24) & 0xff:
12703#endif
12704      bits = (C_BYTEVECTOR_TYPE | C_GC_FORWARDING_BIT);
12705      break;
12706
12707    default:
12708      panic(C_text("invalid encoded special literal"));
12709    }
12710  }
12711
12712#ifndef C_SIXTY_FOUR
12713  if((bits & C_8ALIGN_BIT) != 0) {
12714    /* Align _data_ on 8-byte boundary: */
12715    if(C_aligned8(*ptr)) ++(*ptr);
12716  }
12717#endif
12718
12719  val = (C_word)(*ptr);
12720
12721  if((bits & C_SPECIALBLOCK_BIT) != 0)
12722    panic(C_text("literals with special bit cannot be decoded"));
12723
12724  if(bits == C_FLONUM_TYPE) {
12725    val = C_flonum(ptr, decode_flonum_literal(*str));
12726    while(*((*str)++) != '\0');      /* skip terminating '\0' */
12727    return val;
12728  }
12729
12730  size = decode_size(str);
12731
12732  switch(bits) {
12733  /* This cannot be encoded as a bytevector due to endianness differences */
12734
12735  /* XXX legacy bignum encoding: */
12736  case (C_STRING_TYPE | C_BYTEBLOCK_BIT | C_GC_FORWARDING_BIT): /* This represents "exact int" */
12737  /* XXX */
12738  case (C_BYTEVECTOR_TYPE | C_GC_FORWARDING_BIT): /* This represents "exact int" */
12739    /* bignums are also allocated statically */
12740    val = C_static_bignum(ptr, size, *str);
12741    *str += size;
12742    break;
12743
12744  /* XXX legacy encoding: */
12745  case (C_STRING_TYPE | C_BYTEBLOCK_BIT):
12746    /* strings are always allocated statically */
12747    val = C_static_string(ptr, size, *str);
12748    *str += size;
12749    break;
12750  /* XXX */
12751
12752  case C_STRING_TYPE:
12753    /* strings are always allocated statically */
12754    val = C_static_string(ptr, size - 1, *str);
12755    *str += size;
12756    break;
12757
12758  case C_BYTEVECTOR_TYPE:
12759    /* ... as are bytevectors */
12760    val = C_static_bytevector(ptr, size, *str);
12761    *str += size;
12762    break;
12763
12764  case C_SYMBOL_TYPE:
12765    if(dest == NULL)
12766      panic(C_text("invalid literal symbol destination"));
12767
12768    if (**str == '\1') {
12769      val = C_h_intern(dest, size, ++*str);
12770    } else if (**str == '\2') {
12771      val = C_h_intern_kw(dest, size, ++*str);
12772    } else {
12773      C_snprintf(buffer, sizeof(buffer), C_text("Unknown symbol subtype: %d"), (int)**str);
12774      panic(buffer);
12775    }
12776    *str += size;
12777    break;
12778
12779  case C_LAMBDA_INFO_TYPE:
12780    /* lambda infos are always allocated statically */
12781    val = C_static_lambda_info(ptr, size, *str);
12782    *str += size;
12783    break;
12784
12785  default:
12786    *((*ptr)++) = C_make_header(bits, size);
12787    data = *ptr;
12788
12789    if((bits & C_BYTEBLOCK_BIT) != 0) {
12790      C_memcpy(data, *str, size);
12791      size = C_align(size);
12792      *str += size;
12793      *ptr = (C_word *)C_align((C_word)(*ptr) + size);
12794    }
12795    else {
12796      C_word *dptr = *ptr;
12797      *ptr += size;
12798
12799      while(size--) {
12800	*dptr = decode_literal2(ptr, str, dptr);
12801	++dptr;
12802      }
12803    }
12804  }
12805
12806  return val;
12807}
12808
12809
12810C_regparm C_word
12811C_decode_literal(C_word **ptr, C_char *str)
12812{
12813  return decode_literal2(ptr, &str, NULL);
12814}
12815
12816
12817void
12818C_use_private_repository(C_char *path)
12819{
12820  private_repository = path;
12821}
12822
12823
12824C_char *
12825C_private_repository_path()
12826{
12827  return private_repository;
12828}
12829
12830C_char *
12831C_executable_pathname() {
12832#ifdef SEARCH_EXE_PATH
12833  return C_main_exe == NULL ? NULL : C_strdup(C_main_exe);
12834#else
12835  return C_resolve_executable_pathname(NULL);
12836#endif
12837}
12838
12839C_char *
12840C_executable_dirname() {
12841  int len;
12842  C_char *path;
12843
12844  if((path = C_executable_pathname()) == NULL)
12845    return NULL;
12846
12847#if defined(_WIN32) && !defined(__CYGWIN__)
12848  for(len = C_strlen(path); len >= 0 && path[len] != '\\'; len--);
12849#else
12850  for(len = C_strlen(path); len >= 0 && path[len] != '/'; len--);
12851#endif
12852
12853  path[len] = '\0';
12854  return path;
12855}
12856
12857C_char *
12858C_resolve_executable_pathname(C_char *fname)
12859{
12860  int n;
12861  C_WCHAR *buffer = (C_WCHAR *) C_malloc(C_MAX_PATH);
12862
12863  if(buffer == NULL) return NULL;
12864
12865#if defined(__linux__) || defined(__sun)
12866  C_char linkname[64]; /* /proc/<pid>/exe */
12867  pid_t pid = C_getpid();
12868
12869# ifdef __linux__
12870  C_snprintf(linkname, sizeof(linkname), "/proc/%i/exe", pid);
12871# else
12872  C_snprintf(linkname, sizeof(linkname), "/proc/%i/path/a.out", pid); /* SunOS / Solaris */
12873# endif
12874
12875  n = C_readlink(linkname, buffer, C_MAX_PATH);
12876  if(n < 0 || n >= C_MAX_PATH)
12877    goto error;
12878
12879  buffer[n] = '\0';
12880  return buffer;
12881#elif defined(_WIN32) && !defined(__CYGWIN__)
12882  n = GetModuleFileNameW(NULL, buffer, C_MAX_PATH);
12883  if(n == 0 || n >= C_MAX_PATH)
12884    goto error;
12885
12886  C_char *buf2 = C_strdup(C_utf8(buffer));
12887  C_free(buffer);
12888  return buf2;
12889#elif defined(C_MACOSX)
12890  C_char buf[C_MAX_PATH];
12891  C_u32 size = C_MAX_PATH;
12892
12893  if(_NSGetExecutablePath(buf, &size) != 0)
12894    goto error;
12895
12896  if(C_realpath(buf, buffer) == NULL)
12897    goto error;
12898
12899  return buffer;
12900#elif defined(__HAIKU__)
12901{
12902  image_info info;
12903  int32 cookie = 0;
12904
12905  while (get_next_image_info(0, &cookie, &info) == B_OK) {
12906    if (info.type == B_APP_IMAGE) {
12907      C_strlcpy(buffer, info.name, C_MAX_PATH);
12908      return buffer;
12909    }
12910  }
12911}
12912#elif defined(SEARCH_EXE_PATH)
12913  int len;
12914  C_char *path, buf[C_MAX_PATH];
12915
12916  /* no name given (execve) */
12917  if(fname == NULL)
12918    goto error;
12919
12920  /* absolute pathname */
12921  if(fname[0] == '/') {
12922    if(C_realpath(fname, buffer) == NULL)
12923      goto error;
12924    else
12925      return buffer;
12926  }
12927
12928  /* current directory */
12929  if(C_strchr(fname, '/') != NULL) {
12930    if(C_getcwd(buffer, C_MAX_PATH) == NULL)
12931      goto error;
12932
12933    n = C_snprintf(buf, C_MAX_PATH, "%s/%s", buffer, fname);
12934    if(n < 0 || n >= C_MAX_PATH)
12935      goto error;
12936
12937    if(C_access(buf, X_OK) == 0) {
12938      if(C_realpath(buf, buffer) == NULL)
12939        goto error;
12940      else
12941        return buffer;
12942    }
12943  }
12944
12945  /* walk PATH */
12946  if((path = getenv("PATH")) == NULL)
12947    goto error;
12948
12949  do {
12950    /* check PATH entry length */
12951    len = C_strcspn(path, ":");
12952    if(len == 0 || len >= C_MAX_PATH)
12953      continue;
12954
12955    /* "<path>/<fname>" to buf */
12956    C_strncpy(buf, path, len);
12957    n = C_snprintf(buf + len, C_MAX_PATH - len, "/%s", fname);
12958    if(n < 0 || n + len >= C_MAX_PATH)
12959      continue;
12960
12961    if(C_access(buf, X_OK) != 0)
12962      continue;
12963
12964    /* fname found, resolve links */
12965    if(C_realpath(buf, buffer) != NULL)
12966      return buffer;
12967
12968  /* seek next entry, skip colon */
12969  } while (path += len, *path++);
12970#else
12971# error "Please either define SEARCH_EXE_PATH in Makefile.<platform> or implement C_resolve_executable_pathname for your platform!"
12972#endif
12973
12974error:
12975  C_free(buffer);
12976  return NULL;
12977}
12978
12979C_regparm C_word
12980C_i_getprop(C_word sym, C_word prop, C_word def)
12981{
12982  C_word pl = C_symbol_plist(sym);
12983
12984  while(pl != C_SCHEME_END_OF_LIST) {
12985    if(C_block_item(pl, 0) == prop)
12986      return C_u_i_car(C_u_i_cdr(pl));
12987    else pl = C_u_i_cdr(C_u_i_cdr(pl));
12988  }
12989
12990  return def;
12991}
12992
12993
12994C_regparm C_word
12995C_putprop(C_word **ptr, C_word sym, C_word prop, C_word val)
12996{
12997  C_word pl = C_symbol_plist(sym);
12998
12999  /* Newly added plist?  Ensure the symbol stays! */
13000  if (pl == C_SCHEME_END_OF_LIST) C_i_persist_symbol(sym);
13001
13002  while(pl != C_SCHEME_END_OF_LIST) {
13003    if(C_block_item(pl, 0) == prop) {
13004      C_mutate(&C_u_i_car(C_u_i_cdr(pl)), val);
13005      return val;
13006    }
13007    else pl = C_u_i_cdr(C_u_i_cdr(pl));
13008  }
13009
13010  pl = C_a_pair(ptr, val, C_symbol_plist(sym));
13011  pl = C_a_pair(ptr, prop, pl);
13012  C_mutate_slot(&C_symbol_plist(sym), pl);
13013  return val;
13014}
13015
13016
13017C_regparm C_word
13018C_i_get_keyword(C_word kw, C_word args, C_word def)
13019{
13020  while(!C_immediatep(args)) {
13021    if(C_header_type(args) == C_PAIR_TYPE) {
13022      if(kw == C_u_i_car(args)) {
13023	args = C_u_i_cdr(args);
13024
13025	if(C_immediatep(args) || C_header_type(args) != C_PAIR_TYPE)
13026	  return def;
13027	else return C_u_i_car(args);
13028      }
13029      else {
13030	args = C_u_i_cdr(args);
13031
13032	if(C_immediatep(args) || C_header_type(args) != C_PAIR_TYPE)
13033	  return def;
13034	else args = C_u_i_cdr(args);
13035      }
13036    }
13037  }
13038
13039  return def;
13040}
13041
13042C_word C_i_dump_statistical_profile()
13043{
13044  PROFILE_BUCKET *b, *b2, **bp;
13045  FILE *fp;
13046  C_char *k1, *k2 = NULL;
13047  int n;
13048  double ms;
13049
13050  assert(profiling);
13051  assert(profile_table != NULL);
13052
13053  set_profile_timer(0);
13054
13055  profiling = 0; /* In case a SIGPROF is delivered late */
13056  bp = profile_table;
13057
13058  C_snprintf(buffer, STRING_BUFFER_SIZE, C_text("PROFILE.%d"), C_getpid());
13059
13060  if(debug_mode)
13061    C_dbg(C_text("debug"), C_text("dumping statistical profile to `%s'...\n"), buffer);
13062  fp = fopen(buffer, "w");
13063  if (fp == NULL)
13064    panic(C_text("could not write profile!"));
13065
13066  C_fputs(C_text("statistical\n"), fp);
13067  for(n = 0; n < PROFILE_TABLE_SIZE; ++n) {
13068    for(b = bp[ n ]; b != NULL; b = b2) {
13069      b2 = b->next;
13070
13071      k1 = b->key;
13072      C_fputs(C_text("(|"), fp);
13073      /* Dump raw C string as if it were a symbol */
13074      while((k2 = C_strpbrk(k1, C_text("\\|"))) != NULL) {
13075        C_fwrite(k1, 1, k2-k1, fp);
13076        C_fputc('\\', fp);
13077        C_fputc(*k2, fp);
13078        k1 = k2+1;
13079      }
13080      C_fputs(k1, fp);
13081      ms = (double)b->sample_count * (double)profile_frequency / 1000.0;
13082      C_fprintf(fp, C_text("| " UWORD_COUNT_FORMAT_STRING " %lf)\n"),
13083                b->call_count, ms);
13084      C_free(b);
13085    }
13086  }
13087
13088  C_fclose(fp);
13089  C_free(profile_table);
13090  profile_table = NULL;
13091
13092  return C_SCHEME_UNDEFINED;
13093}
13094
13095void C_ccall C_dump_heap_state(C_word c, C_word *av)
13096{
13097  C_word
13098    /* closure = av[ 0 ] */
13099    k = av[ 1 ];
13100
13101  /* make sure heap is compacted */
13102  C_save(k);
13103  C_fromspace_top = C_fromspace_limit; /* force major GC */
13104  C_reclaim((void *)dump_heap_state_2, 1);
13105}
13106
13107
13108static C_ulong
13109hdump_hash(C_word key)
13110{
13111  return (C_ulong)key % HDUMP_TABLE_SIZE;
13112}
13113
13114
13115static void
13116hdump_count(C_word key, int n, int t)
13117{
13118  HDUMP_BUCKET **bp = hdump_table + hdump_hash(key);
13119  HDUMP_BUCKET *b = *bp;
13120
13121  while(b != NULL) {
13122    if(b->key == key) {
13123      b->count += n;
13124      b->total += t;
13125      return;
13126    }
13127    else b = b->next;
13128  }
13129
13130  b = (HDUMP_BUCKET *)C_malloc(sizeof(HDUMP_BUCKET));
13131
13132  if(b == 0)
13133    panic(C_text("out of memory - can not allocate heap-dump table-bucket"));
13134
13135  b->next = *bp;
13136  b->key = key;
13137  *bp = b;
13138  b->count = n;
13139  b->total = t;
13140}
13141
13142
13143static void C_ccall dump_heap_state_2(C_word c, C_word *av)
13144{
13145  C_word k = av[ 0 ];
13146  HDUMP_BUCKET *b, *b2, **bp;
13147  int n, bytes;
13148  C_byte *scan;
13149  C_SCHEME_BLOCK *sbp;
13150  C_header h;
13151  C_word x, key, *p;
13152  int imm = 0, blk = 0;
13153
13154  hdump_table = (HDUMP_BUCKET **)C_malloc(HDUMP_TABLE_SIZE * sizeof(HDUMP_BUCKET *));
13155
13156  if(hdump_table == NULL)
13157    panic(C_text("out of memory - can not allocate heap-dump table"));
13158
13159  C_memset(hdump_table, 0, sizeof(HDUMP_BUCKET *) * HDUMP_TABLE_SIZE);
13160
13161  scan = fromspace_start;
13162
13163  while(scan < C_fromspace_top) {
13164    ++blk;
13165    sbp = (C_SCHEME_BLOCK *)scan;
13166
13167    if(*((C_word *)sbp) == ALIGNMENT_HOLE_MARKER)
13168      sbp = (C_SCHEME_BLOCK *)((C_word *)sbp + 1);
13169
13170    n = C_header_size(sbp);
13171    h = sbp->header;
13172    bytes = (h & C_BYTEBLOCK_BIT) ? n : n * sizeof(C_word);
13173    key = (C_word)(h & C_HEADER_BITS_MASK);
13174    p = sbp->data;
13175
13176    if(key == C_STRUCTURE_TYPE) key = *p;
13177
13178    hdump_count(key, 1, bytes);
13179
13180    if(n > 0 && (h & C_BYTEBLOCK_BIT) == 0) {
13181      if((h & C_SPECIALBLOCK_BIT) != 0) {
13182	--n;
13183	++p;
13184      }
13185
13186      while(n--) {
13187	x = *(p++);
13188
13189	if(C_immediatep(x)) {
13190	  ++imm;
13191
13192	  if((x & C_FIXNUM_BIT) != 0) key = C_fix(1);
13193	  else {
13194	    switch(x & C_IMMEDIATE_TYPE_BITS) {
13195	    case C_BOOLEAN_BITS: key = C_SCHEME_TRUE; break;
13196	    case C_CHARACTER_BITS: key = C_make_character('A'); break;
13197	    default: key = x;
13198	    }
13199	  }
13200
13201	  hdump_count(key, 1, 0);
13202	}
13203      }
13204    }
13205
13206    scan = (C_byte *)sbp + C_align(bytes) + sizeof(C_word);
13207  }
13208
13209  bp = hdump_table;
13210  /* HACK */
13211#define C_WEAK_PAIR_TYPE (C_PAIR_TYPE | C_SPECIALBLOCK_BIT)
13212
13213  for(n = 0; n < HDUMP_TABLE_SIZE; ++n) {
13214    for(b = bp[ n ]; b != NULL; b = b2) {
13215      b2 = b->next;
13216
13217      switch(b->key) {
13218      case C_fix(1): C_fprintf(C_stderr,                 C_text("fixnum         ")); break;
13219      case C_SCHEME_TRUE: C_fprintf(C_stderr,            C_text("boolean        ")); break;
13220      case C_SCHEME_END_OF_LIST: C_fprintf(C_stderr,     C_text("null           ")); break;
13221      case C_SCHEME_UNDEFINED  : C_fprintf(C_stderr,     C_text("void           ")); break;
13222      case C_SCHEME_BROKEN_WEAK_PTR: C_fprintf(C_stderr, C_text("broken weak ptr")); break;
13223      case C_make_character('A'): C_fprintf(C_stderr,    C_text("character      ")); break;
13224      case C_SCHEME_END_OF_FILE: C_fprintf(C_stderr,     C_text("eof            ")); break;
13225      case C_SCHEME_UNBOUND: C_fprintf(C_stderr,         C_text("unbound        ")); break;
13226      case C_SYMBOL_TYPE: C_fprintf(C_stderr,            C_text("symbol         ")); break;
13227      case C_STRING_TYPE: C_fprintf(C_stderr,            C_text("string         ")); break;
13228      case C_PAIR_TYPE: C_fprintf(C_stderr,              C_text("pair           ")); break;
13229      case C_CLOSURE_TYPE: C_fprintf(C_stderr,           C_text("closure        ")); break;
13230      case C_FLONUM_TYPE: C_fprintf(C_stderr,            C_text("flonum         ")); break;
13231      case C_PORT_TYPE: C_fprintf(C_stderr,              C_text("port           ")); break;
13232      case C_POINTER_TYPE: C_fprintf(C_stderr,           C_text("pointer        ")); break;
13233      case C_LOCATIVE_TYPE: C_fprintf(C_stderr,          C_text("locative       ")); break;
13234      case C_TAGGED_POINTER_TYPE: C_fprintf(C_stderr,    C_text("tagged pointer ")); break;
13235      case C_LAMBDA_INFO_TYPE: C_fprintf(C_stderr,       C_text("lambda info    ")); break;
13236      case C_WEAK_PAIR_TYPE: C_fprintf(C_stderr,         C_text("weak pair      ")); break;
13237      case C_VECTOR_TYPE: C_fprintf(C_stderr,            C_text("vector         ")); break;
13238      case C_BYTEVECTOR_TYPE: C_fprintf(C_stderr,        C_text("bytevector     ")); break;
13239      case C_BIGNUM_TYPE: C_fprintf(C_stderr,            C_text("bignum         ")); break;
13240      case C_CPLXNUM_TYPE: C_fprintf(C_stderr,           C_text("cplxnum        ")); break;
13241      case C_RATNUM_TYPE: C_fprintf(C_stderr,            C_text("ratnum         ")); break;
13242	/* XXX this is sort of funny: */
13243      case C_BYTEBLOCK_BIT: C_fprintf(C_stderr,        C_text("bytevector           ")); break;
13244      default:
13245	x = b->key;
13246
13247	if(!C_immediatep(x) && C_header_bits(x) == C_SYMBOL_TYPE) {
13248	  x = C_block_item(x, 1);
13249	  C_fprintf(C_stderr, C_text("`%.*s'"), (int)C_header_size(x), C_c_string(x));
13250	}
13251	else C_fprintf(C_stderr, C_text("unknown key " UWORD_FORMAT_STRING), (C_uword)b->key);
13252      }
13253
13254      C_fprintf(C_stderr, C_text("\t%d"), b->count);
13255
13256      if(b->total > 0)
13257	C_fprintf(C_stderr, C_text("\t%d bytes"), b->total);
13258
13259      C_fputc('\n', C_stderr);
13260      C_free(b);
13261    }
13262  }
13263
13264  C_fprintf(C_stderr, C_text("\ntotal number of blocks: %d, immediates: %d\n"),
13265	    blk, imm);
13266  C_free(hdump_table);
13267  C_kontinue(k, C_SCHEME_UNDEFINED);
13268}
13269
13270
13271static void C_ccall filter_heap_objects_2(C_word c, C_word *av)
13272{
13273  void *func = C_pointer_address(av[ 0 ]);
13274  C_word
13275    userarg = av[ 1 ],
13276    vector = av[ 2 ],
13277    k = av[ 3 ];
13278  int n, bytes;
13279  C_byte *scan;
13280  C_SCHEME_BLOCK *sbp;
13281  C_header h;
13282  C_word *p;
13283  int vecsize = C_header_size(vector);
13284  typedef int (*filterfunc)(C_word x, C_word userarg);
13285  filterfunc ff = (filterfunc)func;
13286  int vcount = 0;
13287
13288  scan = fromspace_start;
13289
13290  while(scan < C_fromspace_top) {
13291    sbp = (C_SCHEME_BLOCK *)scan;
13292
13293    if(*((C_word *)sbp) == ALIGNMENT_HOLE_MARKER)
13294      sbp = (C_SCHEME_BLOCK *)((C_word *)sbp + 1);
13295
13296    n = C_header_size(sbp);
13297    h = sbp->header;
13298    bytes = (h & C_BYTEBLOCK_BIT) ? n : n * sizeof(C_word);
13299    p = sbp->data;
13300
13301    if(ff((C_word)sbp, userarg)) {
13302      if(vcount < vecsize) {
13303	C_set_block_item(vector, vcount, (C_word)sbp);
13304	++vcount;
13305      }
13306      else {
13307	C_kontinue(k, C_fix(-1));
13308      }
13309    }
13310
13311    scan = (C_byte *)sbp + C_align(bytes) + sizeof(C_word);
13312  }
13313
13314  C_kontinue(k, C_fix(vcount));
13315}
13316
13317
13318void C_ccall C_filter_heap_objects(C_word c, C_word *av)
13319{
13320  C_word
13321    /* closure = av[ 0 ] */
13322    k = av[ 1 ],
13323    func = av[ 2 ],
13324    vector = av[ 3 ],
13325    userarg = av[ 4 ];
13326
13327  /* make sure heap is compacted */
13328  C_save(k);
13329  C_save(vector);
13330  C_save(userarg);
13331  C_save(func);
13332  C_fromspace_top = C_fromspace_limit; /* force major GC */
13333  C_reclaim((void *)filter_heap_objects_2, 4);
13334}
13335
13336C_regparm C_word C_i_process_sleep(C_word n)
13337{
13338#if defined(_WIN32) && !defined(__CYGWIN__)
13339  Sleep(C_unfix(n) * 1000);
13340  return C_fix(0);
13341#else
13342  return C_fix(sleep(C_unfix(n)));
13343#endif
13344}
13345
13346C_regparm C_word
13347C_i_file_exists_p(C_word name, C_word file, C_word dir)
13348{
13349#if defined(_WIN32) && !defined(__CYGWIN__)
13350  struct _stat64i32 buf;
13351#else
13352  struct stat buf;
13353#endif
13354  int res;
13355
13356  res = C_stat(C_OS_FILENAME(name, 0), &buf);
13357
13358  if(res != 0) {
13359    switch(errno) {
13360    case ENOENT: return C_SCHEME_FALSE;
13361    case EOVERFLOW: return C_truep(dir) ? C_SCHEME_FALSE : C_SCHEME_TRUE;
13362    case ENOTDIR: return C_SCHEME_FALSE;
13363    default: return C_fix(res);
13364    }
13365  }
13366
13367  switch(buf.st_mode & S_IFMT) {
13368  case S_IFDIR: return C_truep(file) ? C_SCHEME_FALSE : C_SCHEME_TRUE;
13369  default: return C_truep(dir) ? C_SCHEME_FALSE : C_SCHEME_TRUE;
13370  }
13371}
13372
13373
13374C_regparm C_word
13375C_i_pending_interrupt(C_word dummy)
13376{
13377  if(pending_interrupts_count > 0) {
13378    handling_interrupts = 1; /* Lock out further forced GCs until we're done */
13379    return C_fix(pending_interrupts[ --pending_interrupts_count ]);
13380  } else {
13381    handling_interrupts = 0; /* OK, can go on */
13382    return C_SCHEME_FALSE;
13383  }
13384}
13385
13386
13387/* random numbers, mostly lifted from
13388  https://github.com/jedisct1/libsodium/blob/master/src/libsodium/randombytes/sysrandom/randombytes_sysrandom.c
13389*/
13390
13391#ifdef __linux__
13392# include <sys/syscall.h>
13393#endif
13394
13395
13396#if !defined(_WIN32)
13397static C_word random_urandom(C_word buf, int count)
13398{
13399  static int fd = -1;
13400  int off = 0, r;
13401
13402  if(fd == -1) {
13403    fd = open("/dev/urandom", O_RDONLY);
13404
13405    if(fd == -1) return C_SCHEME_FALSE;
13406  }
13407
13408  while(count > 0) {
13409    r = read(fd, C_data_pointer(buf) + off, count);
13410
13411    if(r == -1) {
13412      if(errno != EINTR && errno != EAGAIN) return C_SCHEME_FALSE;
13413      else r = 0;
13414    }
13415
13416    count -= r;
13417    off += r;
13418   }
13419
13420  return C_SCHEME_TRUE;
13421}
13422#endif
13423
13424
13425C_word C_random_bytes(C_word buf, C_word size)
13426{
13427  int count = C_unfix(size);
13428  int r = 0;
13429  int off = 0;
13430
13431#if defined(__OpenBSD__) || defined(__FreeBSD__)
13432  arc4random_buf(C_data_pointer(buf), count);
13433#elif defined(SYS_getrandom) && defined(__NR_getrandom)
13434  static int use_urandom = 0;
13435
13436  if(use_urandom) return random_urandom(buf, count);
13437
13438  while(count > 0) {
13439    /* GRND_NONBLOCK = 0x0001 */
13440    r = syscall(SYS_getrandom, C_data_pointer(buf) + off, count, 1);
13441
13442    if(r == -1) {
13443      if(errno == ENOSYS) {
13444        use_urandom = 1;
13445        return random_urandom(buf, count);
13446      }
13447      else if(errno != EINTR) return C_SCHEME_FALSE;
13448      else r = 0;
13449    }
13450
13451    count -= r;
13452    off += r;
13453  }
13454#elif defined(_WIN32) && !defined(__CYGWIN__)
13455  typedef BOOLEAN (*func)(PVOID, ULONG);
13456  static func RtlGenRandom = NULL;
13457
13458  if(RtlGenRandom == NULL) {
13459     HMODULE mod = LoadLibrary("advapi32.dll");
13460
13461     if(mod == NULL) return C_SCHEME_FALSE;
13462
13463     if((RtlGenRandom = (func)GetProcAddress(mod, "SystemFunction036")) == NULL)
13464       return C_SCHEME_FALSE;
13465  }
13466
13467  if(!RtlGenRandom((PVOID)C_data_pointer(buf), (LONG)count))
13468    return C_SCHEME_FALSE;
13469#else
13470  return random_urandom(buf, count);
13471#endif
13472
13473  return C_SCHEME_TRUE;
13474}
13475
13476
13477/* WELL512 pseudo random number generator, see also:
13478   https://en.wikipedia.org/wiki/Well_equidistributed_long-period_linear
13479   http://lomont.org/Math/Papers/2008/Lomont_PRNG_2008.pdf
13480*/
13481
13482static C_uword random_word(void)
13483{
13484  C_uword a, b, c, d, r;
13485  a  = random_state[random_state_index];
13486  c  = random_state[(random_state_index+13)&15];
13487  b  = a^c^(a<<16)^(c<<15);
13488  c  = random_state[(random_state_index+9)&15];
13489  c ^= (c>>11);
13490  a  = random_state[random_state_index] = b^c;
13491  d  = a^((a<<5)&0xDA442D24UL);
13492  random_state_index = (random_state_index + 15)&15;
13493  a  = random_state[random_state_index];
13494  random_state[random_state_index] = a^b^d^(a<<2)^(b<<18)^(c<<28);
13495  r = random_state[random_state_index];
13496  return r;
13497}
13498
13499
13500static C_uword random_uniform(C_uword bound)
13501{
13502  C_uword r, min;
13503
13504  if (bound < 2) return 0;
13505
13506  min = (1U + ~bound) % bound; /* = 2**<wordsize> mod bound */
13507
13508  do r = random_word(); while (r < min);
13509
13510  /* r is now clamped to a set whose size mod upper_bound == 0
13511   * the worst case (2**<wordsize-1>+1) requires ~ 2 attempts */
13512
13513  return r % bound;
13514}
13515
13516
13517C_regparm C_word C_random_fixnum(C_word n)
13518{
13519  C_word nf;
13520
13521  if (!(n & C_FIXNUM_BIT))
13522    barf(C_BAD_ARGUMENT_TYPE_NO_FIXNUM_ERROR, "pseudo-random-integer", n);
13523
13524  nf = C_unfix(n);
13525
13526  if(nf < 0)
13527    barf(C_OUT_OF_BOUNDS_ERROR, "pseudo-random-integer", n, C_fix(0));
13528
13529  return C_fix(random_uniform(nf));
13530}
13531
13532
13533C_regparm C_word
13534C_s_a_u_i_random_int(C_word **ptr, C_word n, C_word rn)
13535{
13536  C_uword *start, *end;
13537
13538  if(C_bignum_negativep(rn))
13539    barf(C_OUT_OF_BOUNDS_ERROR, "pseudo-random-integer", rn, C_fix(0));
13540
13541  int len = integer_length_abs(rn);
13542  C_word size = C_fix(C_BIGNUM_BITS_TO_DIGITS(len));
13543  C_word result = C_allocate_scratch_bignum(ptr, size, C_SCHEME_FALSE, C_SCHEME_FALSE);
13544  C_uword *p;
13545  C_uword highest_word = C_bignum_digits(rn)[C_bignum_size(rn)-1];
13546  start = C_bignum_digits(result);
13547  end = start + C_bignum_size(result);
13548
13549  for(p = start; p < (end - 1); ++p) {
13550    *p = random_word();
13551    len -= sizeof(C_uword);
13552  }
13553
13554  *p = random_uniform(highest_word);
13555  return C_bignum_simplify(result);
13556}
13557
13558/*
13559 * C_a_i_random_real: Generate a stream of bits uniformly at random and
13560 * interpret it as the fractional part of the binary expansion of a
13561 * number in [0, 1], 0.00001010011111010100...; then round it.
13562 * More information on https://mumble.net/~campbell/2014/04/28/uniform-random-float
13563 */
13564
13565static inline C_u64 random64() {
13566#ifdef C_SIXTY_FOUR
13567    return random_word();
13568#else
13569    C_u64 v = 0;
13570    v |= ((C_u64) random_word()) << 32;
13571    v |= (C_u64) random_word();
13572    return v;
13573#endif
13574}
13575
13576#if defined(__GNUC__) && !defined(__TINYC__)
13577# define	clz64	__builtin_clzll
13578#else
13579/* https://en.wikipedia.org/wiki/Find_first_set#CLZ */
13580static const C_uchar clz_table_4bit[16] = { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
13581
13582int clz32(C_u32 x)
13583{
13584  int n;
13585  if ((x & 0xFFFF0000) == 0) {n  = 16; x <<= 16;} else {n = 0;}
13586  if ((x & 0xFF000000) == 0) {n +=  8; x <<=  8;}
13587  if ((x & 0xF0000000) == 0) {n +=  4; x <<=  4;}
13588  n += (int)clz_table_4bit[x >> (32-4)];
13589  return n;
13590}
13591
13592int clz64(C_u64 x)
13593{
13594    int y = clz32(x >> 32);
13595
13596    if(y == 32) return y + clz32(x);
13597
13598    return y;
13599}
13600#endif
13601
13602C_regparm C_word
13603C_a_i_random_real(C_word **ptr, C_word n) {
13604  int exponent = -64;
13605  uint64_t significand;
13606  unsigned shift;
13607
13608  while (C_unlikely((significand = random64()) == 0)) {
13609    exponent -= 64;
13610    if (C_unlikely(exponent < -1074))
13611      return 0;
13612  }
13613
13614  shift = clz64(significand);
13615  if (shift != 0) {
13616    exponent -= shift;
13617    significand <<= shift;
13618    significand |= (random64() >> (64 - shift));
13619  }
13620
13621  significand |= 1;
13622  return C_flonum(ptr, ldexp((double)significand, exponent));
13623}
13624
13625C_word C_set_random_seed(C_word buf, C_word n)
13626{
13627  int i, nsu = C_unfix(n) / sizeof(C_uword);
13628  int off = 0;
13629
13630  for(i = 0; i < (C_RANDOM_STATE_SIZE / sizeof(C_uword)); ++i) {
13631    if(off >= nsu) off = 0;
13632
13633    random_state[ i ] = *((C_uword *)C_data_pointer(buf) + off);
13634    ++off;
13635  }
13636
13637  random_state_index = 0;
13638  return C_SCHEME_FALSE;
13639}
13640
13641C_word C_a_extract_struct_2(C_word **ptr, size_t sz, void *sp)
13642{
13643    C_word bv = C_scratch_alloc(C_SIZEOF_BYTEVECTOR(sz));
13644    C_word w;
13645    C_block_header_init(bv, C_make_header(C_BYTEVECTOR_TYPE, sz));
13646    C_memcpy(C_data_pointer(bv), sp, sz);
13647    w = C_a_i_record2(ptr, 2, C_SCHEME_FALSE, bv);
13648    return w;
13649}
13650
13651C_regparm C_word C_i_setenv(C_word var, C_word val)
13652{
13653#if defined(_WIN32) && !defined(__CYGWIN__)
13654	C_WCHAR *wvar = C_utf16(var,0);
13655	C_WCHAR *wval = val == C_SCHEME_FALSE ? NULL : C_utf16(val, 1);
13656	SetEnvironmentVariableW(wvar, wval);
13657	return C_fix(0);
13658#elif defined(HAVE_SETENV)
13659	C_char *cvar = C_c_string(var);
13660	if(val == C_SCHEME_FALSE) unsetenv(C_c_string(var));
13661	else setenv(C_c_string(var), C_c_string(val), 1);
13662	return(C_fix(0));
13663#else
13664	char *sx = C_c_string(C_var),
13665	*sy = (val == C_SCHEME_FALSE ? "" : C_c_string(val));
13666	int n1 = C_strlen(sx), n2 = C_strlen(sy);
13667	int buf_len = n1 + n2 + 2;
13668	char *buf = (char *)C_malloc(buf_len);
13669	if(buf == NULL) return(C_fix(0));
13670	else {
13671		C_strlcpy(buf, sx, buf_len);
13672		C_strlcat(buf, "=", buf_len);
13673		C_strlcat(buf, sy, buf_len);
13674		return(C_fix(putenv(buf)));
13675	}
13676#endif
13677}
13678
13679C_char *C_getenv(C_word var)
13680{
13681#if defined(_WIN32) && !defined(__CYGWIN__)
13682	C_WCHAR *wvar = C_utf16(var, 0);
13683	if(GetEnvironmentVariableW(wvar, (C_WCHAR *)buffer, STRING_BUFFER_SIZE) ==
13684		0) return NULL;
13685	return C_utf8((C_WCHAR *)buffer);
13686#else
13687	return getenv(C_c_string(var));
13688#endif
13689}
13690
13691#ifdef HAVE_CRT_EXTERNS_H
13692# include <crt_externs.h>
13693# define environ (*_NSGetEnviron())
13694#elif !defined(_WIN32) || defined(__CYGWIN__)
13695extern char **environ;
13696#endif
13697
13698C_char *C_getenventry(int i)
13699{
13700#if defined(_WIN32) && !defined(__CYGWIN__)
13701	C_WCHAR *env = GetEnvironmentStringsW();
13702	C_WCHAR *p = env;
13703	while(i--) {
13704		while(*p != 0) ++p;
13705		if(*(++p) == 0) return NULL;
13706	}
13707	C_char *s = C_strdup(C_utf8(p));
13708	FreeEnvironmentStringsW(env);
13709	return s;
13710#else
13711	return environ[ i ] == NULL ? NULL : C_strdup(environ[ i ]);
13712#endif
13713}
Trap