~ 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;
  359C_char
  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, char *argv[], void *toplevel)
  608{
  609  C_word h, s, n;
  610
  611#ifdef _WIN32
  612    parse_argv(C_utf8(GetCommandLineW()));
  613    argc = C_main_argc;
  614    argv = C_main_argv;
  615#endif
  616
  617  pass_serious_signals = 0;
  618  CHICKEN_parse_command_line(argc, argv, &h, &s, &n);
  619
  620  if(!CHICKEN_initialize(h, s, n, toplevel))
  621    panic(C_text("cannot initialize - out of memory"));
  622
  623  CHICKEN_run(NULL);
  624  return 0;
  625}
  626
  627
  628/* Custom argv parser for Windowz: */
  629
  630void parse_argv(C_char *cmds)
  631{
  632  C_char *ptr = cmds, *bptr0, *bptr, *aptr;
  633  int n = 0, delim = 0;
  634  C_main_argv = (C_char **)malloc((MAXIMAL_NUMBER_OF_COMMAND_LINE_ARGUMENTS + 1) * sizeof(C_char *));
  635
  636  if(C_main_argv == NULL)
  637    panic(C_text("cannot allocate argument-list buffer"));
  638
  639  C_main_argc = 0;
  640
  641  while(C_main_argc < MAXIMAL_NUMBER_OF_COMMAND_LINE_ARGUMENTS) {
  642    while(C_utf_isspace((int)(*ptr))) ++ptr;
  643
  644    if(*ptr == '\0') break;
  645
  646    bptr0 = bptr = buffer;
  647    n = 0;
  648    if(*ptr == '\"' || *ptr == '\'') delim = *(ptr++);
  649    else delim = 0;
  650
  651    while(*ptr != '\0') {
  652      if(*ptr == delim || (C_utf_isspace((int)(*ptr)) && !delim)) break;
  653      if(delim && *ptr == '\\') ++ptr;
  654      *(bptr++) = *(ptr++);
  655      ++n;
  656    }
  657
  658    if(delim) ++ptr;
  659
  660    *bptr = '\0';
  661    aptr = (C_char*)malloc(n + 1);
  662    if(!aptr) panic(C_text("cannot allocate argument buffer"));
  663
  664    C_strlcpy(aptr, bptr0, n + 1);
  665    C_main_argv[ C_main_argc++ ] = aptr;
  666  }
  667
  668  C_main_argv[ C_main_argc ] = NULL;
  669}
  670
  671/* simple linear congruential PRNG, to avoid OpenBSD warnings.
  672    https://stackoverflow.com/questions/26237419/faster-than-rand
  673*/
  674
  675static int g_seed;
  676
  677void C_fast_srand(int seed) { g_seed = seed; }
  678
  679/* Output value in range [0, 32767] */
  680int C_fast_rand(void)
  681{
  682	g_seed = (214013*g_seed+2531011);
  683	return (g_seed>>16)&0x7FFF;
  684}
  685
  686
  687/* Initialize runtime system: */
  688
  689int CHICKEN_initialize(int heap, int stack, int symbols, void *toplevel)
  690{
  691  C_SCHEME_BLOCK *k0;
  692  int i;
  693#ifdef HAVE_SIGACTION
  694  struct sigaction sa;
  695#endif
  696
  697  /* FIXME Should have C_tzset in chicken.h? */
  698#if defined(__MINGW32__)
  699# if defined(__MINGW64_VERSION_MAJOR)
  700    ULONGLONG tick_count = GetTickCount64();
  701# else
  702    /* mingw doesn't yet have GetTickCount64 support */
  703    ULONGLONG tick_count = GetTickCount();
  704# endif
  705  C_startup_time_sec = tick_count / 1000;
  706  C_startup_time_msec = tick_count % 1000;
  707  /* Make sure _tzname, _timezone, and _daylight are set */
  708  _tzset();
  709#else
  710  struct timeval tv;
  711  C_gettimeofday(&tv, NULL);
  712  C_startup_time_sec = tv.tv_sec;
  713  C_startup_time_msec = tv.tv_usec / 1000;
  714  /* Make sure tzname, timezone, and daylight are set */
  715  tzset();
  716#endif
  717
  718  if(chicken_is_initialized) return 1;
  719  else chicken_is_initialized = 1;
  720
  721#if defined(__ANDROID__) && defined(DEBUGBUILD)
  722  debug_mode = 2;
  723#endif
  724
  725  if(debug_mode)
  726    C_dbg(C_text("debug"), C_text("application startup...\n"));
  727
  728  C_panic_hook = usual_panic;
  729  symbol_table_list = NULL;
  730
  731  symbol_table = C_new_symbol_table(".", symbols ? symbols : DEFAULT_SYMBOL_TABLE_SIZE);
  732
  733  if(symbol_table == NULL)
  734    return 0;
  735
  736  keyword_table = C_new_symbol_table("kw", symbols ? symbols / 4 : DEFAULT_KEYWORD_TABLE_SIZE);
  737
  738  if(keyword_table == NULL)
  739    return 0;
  740
  741  page_size = 0;
  742  stack_size = stack ? stack : DEFAULT_STACK_SIZE;
  743  C_set_or_change_heap_size(heap ? heap : DEFAULT_HEAP_SIZE, 0);
  744
  745  /* Allocate temporary stack: */
  746  temporary_stack_size = fixed_temporary_stack_size ? fixed_temporary_stack_size : DEFAULT_TEMPORARY_STACK_SIZE;
  747  if((C_temporary_stack_limit = (C_word *)C_malloc(temporary_stack_size * sizeof(C_word))) == NULL)
  748    return 0;
  749
  750  C_temporary_stack_bottom = C_temporary_stack_limit + temporary_stack_size;
  751  C_temporary_stack = C_temporary_stack_bottom;
  752
  753  /* Allocate mutation stack: */
  754  mutation_stack_bottom = (C_word **)C_malloc(DEFAULT_MUTATION_STACK_SIZE * sizeof(C_word *));
  755
  756  if(mutation_stack_bottom == NULL) return 0;
  757
  758  mutation_stack_top = mutation_stack_bottom;
  759  mutation_stack_limit = mutation_stack_bottom + DEFAULT_MUTATION_STACK_SIZE;
  760  C_gc_mutation_hook = NULL;
  761  C_gc_trace_hook = NULL;
  762
  763  /* Initialize finalizer lists: */
  764  finalizer_list = NULL;
  765  finalizer_free_list = NULL;
  766  pending_finalizer_indices =
  767      (FINALIZER_NODE **)C_malloc(C_max_pending_finalizers * sizeof(FINALIZER_NODE *));
  768
  769  if(pending_finalizer_indices == NULL) return 0;
  770
  771  /* Initialize forwarding table: */
  772  forwarding_table =
  773      (C_word *)C_malloc((DEFAULT_FORWARDING_TABLE_SIZE + 1) * 2 * sizeof(C_word));
  774
  775  if(forwarding_table == NULL) return 0;
  776
  777  *forwarding_table = 0;
  778  forwarding_table_size = DEFAULT_FORWARDING_TABLE_SIZE;
  779
  780  /* Setup collectibles: */
  781  collectibles = (C_word **)C_malloc(sizeof(C_word *) * DEFAULT_COLLECTIBLES_SIZE);
  782
  783  if(collectibles == NULL) return 0;
  784
  785  collectibles_top = collectibles;
  786  collectibles_limit = collectibles + DEFAULT_COLLECTIBLES_SIZE;
  787  gc_root_list = NULL;
  788
  789#if !defined(NO_DLOAD2) && defined(HAVE_DLFCN_H)
  790  dlopen_flags = RTLD_LAZY | RTLD_GLOBAL;
  791#else
  792  dlopen_flags = 0;
  793#endif
  794
  795#ifdef HAVE_SIGACTION
  796    sa.sa_flags = 0;
  797    sigfillset(&sa.sa_mask); /* See note in C_establish_signal_handler() */
  798    sa.sa_handler = global_signal_handler;
  799#endif
  800
  801  /* setup signal handlers */
  802  if(!pass_serious_signals) {
  803#ifdef HAVE_SIGACTION
  804    C_sigaction(SIGBUS, &sa, NULL);
  805    C_sigaction(SIGFPE, &sa, NULL);
  806    C_sigaction(SIGILL, &sa, NULL);
  807    C_sigaction(SIGSEGV, &sa, NULL);
  808#else
  809    C_signal(SIGBUS, global_signal_handler);
  810    C_signal(SIGILL, global_signal_handler);
  811    C_signal(SIGFPE, global_signal_handler);
  812    C_signal(SIGSEGV, global_signal_handler);
  813#endif
  814  }
  815
  816  tracked_mutation_count = mutation_count = gc_count_1 = gc_count_1_total = gc_count_2 = maximum_heap_usage = 0;
  817  lf_list = NULL;
  818  C_register_lf2(NULL, 0, create_initial_ptable());
  819  C_restart_trampoline = (void *)toplevel;
  820  trace_buffer = NULL;
  821  C_clear_trace_buffer();
  822  chicken_is_running = chicken_ran_once = 0;
  823  pending_interrupts_count = 0;
  824  handling_interrupts = 0;
  825  last_interrupt_latency = 0;
  826  C_interrupts_enabled = 1;
  827  C_initial_timer_interrupt_period = INITIAL_TIMER_INTERRUPT_PERIOD;
  828  C_timer_interrupt_counter = INITIAL_TIMER_INTERRUPT_PERIOD;
  829  memset(signal_mapping_table, 0, sizeof(int) * NSIG);
  830  C_dlerror = "cannot load compiled code dynamically - this is a statically linked executable";
  831  error_location = C_SCHEME_FALSE;
  832  C_pre_gc_hook = NULL;
  833  C_post_gc_hook = NULL;
  834  C_scratchspace_start = NULL;
  835  C_scratchspace_top = NULL;
  836  C_scratchspace_limit = NULL;
  837  C_scratch_usage = 0;
  838  scratchspace_size = 0;
  839  live_finalizer_count = 0;
  840  allocated_finalizer_count = 0;
  841  current_module_name = NULL;
  842  current_module_handle = NULL;
  843  callback_continuation_level = 0;
  844  weak_pair_chain = (C_word)NULL;
  845  locative_chain = (C_word)NULL;
  846  gc_ms = 0;
  847  if (!random_state_initialized) {
  848    C_fast_srand(time(NULL));
  849    random_state_initialized = 1;
  850  }
  851
  852  for(i = 0; i < C_RANDOM_STATE_SIZE / sizeof(C_uword); ++i)
  853    random_state[ i ] = C_fast_rand();
  854
  855  initialize_symbol_table();
  856
  857  if (profiling) {
  858#ifndef C_NONUNIX
  859# ifdef HAVE_SIGACTION
  860    C_sigaction(C_PROFILE_SIGNAL, &sa, NULL);
  861# else
  862    C_signal(C_PROFILE_SIGNAL, global_signal_handler);
  863# endif
  864#endif
  865
  866    profile_table = (PROFILE_BUCKET **)C_malloc(PROFILE_TABLE_SIZE * sizeof(PROFILE_BUCKET *));
  867
  868    if(profile_table == NULL)
  869      panic(C_text("out of memory - can not allocate profile table"));
  870
  871    C_memset(profile_table, 0, sizeof(PROFILE_BUCKET *) * PROFILE_TABLE_SIZE);
  872  }
  873
  874  /* create k to invoke code for system-startup: */
  875  k0 = (C_SCHEME_BLOCK *)C_align((C_word)C_fromspace_top);
  876  C_fromspace_top += C_align(2 * sizeof(C_word));
  877  k0->header = C_CLOSURE_TYPE | 1;
  878  C_set_block_item(k0, 0, (C_word)termination_continuation);
  879  C_save(k0);
  880  C_save(C_SCHEME_UNDEFINED);
  881  C_restart_c = 2;
  882  return 1;
  883}
  884
  885
  886void *C_get_statistics(void) {
  887  static void *stats[ 8 ];
  888
  889  stats[ 0 ] = fromspace_start;
  890  stats[ 1 ] = C_fromspace_limit;
  891  stats[ 2 ] = C_scratchspace_start;
  892  stats[ 3 ] = C_scratchspace_limit;
  893  stats[ 4 ] = C_stack_limit;
  894  stats[ 5 ] = stack_bottom;
  895  stats[ 6 ] = C_fromspace_top;
  896  stats[ 7 ] = C_scratchspace_top;
  897  return stats;
  898}
  899
  900
  901static C_PTABLE_ENTRY *create_initial_ptable()
  902{
  903  /* IMPORTANT: hardcoded table size -
  904     this must match the number of C_pte calls + 1 (NULL terminator)! */
  905  C_PTABLE_ENTRY *pt = (C_PTABLE_ENTRY *)C_malloc(sizeof(C_PTABLE_ENTRY) * 64);
  906  int i = 0;
  907
  908  if(pt == NULL)
  909    panic(C_text("out of memory - cannot create initial ptable"));
  910
  911  C_pte(termination_continuation);
  912  C_pte(callback_return_continuation);
  913  C_pte(values_continuation);
  914  C_pte(call_cc_values_wrapper);
  915  C_pte(call_cc_wrapper);
  916  C_pte(C_gc);
  917  C_pte(C_allocate_vector);
  918  C_pte(C_allocate_bytevector);
  919  C_pte(C_make_structure);
  920  C_pte(C_ensure_heap_reserve);
  921  C_pte(C_return_to_host);
  922  C_pte(C_get_symbol_table_info);
  923  C_pte(C_get_memory_info);
  924  C_pte(C_decode_seconds);
  925  C_pte(C_stop_timer);
  926  C_pte(C_dload);
  927  C_pte(C_set_dlopen_flags);
  928  C_pte(C_become);
  929  C_pte(C_apply_values);
  930  C_pte(C_times);
  931  C_pte(C_minus);
  932  C_pte(C_plus);
  933  C_pte(C_nequalp);
  934  C_pte(C_greaterp);
  935  /* IMPORTANT: have you read the comments at the start and the end of this function? */
  936  C_pte(C_lessp);
  937  C_pte(C_greater_or_equal_p);
  938  C_pte(C_less_or_equal_p);
  939  C_pte(C_number_to_string);
  940  C_pte(C_make_symbol);
  941  C_pte(C_string_to_symbol);
  942  C_pte(C_string_to_keyword);
  943  C_pte(C_apply);
  944  C_pte(C_call_cc);
  945  C_pte(C_values);
  946  C_pte(C_call_with_values);
  947  C_pte(C_continuation_graft);
  948  C_pte(C_open_file_port);
  949  C_pte(C_software_type);
  950  C_pte(C_machine_type);
  951  C_pte(C_machine_byte_order);
  952  C_pte(C_software_version);
  953  C_pte(C_build_platform);
  954  C_pte(C_make_pointer);
  955  /* IMPORTANT: have you read the comments at the start and the end of this function? */
  956  C_pte(C_make_tagged_pointer);
  957  C_pte(C_peek_signed_integer);
  958  C_pte(C_peek_unsigned_integer);
  959  C_pte(C_peek_int64);
  960  C_pte(C_peek_uint64);
  961  C_pte(C_context_switch);
  962  C_pte(C_register_finalizer);
  963  C_pte(C_copy_closure);
  964  C_pte(C_dump_heap_state);
  965  C_pte(C_filter_heap_objects);
  966  C_pte(C_fixnum_to_string);
  967  C_pte(C_integer_to_string);
  968  C_pte(C_flonum_to_string);
  969  C_pte(C_signum);
  970  C_pte(C_quotient_and_remainder);
  971  C_pte(C_u_integer_quotient_and_remainder);
  972  C_pte(C_bitwise_and);
  973  C_pte(C_bitwise_ior);
  974  C_pte(C_bitwise_xor);
  975
  976  /* IMPORTANT: did you remember the hardcoded pte table size? */
  977  pt[ i ].id = NULL;
  978  return pt;
  979}
  980
  981
  982void *CHICKEN_new_gc_root_2(int finalizable)
  983{
  984  C_GC_ROOT *r = (C_GC_ROOT *)C_malloc(sizeof(C_GC_ROOT));
  985
  986  if(r == NULL)
  987    panic(C_text("out of memory - cannot allocate GC root"));
  988
  989  r->value = C_SCHEME_UNDEFINED;
  990  r->next = gc_root_list;
  991  r->prev = NULL;
  992  r->finalizable = finalizable;
  993
  994  if(gc_root_list != NULL) gc_root_list->prev = r;
  995
  996  gc_root_list = r;
  997  return (void *)r;
  998}
  999
  1000
 1001void *CHICKEN_new_gc_root()
 1002{
 1003  return CHICKEN_new_gc_root_2(0);
 1004}
 1005
 1006
 1007void *CHICKEN_new_finalizable_gc_root()
 1008{
 1009  return CHICKEN_new_gc_root_2(1);
 1010}
 1011
 1012
 1013void CHICKEN_delete_gc_root(void *root)
 1014{
 1015  C_GC_ROOT *r = (C_GC_ROOT *)root;
 1016
 1017  if(r->prev == NULL) gc_root_list = r->next;
 1018  else r->prev->next = r->next;
 1019
 1020  if(r->next != NULL) r->next->prev = r->prev;
 1021
 1022  C_free(root);
 1023}
 1024
 1025
 1026void *CHICKEN_global_lookup(char *name)
 1027{
 1028  int
 1029    len = C_strlen(name),
 1030    key = hash_string(len, name, symbol_table->size, symbol_table->rand);
 1031  C_word s;
 1032  void *root = CHICKEN_new_gc_root();
 1033
 1034  if(C_truep(s = lookup(key, len, name, symbol_table))) {
 1035    if(C_block_item(s, 0) != C_SCHEME_UNBOUND) {
 1036      CHICKEN_gc_root_set(root, s);
 1037      return root;
 1038    }
 1039  }
 1040
 1041  return NULL;
 1042}
 1043
 1044
 1045int CHICKEN_is_running()
 1046{
 1047  return chicken_is_running;
 1048}
 1049
 1050
 1051void CHICKEN_interrupt()
 1052{
 1053  C_timer_interrupt_counter = 0;
 1054}
 1055
 1056
 1057C_regparm C_SYMBOL_TABLE *C_new_symbol_table(char *name, unsigned int size)
 1058{
 1059  C_SYMBOL_TABLE *stp;
 1060  int i;
 1061
 1062  if((stp = C_find_symbol_table(name)) != NULL) return stp;
 1063
 1064  if((stp = (C_SYMBOL_TABLE *)C_malloc(sizeof(C_SYMBOL_TABLE))) == NULL)
 1065    return NULL;
 1066
 1067  stp->name = name;
 1068  stp->size = size;
 1069  stp->next = symbol_table_list;
 1070  stp->rand = C_fast_rand();
 1071
 1072  if((stp->table = (C_word *)C_malloc(size * sizeof(C_word))) == NULL)
 1073    return NULL;
 1074
 1075  for(i = 0; i < stp->size; stp->table[ i++ ] = C_SCHEME_END_OF_LIST);
 1076
 1077  symbol_table_list = stp;
 1078  return stp;
 1079}
 1080
 1081
 1082C_regparm C_SYMBOL_TABLE *C_find_symbol_table(char *name)
 1083{
 1084  C_SYMBOL_TABLE *stp;
 1085
 1086  for(stp = symbol_table_list; stp != NULL; stp = stp->next)
 1087    if(!C_strcmp(name, stp->name)) return stp;
 1088
 1089  return NULL;
 1090}
 1091
 1092
 1093C_regparm C_word C_find_symbol(C_word bv, C_SYMBOL_TABLE *stable)
 1094{
 1095  C_char *sptr = C_c_string(bv);
 1096  int len = C_header_size(bv) - 1;
 1097  int key;
 1098  C_word s;
 1099
 1100  if(stable == NULL) stable = symbol_table;
 1101
 1102  key = hash_string(len, sptr, stable->size, stable->rand);
 1103
 1104  if(C_truep(s = lookup(key, len, sptr, stable))) return s;
 1105  else return C_SCHEME_FALSE;
 1106}
 1107
 1108
 1109/* Setup symbol-table with internally used symbols; */
 1110
 1111void initialize_symbol_table(void)
 1112{
 1113  int i;
 1114
 1115  for(i = 0; i < symbol_table->size; symbol_table->table[ i++ ] = C_SCHEME_END_OF_LIST);
 1116
 1117  /* Obtain reference to hooks for later: */
 1118  core_provided_symbol = C_intern2(C_heaptop, C_text("##core#provided"));
 1119  interrupt_hook_symbol = C_intern2(C_heaptop, C_text("##sys#interrupt-hook"));
 1120  error_hook_symbol = C_intern2(C_heaptop, C_text("##sys#error-hook"));
 1121  callback_continuation_stack_symbol = C_intern3(C_heaptop, C_text("##sys#callback-continuation-stack"), C_SCHEME_END_OF_LIST);
 1122  pending_finalizers_symbol = C_intern2(C_heaptop, C_text("##sys#pending-finalizers"));
 1123  current_thread_symbol = C_intern3(C_heaptop, C_text("##sys#current-thread"), C_SCHEME_FALSE);
 1124
 1125  /* SRFI-4 tags */
 1126  s8vector_symbol = C_intern2(C_heaptop, C_text("s8vector"));
 1127  u16vector_symbol = C_intern2(C_heaptop, C_text("u16vector"));
 1128  s16vector_symbol = C_intern2(C_heaptop, C_text("s16vector"));
 1129  u32vector_symbol = C_intern2(C_heaptop, C_text("u32vector"));
 1130  s32vector_symbol = C_intern2(C_heaptop, C_text("s32vector"));
 1131  u64vector_symbol = C_intern2(C_heaptop, C_text("u64vector"));
 1132  s64vector_symbol = C_intern2(C_heaptop, C_text("s64vector"));
 1133  f32vector_symbol = C_intern2(C_heaptop, C_text("f32vector"));
 1134  f64vector_symbol = C_intern2(C_heaptop, C_text("f64vector"));
 1135}
 1136
 1137
 1138C_regparm C_word C_find_keyword(C_word str, C_SYMBOL_TABLE *kwtable)
 1139{
 1140  C_char *sptr = C_c_string(str);
 1141  int len = C_header_size(str) - 1;
 1142  int key;
 1143  C_word s;
 1144
 1145  if(kwtable == NULL) kwtable = keyword_table;
 1146
 1147  key = hash_string(len, sptr, kwtable->size, kwtable->rand);
 1148
 1149  if(C_truep(s = lookup(key, len, sptr, kwtable))) return s;
 1150  else return C_SCHEME_FALSE;
 1151}
 1152
 1153
 1154void C_ccall sigsegv_trampoline(C_word c, C_word *av)
 1155{
 1156  barf(C_MEMORY_VIOLATION_ERROR, NULL);
 1157}
 1158
 1159
 1160void C_ccall sigbus_trampoline(C_word c, C_word *av)
 1161{
 1162  barf(C_BUS_ERROR, NULL);
 1163}
 1164
 1165
 1166void C_ccall sigfpe_trampoline(C_word c, C_word *av)
 1167{
 1168  barf(C_FLOATING_POINT_EXCEPTION_ERROR, NULL);
 1169}
 1170
 1171
 1172void C_ccall sigill_trampoline(C_word c, C_word *av)
 1173{
 1174  barf(C_ILLEGAL_INSTRUCTION_ERROR, NULL);
 1175}
 1176
 1177
 1178/* This is called from POSIX signals: */
 1179
 1180void global_signal_handler(int signum)
 1181{
 1182#if defined(HAVE_SIGPROCMASK)
 1183  if(signum == SIGSEGV || signum == SIGFPE || signum == SIGILL || signum == SIGBUS) {
 1184    sigset_t sset;
 1185
 1186    if(serious_signal_occurred || !chicken_is_running) {
 1187      switch(signum) {
 1188      case SIGSEGV: panic(C_text("unrecoverable segmentation violation"));
 1189      case SIGFPE: panic(C_text("unrecoverable floating-point exception"));
 1190      case SIGILL: panic(C_text("unrecoverable illegal instruction error"));
 1191      case SIGBUS: panic(C_text("unrecoverable bus error"));
 1192      default: panic(C_text("unrecoverable serious condition"));
 1193      }
 1194    }
 1195    else serious_signal_occurred = 1;
 1196
 1197    /* unblock signal to avoid nested invocation of the handler */
 1198    sigemptyset(&sset);
 1199    sigaddset(&sset, signum);
 1200    C_sigprocmask(SIG_UNBLOCK, &sset, NULL);
 1201
 1202    switch(signum) {
 1203    case SIGSEGV: C_reclaim(sigsegv_trampoline, 0);
 1204    case SIGFPE: C_reclaim(sigfpe_trampoline, 0);
 1205    case SIGILL: C_reclaim(sigill_trampoline, 0);
 1206    case SIGBUS: C_reclaim(sigbus_trampoline, 0);
 1207    default: panic(C_text("invalid serious signal"));
 1208    }
 1209  }
 1210#endif
 1211
 1212  /* TODO: Make full use of sigaction: check that /our/ timer expired */
 1213  if (signum == C_PROFILE_SIGNAL && profiling) take_profile_sample();
 1214  else C_raise_interrupt(signal_mapping_table[ signum ]);
 1215
 1216#ifndef HAVE_SIGACTION
 1217  /* not necessarily needed, but older UNIXen may not leave the handler installed: */
 1218  C_signal(signum, global_signal_handler);
 1219#endif
 1220}
 1221
 1222
 1223/* Align memory to page boundary */
 1224
 1225static void *align_to_page(void *mem)
 1226{
 1227  return (void *)C_align((C_uword)mem);
 1228}
 1229
 1230
 1231static C_byte *
 1232heap_alloc (size_t size, C_byte **page_aligned)
 1233{
 1234  C_byte *p;
 1235  p = (C_byte *)C_malloc (size + page_size);
 1236
 1237  if (p != NULL && page_aligned) *page_aligned = align_to_page (p);
 1238
 1239  return p;
 1240}
 1241
 1242
 1243static void
 1244heap_free (C_byte *ptr, size_t size)
 1245{
 1246  C_free (ptr);
 1247}
 1248
 1249
 1250static C_byte *
 1251heap_realloc (C_byte *ptr, size_t old_size,
 1252	      size_t new_size, C_byte **page_aligned)
 1253{
 1254  C_byte *p;
 1255  p = (C_byte *)C_realloc (ptr, new_size + page_size);
 1256
 1257  if (p != NULL && page_aligned) *page_aligned = align_to_page (p);
 1258
 1259  return p;
 1260}
 1261
 1262
 1263/* Modify heap size at runtime: */
 1264
 1265void C_set_or_change_heap_size(C_word heap, int reintern)
 1266{
 1267  C_byte *ptr1, *ptr2, *ptr1a, *ptr2a;
 1268  C_word size = heap / 2;
 1269
 1270  if(heap_size_changed && fromspace_start) return;
 1271
 1272  if(fromspace_start && heap_size >= heap) return;
 1273
 1274  if(debug_mode)
 1275    C_dbg(C_text("debug"), C_text("heap resized to " UWORD_COUNT_FORMAT_STRING " bytes\n"), heap);
 1276
 1277  heap_size = heap;
 1278
 1279  if((ptr1 = heap_realloc (fromspace_start,
 1280			   C_fromspace_limit - fromspace_start,
 1281			   size, &ptr1a)) == NULL ||
 1282     (ptr2 = heap_realloc (tospace_start,
 1283			   tospace_limit - tospace_start,
 1284			   size, &ptr2a)) == NULL)
 1285    panic(C_text("out of memory - cannot allocate heap"));
 1286
 1287  heapspace1 = ptr1;
 1288  heapspace1_size = size;
 1289  heapspace2 = ptr2;
 1290  heapspace2_size = size;
 1291  fromspace_start = ptr1a;
 1292  C_fromspace_top = fromspace_start;
 1293  C_fromspace_limit = fromspace_start + size;
 1294  tospace_start = ptr2a;
 1295  tospace_top = tospace_start;
 1296  tospace_limit = tospace_start + size;
 1297  mutation_stack_top = mutation_stack_bottom;
 1298
 1299  if(reintern) initialize_symbol_table();
 1300}
 1301
 1302
 1303/* Modify stack-size at runtime: */
 1304
 1305void C_do_resize_stack(C_word stack)
 1306{
 1307  C_uword old = stack_size,
 1308          diff = stack - old;
 1309
 1310  if(diff != 0 && !stack_size_changed) {
 1311    if(debug_mode)
 1312      C_dbg(C_text("debug"), C_text("stack resized to " UWORD_COUNT_FORMAT_STRING " bytes\n"), stack);
 1313
 1314    stack_size = stack;
 1315
 1316#if C_STACK_GROWS_DOWNWARD
 1317    C_stack_hard_limit = (C_word *)((C_byte *)C_stack_hard_limit - diff);
 1318#else
 1319    C_stack_hard_limit = (C_word *)((C_byte *)C_stack_hard_limit + diff);
 1320#endif
 1321    C_stack_limit = C_stack_hard_limit;
 1322  }
 1323}
 1324
 1325
 1326/* Check whether nursery is sufficiently big: */
 1327
 1328void C_check_nursery_minimum(C_word words)
 1329{
 1330  if(words >= C_bytestowords(stack_size))
 1331    panic(C_text("nursery is too small - try higher setting using the `-:s' option"));
 1332}
 1333
 1334C_word C_resize_pending_finalizers(C_word size) {
 1335  int sz = C_num_to_int(size);
 1336
 1337  FINALIZER_NODE **newmem =
 1338    (FINALIZER_NODE **)C_realloc(pending_finalizer_indices, sz * sizeof(FINALIZER_NODE *));
 1339
 1340  if (newmem == NULL)
 1341    return C_SCHEME_FALSE;
 1342
 1343  pending_finalizer_indices = newmem;
 1344  C_max_pending_finalizers = sz;
 1345  return C_SCHEME_TRUE;
 1346}
 1347
 1348
 1349/* Parse runtime options from command-line: */
 1350
 1351void CHICKEN_parse_command_line(int argc, C_char *argv[], C_word *heap, C_word *stack, C_word *symbols)
 1352{
 1353  int i;
 1354  C_char *ptr;
 1355  C_word x;
 1356
 1357  C_main_argc = argc;
 1358  C_main_argv = argv;
 1359
 1360  *heap = DEFAULT_HEAP_SIZE;
 1361  *stack = DEFAULT_STACK_SIZE;
 1362  *symbols = DEFAULT_SYMBOL_TABLE_SIZE;
 1363
 1364  for(i = 1; i < C_main_argc; ++i) {
 1365    if (strncmp(C_main_argv[ i ], C_text("-:"), 2))
 1366      break; /* Stop parsing on first non-runtime option */
 1367
 1368    ptr = &C_main_argv[ i ][ 2 ];
 1369    if (*ptr == '\0')
 1370      break; /* Also stop parsing on first "empty" option (i.e. "-:") */
 1371
 1372    do {
 1373      switch(*(ptr++)) {
 1374      case '?':
 1375        C_dbg("Runtime options", "\n\n"
 1376              " -:?              display this text\n"
 1377              " -:c              always treat stdin as console\n"
 1378              " -:d              enable debug output\n"
 1379              " -:D              enable more debug output\n"
 1380              " -:g              show GC information\n"
 1381              " -:o              disable stack overflow checks\n"
 1382              " -:hiSIZE         set initial heap size\n"
 1383              " -:hmSIZE         set maximal heap size\n"
 1384              " -:hfSIZE         set minimum unused heap size\n"
 1385              " -:hgPERCENTAGE   set heap growth percentage\n"
 1386              " -:hsPERCENTAGE   set heap shrink percentage\n"
 1387              " -:huPERCENTAGE   set percentage of memory used at which heap will be shrunk\n"
 1388              " -:hSIZE          set fixed heap size\n"
 1389              " -:r              write trace output to stderr\n"
 1390              " -:RSEED          initialize rand() seed with SEED (helpful for benchmark stability)\n"
 1391              " -:p              collect statistical profile and write to file at exit\n"
 1392              " -:PFREQUENCY     like -:p, specifying sampling frequency in us (default: 10000)\n"
 1393              " -:sSIZE          set nursery (stack) size\n"
 1394              " -:tSIZE          set symbol-table size\n"
 1395              " -:fSIZE          set maximal number of pending finalizers\n"
 1396              " -:x              deliver uncaught exceptions of other threads to primordial one\n"
 1397              " -:B              sound bell on major GC\n"
 1398              " -:G              force GUI mode\n"
 1399              " -:aSIZE          set trace-buffer/call-chain size\n"
 1400              " -:ASIZE          set fixed temporary stack size\n"
 1401              " -:H              dump heap state on exit\n"
 1402              " -:S              do not handle segfaults or other serious conditions\n"
 1403              "\n  SIZE may have a `k' (`K'), `m' (`M') or `g' (`G') suffix, meaning size\n"
 1404              "  times 1024, 1048576, and 1073741824, respectively.\n\n");
 1405        C_exit_runtime(C_fix(0));
 1406
 1407      case 'h':
 1408        switch(*ptr) {
 1409        case 'i':
 1410          *heap = arg_val(ptr + 1);
 1411          heap_size_changed = 1;
 1412          goto next;
 1413        case 'f':
 1414          C_heap_half_min_free = arg_val(ptr + 1);
 1415          goto next;
 1416        case 'g':
 1417          C_heap_growth = arg_val(ptr + 1);
 1418          goto next;
 1419        case 'm':
 1420          C_maximal_heap_size = arg_val(ptr + 1);
 1421          goto next;
 1422        case 's':
 1423          C_heap_shrinkage = arg_val(ptr + 1);
 1424          goto next;
 1425        case 'u':
 1426          C_heap_shrinkage_used = arg_val(ptr + 1);
 1427          goto next;
 1428        default:
 1429          *heap = arg_val(ptr);
 1430          heap_size_changed = 1;
 1431          C_heap_size_is_fixed = 1;
 1432          goto next;
 1433        }
 1434
 1435      case 'o':
 1436        C_disable_overflow_check = 1;
 1437        break;
 1438
 1439      case 'B':
 1440        gc_bell = 1;
 1441        break;
 1442
 1443      case 'G':
 1444        C_gui_mode = 1;
 1445        break;
 1446
 1447      case 'H':
 1448        dump_heap_on_exit = 1;
 1449        break;
 1450
 1451      case 'S':
 1452        pass_serious_signals = 1;
 1453        break;
 1454
 1455      case 's':
 1456        *stack = arg_val(ptr);
 1457        stack_size_changed = 1;
 1458        goto next;
 1459
 1460      case 'f':
 1461        C_max_pending_finalizers = arg_val(ptr);
 1462        goto next;
 1463
 1464      case 'a':
 1465        C_trace_buffer_size = arg_val(ptr);
 1466        goto next;
 1467
 1468      case 'A':
 1469        fixed_temporary_stack_size = arg_val(ptr);
 1470        goto next;
 1471
 1472      case 't':
 1473        *symbols = arg_val(ptr);
 1474        goto next;
 1475
 1476      case 'c':
 1477        fake_tty_flag = 1;
 1478        break;
 1479
 1480      case 'd':
 1481        debug_mode = 1;
 1482        break;
 1483
 1484      case 'D':
 1485        debug_mode = 2;
 1486        break;
 1487
 1488      case 'g':
 1489        gc_report_flag = 2;
 1490        break;
 1491
 1492      case 'P':
 1493        profiling = 1;
 1494        profile_frequency = arg_val(ptr);
 1495        goto next;
 1496
 1497      case 'p':
 1498        profiling = 1;
 1499        break;
 1500
 1501      case 'r':
 1502        show_trace = 1;
 1503        break;
 1504
 1505      case 'R':
 1506        C_fast_srand((unsigned int)arg_val(ptr));
 1507        random_state_initialized = 1;
 1508        goto next;
 1509
 1510      case 'x':
 1511        C_abort_on_thread_exceptions = 1;
 1512        break;
 1513
 1514      default: panic(C_text("illegal runtime option"));
 1515      }
 1516    } while(*ptr != '\0');
 1517
 1518    next:;
 1519    }
 1520}
 1521
 1522
 1523C_word arg_val(C_char *arg)
 1524{
 1525  int len;
 1526  C_char *end;
 1527  C_long val, mul = 1;
 1528
 1529  if (arg == NULL) panic(C_text("illegal runtime-option argument"));
 1530
 1531  len = C_strlen(arg);
 1532
 1533  if(len < 1) panic(C_text("illegal runtime-option argument"));
 1534
 1535  switch(arg[ len - 1 ]) {
 1536  case 'k':
 1537  case 'K': mul = 1024; break;
 1538
 1539  case 'm':
 1540  case 'M': mul = 1024 * 1024; break;
 1541
 1542  case 'g':
 1543  case 'G': mul = 1024 * 1024 * 1024; break;
 1544
 1545  default: mul = 1;
 1546  }
 1547
 1548  val = C_strtow(arg, &end, 10);
 1549
 1550  if((mul != 1 ? end[ 1 ] != '\0' : end[ 0 ] != '\0'))
 1551    panic(C_text("invalid runtime-option argument suffix"));
 1552
 1553  return val * mul;
 1554}
 1555
 1556
 1557/* Run embedded code with arguments: */
 1558
 1559C_word CHICKEN_run(void *toplevel)
 1560{
 1561  if(!chicken_is_initialized && !CHICKEN_initialize(0, 0, 0, toplevel))
 1562    panic(C_text("could not initialize"));
 1563
 1564  if(chicken_is_running)
 1565    panic(C_text("re-invocation of Scheme world while process is already running"));
 1566
 1567  chicken_is_running = chicken_ran_once = 1;
 1568  return_to_host = 0;
 1569
 1570  if(profiling) set_profile_timer(profile_frequency);
 1571
 1572#if C_STACK_GROWS_DOWNWARD
 1573  C_stack_hard_limit = (C_word *)((C_byte *)C_stack_pointer - stack_size);
 1574#else
 1575  C_stack_hard_limit = (C_word *)((C_byte *)C_stack_pointer + stack_size);
 1576#endif
 1577  C_stack_limit = C_stack_hard_limit;
 1578
 1579  stack_bottom = C_stack_pointer;
 1580
 1581  if(debug_mode)
 1582    C_dbg(C_text("debug"), C_text("stack bottom is 0x%lx\n"), (C_word)stack_bottom);
 1583
 1584  /* The point of (usually) no return... */
 1585#ifdef HAVE_SIGSETJMP
 1586  C_sigsetjmp(C_restart, 0);
 1587#else
 1588  C_setjmp(C_restart);
 1589#endif
 1590
 1591  serious_signal_occurred = 0;
 1592
 1593  if(!return_to_host) {
 1594    /* We must copy the argvector onto the stack, because
 1595     * any subsequent save() will otherwise clobber it.
 1596     */
 1597    C_word *p = C_alloc(C_restart_c);
 1598    assert(C_restart_c == (C_temporary_stack_bottom - C_temporary_stack));
 1599    C_memcpy(p, C_temporary_stack, C_restart_c * sizeof(C_word));
 1600    C_temporary_stack = C_temporary_stack_bottom;
 1601    ((C_proc)C_restart_trampoline)(C_restart_c, p);
 1602  }
 1603
 1604  if(profiling) set_profile_timer(0);
 1605
 1606  chicken_is_running = 0;
 1607  return C_restore;
 1608}
 1609
 1610
 1611C_word CHICKEN_continue(C_word k)
 1612{
 1613  if(C_temporary_stack_bottom != C_temporary_stack)
 1614    panic(C_text("invalid temporary stack level"));
 1615
 1616  if(!chicken_is_initialized)
 1617    panic(C_text("runtime system has not been initialized - `CHICKEN_run' has probably not been called"));
 1618
 1619  C_save(k);
 1620  return CHICKEN_run(NULL);
 1621}
 1622
 1623
 1624/* The final continuation: */
 1625
 1626void C_ccall termination_continuation(C_word c, C_word *av)
 1627{
 1628  if(debug_mode) {
 1629    C_dbg(C_text("debug"), C_text("application terminated normally\n"));
 1630  }
 1631
 1632  C_exit_runtime(C_fix(0));
 1633}
 1634
 1635
 1636/* Signal unrecoverable runtime error: */
 1637
 1638void panic(C_char *msg)
 1639{
 1640  if(C_panic_hook != NULL) C_panic_hook(msg);
 1641
 1642  usual_panic(msg);
 1643}
 1644
 1645
 1646void usual_panic(C_char *msg)
 1647{
 1648  C_char *dmp = C_dump_trace(0);
 1649
 1650  C_dbg_hook(C_SCHEME_UNDEFINED);
 1651
 1652  if(C_gui_mode) {
 1653    C_snprintf(buffer, sizeof(buffer), C_text("%s\n\n%s"), msg, dmp);
 1654#if defined(_WIN32) && !defined(__CYGWIN__)
 1655    MessageBox(NULL, buffer, C_text("CHICKEN runtime"), MB_OK | MB_ICONERROR);
 1656    ExitProcess(1);
 1657#endif
 1658  } /* fall through if not WIN32 GUI app */
 1659
 1660  C_dbg("panic", C_text("%s - execution terminated\n\n%s"), msg, dmp);
 1661  C_exit_runtime(C_fix(1));
 1662}
 1663
 1664
 1665void horror(C_char *msg)
 1666{
 1667  C_dbg_hook(C_SCHEME_UNDEFINED);
 1668
 1669  if(C_gui_mode) {
 1670    C_snprintf(buffer, sizeof(buffer), C_text("%s"), msg);
 1671#if defined(_WIN32) && !defined(__CYGWIN__)
 1672    MessageBox(NULL, buffer, C_text("CHICKEN runtime"), MB_OK | MB_ICONERROR);
 1673    ExitProcess(1);
 1674#endif
 1675  } /* fall through */
 1676
 1677  C_dbg("horror", C_text("\n%s - execution terminated"), msg);
 1678  C_exit_runtime(C_fix(1));
 1679}
 1680
 1681
 1682/* Error-hook, called from C-level runtime routines: */
 1683
 1684void barf(int code, char *loc, ...)
 1685{
 1686  C_char *msg;
 1687  C_word err = error_hook_symbol;
 1688  int c, i;
 1689  va_list v;
 1690  C_word *av;
 1691
 1692  C_dbg_hook(C_SCHEME_UNDEFINED);
 1693
 1694  C_temporary_stack = C_temporary_stack_bottom;
 1695  err = C_block_item(err, 0);
 1696
 1697  switch(code) {
 1698  case C_BAD_ARGUMENT_COUNT_ERROR:
 1699    msg = C_text("bad argument count");
 1700    c = 3;
 1701    break;
 1702
 1703  case C_BAD_MINIMUM_ARGUMENT_COUNT_ERROR:
 1704    msg = C_text("too few arguments");
 1705    c = 3;
 1706    break;
 1707
 1708  case C_BAD_ARGUMENT_TYPE_ERROR:
 1709    msg = C_text("bad argument type");
 1710    c = 1;
 1711    break;
 1712
 1713  case C_UNBOUND_VARIABLE_ERROR:
 1714    msg = C_text("unbound variable");
 1715    c = 1;
 1716    break;
 1717
 1718  case C_BAD_ARGUMENT_TYPE_NO_KEYWORD_ERROR:
 1719    msg = C_text("bad argument type - not a keyword");
 1720    c = 1;
 1721    break;
 1722
 1723  case C_OUT_OF_MEMORY_ERROR:
 1724    msg = C_text("not enough memory");
 1725    c = 0;
 1726    break;
 1727
 1728  case C_DIVISION_BY_ZERO_ERROR:
 1729    msg = C_text("division by zero");
 1730    c = 0;
 1731    break;
 1732
 1733  case C_OUT_OF_BOUNDS_ERROR:
 1734    msg = C_text("out of range");
 1735    c = 2;
 1736    break;
 1737
 1738  case C_NOT_A_CLOSURE_ERROR:
 1739    msg = C_text("call of non-procedure");
 1740    c = 1;
 1741    break;
 1742
 1743  case C_CONTINUATION_CANT_RECEIVE_VALUES_ERROR:
 1744    msg = C_text("continuation cannot receive multiple values");
 1745    c = 1;
 1746    break;
 1747
 1748  case C_BAD_ARGUMENT_TYPE_CYCLIC_LIST_ERROR:
 1749    msg = C_text("bad argument type - not a non-cyclic list");
 1750    c = 1;
 1751    break;
 1752
 1753  case C_TOO_DEEP_RECURSION_ERROR:
 1754    msg = C_text("recursion too deep");
 1755    c = 0;
 1756    break;
 1757
 1758  case C_CANT_REPRESENT_INEXACT_ERROR:
 1759    msg = C_text("inexact number cannot be represented as an exact number");
 1760    c = 1;
 1761    break;
 1762
 1763  case C_NOT_A_PROPER_LIST_ERROR:
 1764    msg = C_text("bad argument type - not a proper list");
 1765    c = 1;
 1766    break;
 1767
 1768  case C_BAD_ARGUMENT_TYPE_NO_FIXNUM_ERROR:
 1769    msg = C_text("bad argument type - not a fixnum");
 1770    c = 1;
 1771    break;
 1772
 1773  case C_BAD_ARGUMENT_TYPE_NO_STRING_ERROR:
 1774    msg = C_text("bad argument type - not a string");
 1775    c = 1;
 1776    break;
 1777
 1778  case C_BAD_ARGUMENT_TYPE_NO_PAIR_ERROR:
 1779    msg = C_text("bad argument type - not a pair");
 1780    c = 1;
 1781    break;
 1782
 1783  case C_BAD_ARGUMENT_TYPE_NO_BOOLEAN_ERROR:
 1784    msg = C_text("bad argument type - not a boolean");
 1785    c = 1;
 1786    break;
 1787
 1788  case C_BAD_ARGUMENT_TYPE_NO_LOCATIVE_ERROR:
 1789    msg = C_text("bad argument type - not a locative");
 1790    c = 1;
 1791    break;
 1792
 1793  case C_BAD_ARGUMENT_TYPE_NO_LIST_ERROR:
 1794    msg = C_text("bad argument type - not a list");
 1795    c = 1;
 1796    break;
 1797
 1798  case C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR:
 1799    msg = C_text("bad argument type - not a number");
 1800    c = 1;
 1801    break;
 1802
 1803  case C_BAD_ARGUMENT_TYPE_NO_SYMBOL_ERROR:
 1804    msg = C_text("bad argument type - not a symbol");
 1805    c = 1;
 1806    break;
 1807
 1808  case C_BAD_ARGUMENT_TYPE_NO_VECTOR_ERROR:
 1809    msg = C_text("bad argument type - not a vector");
 1810    c = 1;
 1811    break;
 1812
 1813  case C_BAD_ARGUMENT_TYPE_NO_CHAR_ERROR:
 1814    msg = C_text("bad argument type - not a character");
 1815    c = 1;
 1816    break;
 1817
 1818  case C_STACK_OVERFLOW_ERROR:
 1819    msg = C_text("stack overflow");
 1820    c = 0;
 1821    break;
 1822
 1823  case C_BAD_ARGUMENT_TYPE_BAD_STRUCT_ERROR:
 1824    msg = C_text("bad argument type - not a structure of the required type");
 1825    c = 2;
 1826    break;
 1827
 1828  case C_BAD_ARGUMENT_TYPE_NO_BYTEVECTOR_ERROR:
 1829    msg = C_text("bad argument type - not a bytevector");
 1830    c = 1;
 1831    break;
 1832
 1833  case C_LOST_LOCATIVE_ERROR:
 1834    msg = C_text("locative refers to reclaimed object");
 1835    c = 1;
 1836    break;
 1837
 1838  case C_BAD_ARGUMENT_TYPE_NO_BLOCK_ERROR:
 1839    msg = C_text("bad argument type - not a object");
 1840    c = 1;
 1841    break;
 1842
 1843  case C_BAD_ARGUMENT_TYPE_NO_NUMBER_VECTOR_ERROR:
 1844    msg = C_text("bad argument type - not a number vector");
 1845    c = 2;
 1846    break;
 1847
 1848  case C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR:
 1849    msg = C_text("bad argument type - not an integer");
 1850    c = 1;
 1851    break;
 1852
 1853  case C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR:
 1854    msg = C_text("bad argument type - not an unsigned integer");
 1855    c = 1;
 1856    break;
 1857
 1858  case C_BAD_ARGUMENT_TYPE_NO_POINTER_ERROR:
 1859    msg = C_text("bad argument type - not a pointer");
 1860    c = 1;
 1861    break;
 1862
 1863  case C_BAD_ARGUMENT_TYPE_NO_TAGGED_POINTER_ERROR:
 1864    msg = C_text("bad argument type - not a tagged pointer");
 1865    c = 2;
 1866    break;
 1867
 1868  case C_BAD_ARGUMENT_TYPE_NO_FLONUM_ERROR:
 1869    msg = C_text("bad argument type - not a flonum");
 1870    c = 1;
 1871    break;
 1872
 1873  case C_BAD_ARGUMENT_TYPE_NO_CLOSURE_ERROR:
 1874    msg = C_text("bad argument type - not a procedure");
 1875    c = 1;
 1876    break;
 1877
 1878  case C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR:
 1879    msg = C_text("bad argument type - invalid base");
 1880    c = 1;
 1881    break;
 1882
 1883  case C_CIRCULAR_DATA_ERROR:
 1884    msg = C_text("recursion too deep or circular data encountered");
 1885    c = 0;
 1886    break;
 1887
 1888  case C_BAD_ARGUMENT_TYPE_NO_PORT_ERROR:
 1889    msg = C_text("bad argument type - not a port");
 1890    c = 1;
 1891    break;
 1892
 1893  case C_BAD_ARGUMENT_TYPE_PORT_DIRECTION_ERROR:
 1894    msg = C_text("bad argument type - not a port of the correct type");
 1895    c = 1;
 1896    break;
 1897
 1898  case C_BAD_ARGUMENT_TYPE_PORT_NO_INPUT_ERROR:
 1899    msg = C_text("bad argument type - not an input-port");
 1900    c = 1;
 1901    break;
 1902
 1903  case C_BAD_ARGUMENT_TYPE_PORT_NO_OUTPUT_ERROR:
 1904    msg = C_text("bad argument type - not an output-port");
 1905    c = 1;
 1906    break;
 1907
 1908  case C_PORT_CLOSED_ERROR:
 1909    msg = C_text("port already closed");
 1910    c = 1;
 1911    break;
 1912
 1913  case C_ASCIIZ_REPRESENTATION_ERROR:
 1914    msg = C_text("cannot represent string with NUL bytes as C string");
 1915    c = 1;
 1916    break;
 1917
 1918  case C_MEMORY_VIOLATION_ERROR:
 1919    msg = C_text("segmentation violation");
 1920    c = 0;
 1921    break;
 1922
 1923  case C_FLOATING_POINT_EXCEPTION_ERROR:
 1924    msg = C_text("floating point exception");
 1925    c = 0;
 1926    break;
 1927
 1928  case C_ILLEGAL_INSTRUCTION_ERROR:
 1929    msg = C_text("illegal instruction");
 1930    c = 0;
 1931    break;
 1932
 1933  case C_BUS_ERROR:
 1934    msg = C_text("bus error");
 1935    c = 0;
 1936    break;
 1937
 1938  case C_BAD_ARGUMENT_TYPE_NO_EXACT_ERROR:
 1939    msg = C_text("bad argument type - not an exact number");
 1940    c = 1;
 1941    break;
 1942
 1943  case C_BAD_ARGUMENT_TYPE_NO_INEXACT_ERROR:
 1944    msg = C_text("bad argument type - not an inexact number");
 1945    c = 1;
 1946    break;
 1947
 1948  case C_BAD_ARGUMENT_TYPE_NO_REAL_ERROR:
 1949    msg = C_text("bad argument type - not an real");
 1950    c = 1;
 1951    break;
 1952
 1953  case C_BAD_ARGUMENT_TYPE_COMPLEX_NO_ORDERING_ERROR:
 1954    msg = C_text("bad argument type - complex number has no ordering");
 1955    c = 1;
 1956    break;
 1957
 1958  case C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR:
 1959    msg = C_text("bad argument type - not an exact integer");
 1960    c = 1;
 1961    break;
 1962
 1963  case C_BAD_ARGUMENT_TYPE_FOREIGN_LIMITATION:
 1964    msg = C_text("number does not fit in foreign type");
 1965    c = 1;
 1966    break;
 1967
 1968  case C_BAD_ARGUMENT_TYPE_COMPLEX_ABS:
 1969    msg = C_text("cannot compute absolute value of complex number");
 1970    c = 1;
 1971    break;
 1972
 1973  case C_REST_ARG_OUT_OF_BOUNDS_ERROR:
 1974    msg = C_text("attempted rest argument access beyond end of list");
 1975    c = 3;
 1976    break;
 1977
 1978  case C_DECODING_ERROR:
 1979    msg = C_text("string contains invalid UTF-8 sequence");
 1980    c = 2;
 1981    break;
 1982
 1983  case C_BAD_ARGUMENT_TYPE_NUMERIC_RANGE_ERROR:
 1984    msg = C_text("bad argument type - value exceeds numeric range");
 1985    c = 1;
 1986    break;
 1987
 1988  default: panic(C_text("illegal internal error code"));
 1989  }
 1990
 1991  if(C_immediatep(err)) {
 1992    C_dbg(C_text("error"), C_text("%s\n"), msg);
 1993    panic(C_text("`##sys#error-hook' is not defined - the `library' unit was probably not linked with this executable"));
 1994  } else {
 1995    av = C_alloc(c + 4);
 1996    va_start(v, loc);
 1997    av[ 0 ] = err;
 1998    /* No continuation is passed: '##sys#error-hook' may not return: */
 1999    av[ 1 ] = C_SCHEME_UNDEFINED;
 2000    av[ 2 ] = C_fix(code);
 2001
 2002    if(loc != NULL)
 2003      av[ 3 ] = intern0(loc);
 2004    else {
 2005      av[ 3 ] = error_location;
 2006      error_location = C_SCHEME_FALSE;
 2007    }
 2008
 2009    for(i = 0; i < c; ++i)
 2010      av[ i + 4 ] = va_arg(v, C_word);
 2011
 2012    va_end(v);
 2013    C_do_apply(c + 4, av);
 2014  }
 2015}
 2016
 2017
 2018/* Never use extended number hook procedure names longer than this! */
 2019/* Current longest name: ##sys#integer->string/recursive */
 2020#define MAX_EXTNUM_HOOK_NAME 32
 2021
 2022/* This exists so that we don't have to create any extra closures */
 2023static void try_extended_number(char *ext_proc_name, C_word c, C_word k, ...)
 2024{
 2025  static C_word ab[C_SIZEOF_STRING(MAX_EXTNUM_HOOK_NAME)];
 2026  int i;
 2027  va_list v;
 2028  C_word ext_proc_sym, ext_proc = C_SCHEME_FALSE, *a = ab;
 2029
 2030  ext_proc_sym = C_lookup_symbol(C_intern2(&a, ext_proc_name));
 2031
 2032  if(!C_immediatep(ext_proc_sym))
 2033    ext_proc = C_block_item(ext_proc_sym, 0);
 2034
 2035  if (!C_immediatep(ext_proc) && C_closurep(ext_proc)) {
 2036    C_word *av = C_alloc(c + 1);
 2037    av[ 0 ] = ext_proc;
 2038    av[ 1 ] = k;
 2039    va_start(v, k);
 2040
 2041    for(i = 0; i < c - 1; ++i)
 2042      av[ i + 2 ] = va_arg(v, C_word);
 2043
 2044    va_end(v);
 2045    C_do_apply(c + 1, av);
 2046  } else {
 2047    barf(C_UNBOUND_VARIABLE_ERROR, NULL, ext_proc_sym);
 2048  }
 2049}
 2050
 2051
 2052/* Hook for setting breakpoints */
 2053
 2054C_word C_dbg_hook(C_word dummy)
 2055{
 2056  return dummy;
 2057}
 2058
 2059
 2060/* Timing routines: */
 2061
 2062/* DEPRECATED */
 2063C_regparm C_u64 C_milliseconds(void)
 2064{
 2065  return C_current_process_milliseconds();
 2066}
 2067
 2068C_regparm C_u64 C_current_process_milliseconds(void)
 2069{
 2070#if defined(__MINGW32__)
 2071# if defined(__MINGW64_VERSION_MAJOR)
 2072    ULONGLONG tick_count = GetTickCount64();
 2073# else
 2074    ULONGLONG tick_count = GetTickCount();
 2075# endif
 2076    return tick_count - (C_startup_time_sec * 1000) - C_startup_time_msec;
 2077#else
 2078    struct timeval tv;
 2079
 2080    if(C_gettimeofday(&tv, NULL) == -1) return 0;
 2081    else return (tv.tv_sec - C_startup_time_sec) * 1000 + tv.tv_usec / 1000 - C_startup_time_msec;
 2082#endif
 2083}
 2084
 2085
 2086C_regparm time_t C_seconds(C_long *ms)
 2087{
 2088#ifdef C_NONUNIX
 2089  if(ms != NULL) *ms = 0;
 2090
 2091  return (time_t)(clock() / CLOCKS_PER_SEC);
 2092#else
 2093  struct timeval tv;
 2094
 2095  if(C_gettimeofday(&tv, NULL) == -1) {
 2096    if(ms != NULL) *ms = 0;
 2097
 2098    return (time_t)0;
 2099  }
 2100  else {
 2101    if(ms != NULL) *ms = tv.tv_usec / 1000;
 2102
 2103    return tv.tv_sec;
 2104  }
 2105#endif
 2106}
 2107
 2108
 2109C_regparm C_u64 C_cpu_milliseconds(void)
 2110{
 2111#if defined(C_NONUNIX) || defined(__CYGWIN__)
 2112    if(CLOCKS_PER_SEC == 1000) return clock();
 2113    else return ((C_u64)clock() / CLOCKS_PER_SEC) * 1000;
 2114#else
 2115    struct rusage ru;
 2116
 2117    if(C_getrusage(RUSAGE_SELF, &ru) == -1) return 0;
 2118    else return (((C_u64)ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) * 1000
 2119                 + ((C_u64)ru.ru_utime.tv_usec + ru.ru_stime.tv_usec) / 1000);
 2120#endif
 2121}
 2122
 2123
 2124/* Support code for callbacks: */
 2125
 2126int C_save_callback_continuation(C_word **ptr, C_word k)
 2127{
 2128  C_word p = C_a_pair(ptr, k, C_block_item(callback_continuation_stack_symbol, 0));
 2129
 2130  C_mutate_slot(&C_block_item(callback_continuation_stack_symbol, 0), p);
 2131  return ++callback_continuation_level;
 2132}
 2133
 2134
 2135C_word C_restore_callback_continuation(void)
 2136{
 2137  /* obsolete, but retained for keeping old code working */
 2138  C_word p = C_block_item(callback_continuation_stack_symbol, 0),
 2139         k;
 2140
 2141  assert(!C_immediatep(p) && C_header_type(p) == C_PAIR_TYPE);
 2142  k = C_u_i_car(p);
 2143
 2144  C_mutate(&C_block_item(callback_continuation_stack_symbol, 0), C_u_i_cdr(p));
 2145  --callback_continuation_level;
 2146  return k;
 2147}
 2148
 2149
 2150C_word C_restore_callback_continuation2(int level)
 2151{
 2152  C_word p = C_block_item(callback_continuation_stack_symbol, 0),
 2153         k;
 2154
 2155  if(level != callback_continuation_level || C_immediatep(p) || C_header_type(p) != C_PAIR_TYPE)
 2156    panic(C_text("unbalanced callback continuation stack"));
 2157
 2158  k = C_u_i_car(p);
 2159
 2160  C_mutate(&C_block_item(callback_continuation_stack_symbol, 0), C_u_i_cdr(p));
 2161  --callback_continuation_level;
 2162  return k;
 2163}
 2164
 2165
 2166C_word C_callback(C_word closure, int argc)
 2167{
 2168#ifdef HAVE_SIGSETJMP
 2169  sigjmp_buf prev;
 2170#else
 2171  jmp_buf prev;
 2172#endif
 2173  C_word
 2174    *a = C_alloc(C_SIZEOF_CLOSURE(2)),
 2175    k = C_closure(&a, 2, (C_word)callback_return_continuation, C_SCHEME_FALSE),
 2176    *av;
 2177  int old = chicken_is_running;
 2178
 2179  if(old && C_block_item(callback_continuation_stack_symbol, 0) == C_SCHEME_END_OF_LIST)
 2180    panic(C_text("callback invoked in non-safe context"));
 2181
 2182  C_memcpy(&prev, &C_restart, sizeof(C_restart));
 2183  callback_returned_flag = 0;
 2184  chicken_is_running = 1;
 2185  av = C_alloc(argc + 2);
 2186  av[ 0 ] = closure;
 2187  av[ 1 ] = k;
 2188  /*XXX is the order of arguments an issue? */
 2189  C_memcpy(av + 2, C_temporary_stack, argc * sizeof(C_word));
 2190  C_temporary_stack = C_temporary_stack_bottom;
 2191
 2192#ifdef HAVE_SIGSETJMP
 2193  if(!C_sigsetjmp(C_restart, 0)) C_do_apply(argc + 2, av);
 2194#else
 2195  if(!C_setjmp(C_restart)) C_do_apply(argc + 2, av);
 2196#endif
 2197
 2198  serious_signal_occurred = 0;
 2199
 2200  if(!callback_returned_flag) {
 2201    /* We must copy the argvector onto the stack, because
 2202     * any subsequent save() will otherwise clobber it.
 2203     */
 2204    C_word *p = C_alloc(C_restart_c);
 2205    assert(C_restart_c == (C_temporary_stack_bottom - C_temporary_stack));
 2206    C_memcpy(p, C_temporary_stack, C_restart_c * sizeof(C_word));
 2207    C_temporary_stack = C_temporary_stack_bottom;
 2208    ((C_proc)C_restart_trampoline)(C_restart_c, p);
 2209  }
 2210  else {
 2211    C_memcpy(&C_restart, &prev, sizeof(C_restart));
 2212    callback_returned_flag = 0;
 2213  }
 2214
 2215  chicken_is_running = old;
 2216  return C_restore;
 2217}
 2218
 2219
 2220void C_callback_adjust_stack(C_word *a, int size)
 2221{
 2222  if(!chicken_is_running && !C_in_stackp((C_word)a)) {
 2223    if(debug_mode)
 2224      C_dbg(C_text("debug"),
 2225	    C_text("callback invoked in lower stack region - adjusting limits:\n"
 2226		   "[debug]   current:  \t%p\n"
 2227		   "[debug]   previous: \t%p (bottom) - %p (limit)\n"),
 2228	    a, stack_bottom, C_stack_limit);
 2229
 2230#if C_STACK_GROWS_DOWNWARD
 2231    C_stack_hard_limit = (C_word *)((C_byte *)a - stack_size);
 2232    stack_bottom = a + size;
 2233#else
 2234    C_stack_hard_limit = (C_word *)((C_byte *)a + stack_size);
 2235    stack_bottom = a;
 2236#endif
 2237    C_stack_limit = C_stack_hard_limit;
 2238
 2239    if(debug_mode)
 2240      C_dbg(C_text("debug"), C_text("new:      \t%p (bottom) - %p (limit)\n"),
 2241	    stack_bottom, C_stack_limit);
 2242  }
 2243}
 2244
 2245
 2246C_word C_callback_wrapper(void *proc, int argc)
 2247{
 2248  C_word
 2249    *a = C_alloc(C_SIZEOF_CLOSURE(1)),
 2250    closure = C_closure(&a, 1, (C_word)proc),
 2251    result;
 2252
 2253  result = C_callback(closure, argc);
 2254  assert(C_temporary_stack == C_temporary_stack_bottom);
 2255  return result;
 2256}
 2257
 2258
 2259void C_ccall callback_return_continuation(C_word c, C_word *av)
 2260{
 2261  C_word self = av[0];
 2262  C_word r = av[1];
 2263
 2264  if(C_block_item(self, 1) == C_SCHEME_TRUE)
 2265    panic(C_text("callback returned twice"));
 2266
 2267  assert(callback_returned_flag == 0);
 2268  callback_returned_flag = 1;
 2269  C_set_block_item(self, 1, C_SCHEME_TRUE);
 2270  C_save(r);
 2271  C_reclaim(NULL, 0);
 2272}
 2273
 2274
 2275/* Register/unregister literal frame: */
 2276
 2277void C_initialize_lf(C_word *lf, int count)
 2278{
 2279  while(count-- > 0)
 2280    *(lf++) = C_SCHEME_UNBOUND;
 2281}
 2282
 2283
 2284void *C_register_lf(C_word *lf, int count)
 2285{
 2286  return C_register_lf2(lf, count, NULL);
 2287}
 2288
 2289
 2290void *C_register_lf2(C_word *lf, int count, C_PTABLE_ENTRY *ptable)
 2291{
 2292  LF_LIST *node = (LF_LIST *)C_malloc(sizeof(LF_LIST));
 2293  LF_LIST *np;
 2294  int status = 0;
 2295
 2296  node->lf = lf;
 2297  node->count = count;
 2298  node->ptable = ptable;
 2299  node->module_name = current_module_name;
 2300  node->module_handle = current_module_handle;
 2301  current_module_handle = NULL;
 2302
 2303  if(lf_list) lf_list->prev = node;
 2304
 2305  node->next = lf_list;
 2306  node->prev = NULL;
 2307  lf_list = node;
 2308  return (void *)node;
 2309}
 2310
 2311
 2312LF_LIST *find_module_handle(char *name)
 2313{
 2314  LF_LIST *np;
 2315
 2316  for(np = lf_list; np != NULL; np = np->next) {
 2317    if(np->module_name != NULL && !C_strcmp(np->module_name, name))
 2318      return np;
 2319  }
 2320
 2321  return NULL;
 2322}
 2323
 2324
 2325void C_unregister_lf(void *handle)
 2326{
 2327  LF_LIST *node = (LF_LIST *) handle;
 2328
 2329  if (node->next) node->next->prev = node->prev;
 2330
 2331  if (node->prev) node->prev->next = node->next;
 2332
 2333  if (lf_list == node) lf_list = node->next;
 2334
 2335  C_free(node->module_name);
 2336  C_free(node);
 2337}
 2338
 2339
 2340/* Intern symbol into symbol-table: */
 2341
 2342C_regparm C_word C_intern(C_word **ptr, int len, C_char *str)
 2343{
 2344  return C_intern_in(ptr, len, str, symbol_table);
 2345}
 2346
 2347
 2348C_regparm C_word C_h_intern(C_word *slot, int len, C_char *str)
 2349{
 2350  return C_h_intern_in(slot, len, str, symbol_table);
 2351}
 2352
 2353
 2354C_regparm C_word C_intern_kw(C_word **ptr, int len, C_char *str)
 2355{
 2356  C_word kw = C_intern_in(ptr, len, str, keyword_table);
 2357  C_set_block_item(kw, 0, kw); /* Keywords evaluate to themselves */
 2358  C_set_block_item(kw, 2, C_SCHEME_FALSE); /* Keywords have no plists */
 2359  return kw;
 2360}
 2361
 2362
 2363C_regparm C_word C_h_intern_kw(C_word *slot, int len, C_char *str)
 2364{
 2365  C_word kw = C_h_intern_in(slot, len, str, keyword_table);
 2366  C_set_block_item(kw, 0, kw); /* Keywords evaluate to themselves */
 2367  C_set_block_item(kw, 2, C_SCHEME_FALSE); /* Keywords have no plists */
 2368  return kw;
 2369}
 2370
 2371C_regparm C_word C_intern_in(C_word **ptr, int len, C_char *str, C_SYMBOL_TABLE *stable)
 2372{
 2373  int key;
 2374  C_word s;
 2375
 2376  if(stable == NULL) stable = symbol_table;
 2377
 2378  key = hash_string(len, str, stable->size, stable->rand);
 2379
 2380  if(C_truep(s = lookup(key, len, str, stable))) return s;
 2381
 2382  s = C_bytevector(ptr, len + 1, str);
 2383  return add_symbol(ptr, key, s, stable);
 2384}
 2385
 2386
 2387C_regparm C_word C_h_intern_in(C_word *slot, int len, C_char *str, C_SYMBOL_TABLE *stable)
 2388{
 2389  /* Intern as usual, but remember slot, and allocate in static
 2390   * memory.  If symbol already exists, replace its string by a fresh
 2391   * statically allocated string to ensure it never gets collected, as
 2392   * lf[] entries are not tracked by the GC.
 2393   */
 2394  int key;
 2395  C_word s, bv;
 2396
 2397  if(stable == NULL) stable = symbol_table;
 2398
 2399  key = hash_string(len, str, stable->size, stable->rand);
 2400
 2401  if(C_truep(s = lookup(key, len, str, stable))) {
 2402    if(C_in_stackp(s)) C_mutate_slot(slot, s);
 2403
 2404    if(!C_truep(C_permanentp(C_symbol_name(s)))) {
 2405      /* Replace by statically allocated string, and persist it */
 2406      bv = C_static_bytevector(C_heaptop, len + 1, str);
 2407      C_c_bytevector(bv)[ len ] = 0;
 2408      C_set_block_item(s, 1, bv);
 2409      C_i_persist_symbol(s);
 2410    }
 2411    return s;
 2412  }
 2413
 2414  bv = C_static_bytevector(C_heaptop, len + 1, str);
 2415  C_c_bytevector(bv)[ len ] = 0;
 2416  return add_symbol(C_heaptop, key, bv, stable);
 2417}
 2418
 2419
 2420C_regparm C_word intern0(C_char *str)
 2421{
 2422  int len = C_strlen(str);
 2423  int key = hash_string(len, str, symbol_table->size, symbol_table->rand);
 2424  C_word s;
 2425
 2426  if(C_truep(s = lookup(key, len, str, symbol_table))) return s;
 2427  else return C_SCHEME_FALSE;
 2428}
 2429
 2430
 2431C_regparm C_word C_lookup_symbol(C_word sym)
 2432{
 2433  int key;
 2434  C_word bv = C_block_item(sym, 1);
 2435  int len = C_header_size(bv) - 1;
 2436
 2437  key = hash_string(len, C_c_string(bv), symbol_table->size, symbol_table->rand);
 2438
 2439  return lookup(key, len, C_c_string(bv), symbol_table);
 2440}
 2441
 2442
 2443C_regparm C_word C_intern2(C_word **ptr, C_char *str)
 2444{
 2445  return C_intern_in(ptr, C_strlen(str), str, symbol_table);
 2446}
 2447
 2448
 2449C_regparm C_word C_intern3(C_word **ptr, C_char *str, C_word value)
 2450{
 2451  C_word s = C_intern_in(ptr, C_strlen(str), str, symbol_table);
 2452
 2453  C_mutate(&C_block_item(s,0), value);
 2454  C_i_persist_symbol(s); /* Symbol has a value now; persist it */
 2455  return s;
 2456}
 2457
 2458
 2459C_regparm C_word hash_string(int len, C_char *str, C_word m, C_word r)
 2460{
 2461  C_uword key = r;
 2462
 2463  while(len--)
 2464      key ^= (key << 6) + (key >> 2) + *(str++);
 2465
 2466  return (C_word)(key % (C_uword)m);
 2467}
 2468
 2469
 2470C_regparm C_word lookup(C_word key, int len, C_char *str, C_SYMBOL_TABLE *stable)
 2471{
 2472  C_word bucket, last = 0, sym, s;
 2473
 2474  for(bucket = stable->table[ key ]; bucket != C_SCHEME_END_OF_LIST;
 2475      bucket = C_block_item(bucket,1)) {
 2476    sym = C_block_item(bucket,0);
 2477
 2478    /* If the symbol is unreferenced, drop it: */
 2479    if (sym == C_SCHEME_BROKEN_WEAK_PTR) {
 2480       if (last) C_set_block_item(last, 1, C_block_item(bucket, 1));
 2481       else stable->table[ key ] = C_block_item(bucket,1);
 2482    } else {
 2483      last = bucket;
 2484      s = C_block_item(sym, 1);
 2485
 2486      if(C_header_size(s) - 1 == (C_word)len
 2487         && !C_memcmp(str, (C_char *)C_data_pointer(s), len))
 2488        return sym;
 2489    }
 2490  }
 2491
 2492  return C_SCHEME_FALSE;
 2493}
 2494
 2495/* Mark a symbol as "persistent", to prevent it from being GC'ed */
 2496C_regparm C_word C_i_persist_symbol(C_word sym)
 2497{
 2498  C_word bucket;
 2499  C_SYMBOL_TABLE *stp;
 2500
 2501  /* Normally, this will get called with a symbol, but in
 2502   * C_h_intern_kw we may call it with keywords too.
 2503   */
 2504  if(!C_truep(C_i_symbolp(sym)) && !C_truep(C_i_keywordp(sym))) {
 2505    error_location = C_SCHEME_FALSE;
 2506    barf(C_BAD_ARGUMENT_TYPE_NO_SYMBOL_ERROR, NULL, sym);
 2507  }
 2508
 2509  for(stp = symbol_table_list; stp != NULL; stp = stp->next) {
 2510    bucket = lookup_bucket(sym, stp);
 2511
 2512    if (C_truep(bucket)) {
 2513      /* Change weak to strong ref to ensure long-term survival */
 2514      C_block_header(bucket) = C_block_header(bucket) & ~C_SPECIALBLOCK_BIT;
 2515      /* Ensure survival on next minor GC */
 2516      if (C_in_stackp(sym)) C_mutate_slot(&C_block_item(bucket, 0), sym);
 2517    }
 2518  }
 2519  return C_SCHEME_UNDEFINED;
 2520}
 2521
 2522/* Possibly remove "persistence" of symbol, to allowed it to be GC'ed.
 2523 * This is only done if the symbol is unbound, has an empty plist and
 2524 * is allocated in managed memory.
 2525 */
 2526C_regparm C_word C_i_unpersist_symbol(C_word sym)
 2527{
 2528  C_word bucket;
 2529  C_SYMBOL_TABLE *stp;
 2530
 2531  C_i_check_symbol(sym);
 2532
 2533  if (C_persistable_symbol(sym) ||
 2534      C_truep(C_permanentp(C_symbol_name(sym)))) {
 2535    return C_SCHEME_FALSE;
 2536  }
 2537
 2538  for(stp = symbol_table_list; stp != NULL; stp = stp->next) {
 2539    bucket = lookup_bucket(sym, NULL);
 2540
 2541    if (C_truep(bucket)) {
 2542      /* Turn it into a weak ref */
 2543      C_block_header(bucket) = C_block_header(bucket) | C_SPECIALBLOCK_BIT;
 2544      return C_SCHEME_TRUE;
 2545    }
 2546  }
 2547  return C_SCHEME_FALSE;
 2548}
 2549
 2550C_regparm C_word lookup_bucket(C_word sym, C_SYMBOL_TABLE *stable)
 2551{
 2552  C_word bucket, str = C_block_item(sym, 1);
 2553  int key, len = C_header_size(str) - 1;
 2554
 2555  if (stable == NULL) stable = symbol_table;
 2556
 2557  key = hash_string(len, C_c_string(str), stable->size, stable->rand);
 2558
 2559  for(bucket = stable->table[ key ]; bucket != C_SCHEME_END_OF_LIST;
 2560      bucket = C_block_item(bucket,1)) {
 2561    if (C_block_item(bucket,0) == sym) return bucket;
 2562  }
 2563  return C_SCHEME_FALSE;
 2564}
 2565
 2566
 2567double compute_symbol_table_load(double *avg_bucket_len, int *total_n)
 2568{
 2569  C_word bucket, last;
 2570  int i, j, alen = 0, bcount = 0, total = 0;
 2571
 2572  for(i = 0; i < symbol_table->size; ++i) {
 2573    last = 0;
 2574    j = 0;
 2575    for(bucket = symbol_table->table[ i ]; bucket != C_SCHEME_END_OF_LIST;
 2576        bucket = C_block_item(bucket,1)) {
 2577      /* If the symbol is unreferenced, drop it: */
 2578      if (C_block_item(bucket,0) == C_SCHEME_BROKEN_WEAK_PTR) {
 2579         if (last) C_set_block_item(last, 1, C_block_item(bucket, 1));
 2580         else symbol_table->table[ i ] = C_block_item(bucket,1);
 2581      } else {
 2582        last = bucket;
 2583        ++j;
 2584      }
 2585    }
 2586
 2587    if(j > 0) {
 2588      alen += j;
 2589      ++bcount;
 2590    }
 2591
 2592    total += j;
 2593  }
 2594
 2595  if(avg_bucket_len != NULL)
 2596    *avg_bucket_len = (double)alen / (double)bcount;
 2597
 2598  *total_n = total;
 2599
 2600  /* return load: */
 2601  return (double)total / (double)symbol_table->size;
 2602}
 2603
 2604
 2605C_word add_symbol(C_word **ptr, C_word key, C_word bv, C_SYMBOL_TABLE *stable)
 2606{
 2607  C_word bucket, sym, b2, *p;
 2608
 2609  p = *ptr;
 2610  sym = (C_word)p;
 2611  p += C_SIZEOF_SYMBOL;
 2612  C_block_header_init(sym, C_SYMBOL_TAG);
 2613  C_set_block_item(sym, 0, C_SCHEME_UNBOUND);
 2614  C_set_block_item(sym, 1, bv);
 2615  C_set_block_item(sym, 2, C_SCHEME_END_OF_LIST);
 2616  *ptr = p;
 2617  b2 = stable->table[ key ];	/* previous bucket */
 2618
 2619  /* Create new weak or strong bucket depending on persistability */
 2620  if (C_truep(C_permanentp(bv))) {
 2621    bucket = C_a_pair(ptr, sym, b2);
 2622  } else {
 2623    bucket = C_a_weak_pair(ptr, sym, b2);
 2624  }
 2625
 2626  if(ptr != C_heaptop) C_mutate_slot(&stable->table[ key ], bucket);
 2627  else {
 2628    /* If a stack-allocated bucket was here, and we allocate from
 2629       heap-top (say, in a toplevel literal frame allocation) then we have
 2630       to inform the memory manager that a 2nd gen. block points to a
 2631       1st gen. block, hence the mutation: */
 2632    C_mutate(&C_block_item(bucket,1), b2);
 2633    stable->table[ key ] = bucket;
 2634  }
 2635
 2636  return sym;
 2637}
 2638
 2639
 2640C_regparm int C_in_stackp(C_word x)
 2641{
 2642  C_word *ptr = (C_word *)(C_uword)x;
 2643
 2644#if C_STACK_GROWS_DOWNWARD
 2645  return ptr >= C_stack_pointer_test && ptr <= stack_bottom;
 2646#else
 2647  return ptr < C_stack_pointer_test && ptr >= stack_bottom;
 2648#endif
 2649}
 2650
 2651
 2652C_regparm int C_in_heapp(C_word x)
 2653{
 2654  C_byte *ptr = (C_byte *)(C_uword)x;
 2655  return (ptr >= fromspace_start && ptr < C_fromspace_limit) ||
 2656         (ptr >= tospace_start && ptr < tospace_limit);
 2657}
 2658
 2659/* Only used during major GC (heap realloc) */
 2660static C_regparm int C_in_new_heapp(C_word x)
 2661{
 2662  C_byte *ptr = (C_byte *)(C_uword)x;
 2663  return (ptr >= new_tospace_start && ptr < new_tospace_limit);
 2664}
 2665
 2666C_regparm int C_in_fromspacep(C_word x)
 2667{
 2668  C_byte *ptr = (C_byte *)(C_uword)x;
 2669  return (ptr >= fromspace_start && ptr < C_fromspace_limit);
 2670}
 2671
 2672C_regparm int C_in_scratchspacep(C_word x)
 2673{
 2674  C_word *ptr = (C_word *)(C_uword)x;
 2675  return (ptr >= C_scratchspace_start && ptr < C_scratchspace_limit);
 2676}
 2677
 2678/* Cons the rest-aguments together: */
 2679
 2680C_regparm C_word C_build_rest(C_word **ptr, C_word c, C_word n, C_word *av)
 2681{
 2682  C_word
 2683    x = C_SCHEME_END_OF_LIST,
 2684    *p = *ptr;
 2685  C_SCHEME_BLOCK *node;
 2686
 2687  av += c;
 2688
 2689  while(--c >= n) {
 2690    node = (C_SCHEME_BLOCK *)p;
 2691    p += 3;
 2692    node->header = C_PAIR_TYPE | (C_SIZEOF_PAIR - 1);
 2693    node->data[ 0 ] = *(--av);
 2694    node->data[ 1 ] = x;
 2695    x = (C_word)node;
 2696  }
 2697
 2698  *ptr = p;
 2699  return x;
 2700}
 2701
 2702
 2703/* Print error messages and exit: */
 2704
 2705void C_bad_memory(void)
 2706{
 2707  panic(C_text("there is not enough stack-space to run this executable"));
 2708}
 2709
 2710
 2711void C_bad_memory_2(void)
 2712{
 2713  panic(C_text("there is not enough heap-space to run this executable - try using the '-:h...' option"));
 2714}
 2715
 2716
 2717/* The following two can be thrown out in the next release... */
 2718
 2719void C_bad_argc(int c, int n)
 2720{
 2721  C_bad_argc_2(c, n, C_SCHEME_FALSE);
 2722}
 2723
 2724
 2725void C_bad_min_argc(int c, int n)
 2726{
 2727  C_bad_min_argc_2(c, n, C_SCHEME_FALSE);
 2728}
 2729
 2730
 2731void C_bad_argc_2(int c, int n, C_word closure)
 2732{
 2733  barf(C_BAD_ARGUMENT_COUNT_ERROR, NULL, C_fix(n - 2), C_fix(c - 2), closure);
 2734}
 2735
 2736
 2737void C_bad_min_argc_2(int c, int n, C_word closure)
 2738{
 2739  barf(C_BAD_MINIMUM_ARGUMENT_COUNT_ERROR, NULL, C_fix(n - 2), C_fix(c - 2), closure);
 2740}
 2741
 2742
 2743void C_stack_overflow(C_char *loc)
 2744{
 2745  barf(C_STACK_OVERFLOW_ERROR, loc);
 2746}
 2747
 2748
 2749void C_no_closure_error(C_word x)
 2750{
 2751  barf(C_NOT_A_CLOSURE_ERROR, NULL, x);
 2752}
 2753
 2754
 2755void C_div_by_zero_error(C_char *loc)
 2756{
 2757  barf(C_DIVISION_BY_ZERO_ERROR, loc);
 2758}
 2759
 2760void C_unimplemented(C_char *msg)
 2761{
 2762	C_fprintf(C_stderr, C_text("Error: unimplemented feature: %s\n"), msg);
 2763  	C_exit_runtime(C_fix(EX_SOFTWARE));
 2764}
 2765
 2766void C_not_an_integer_error(C_char *loc, C_word x)
 2767{
 2768  barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, loc, x);
 2769}
 2770
 2771void C_not_an_uinteger_error(C_char *loc, C_word x)
 2772{
 2773  barf(C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR, loc, x);
 2774}
 2775
 2776void C_rest_arg_out_of_bounds_error(C_word c, C_word n, C_word ka)
 2777{
 2778  C_rest_arg_out_of_bounds_error_2(c, n, ka, C_SCHEME_FALSE);
 2779}
 2780
 2781void C_rest_arg_out_of_bounds_error_2(C_word c, C_word n, C_word ka, C_word closure)
 2782{
 2783  barf(C_REST_ARG_OUT_OF_BOUNDS_ERROR, NULL, C_u_fixnum_difference(c, ka), C_u_fixnum_difference(n, ka), closure);
 2784}
 2785
 2786/* Allocate and initialize record: */
 2787
 2788C_regparm C_word C_string(C_word **ptr, int len, C_char *str)
 2789{
 2790  C_word buf = C_bytevector(ptr, len + 1, str);
 2791  C_word s = (C_word)(*ptr);
 2792  int n;
 2793  *ptr += 5; /* C_SIZEOF_STRING */
 2794  C_c_bytevector(buf)[ len ] = 0;
 2795  C_block_header_init(s, C_STRING_TAG);
 2796  C_set_block_item(s, 0, buf);
 2797  n = C_utf_count(str, len);
 2798  C_set_block_item(s, 1, C_fix(n));
 2799  C_set_block_item(s, 2, C_fix(0));
 2800  C_set_block_item(s, 3, C_fix(0));
 2801  return s;
 2802}
 2803
 2804C_regparm C_word C_static_string(C_word **ptr, int len, C_char *str)
 2805{
 2806  C_word buf = C_static_bytevector(ptr, len + 1, str);
 2807  C_word s = (C_word)(*ptr);
 2808  int n;
 2809  *ptr += 5; /* C_SIZEOF_STRING */
 2810  C_c_bytevector(buf)[ len ] = 0;
 2811  C_block_header_init(s, C_STRING_TAG);
 2812  C_set_block_item(s, 0, buf);
 2813  n = C_utf_count(str, len);
 2814  C_set_block_item(s, 1, C_fix(n));
 2815  C_set_block_item(s, 2, C_fix(0));
 2816  C_set_block_item(s, 3, C_fix(0));
 2817  return s;
 2818}
 2819
 2820C_regparm C_word C_static_bignum(C_word **ptr, int len, C_char *str)
 2821{
 2822  C_word *dptr, bignum, bigvec, retval, size, negp = 0;
 2823
 2824  if (*str == '+' || *str == '-') {
 2825    negp = ((*str++) == '-') ? 1 : 0;
 2826    --len;
 2827  }
 2828  size = C_BIGNUM_BITS_TO_DIGITS((unsigned int)len << 2);
 2829
 2830  dptr = (C_word *)C_malloc(C_wordstobytes(C_SIZEOF_INTERNAL_BIGNUM_VECTOR(size)));
 2831  if(dptr == NULL)
 2832    panic(C_text("out of memory - cannot allocate static bignum"));
 2833
 2834  bigvec = (C_word)dptr;
 2835  C_block_header_init(bigvec, C_BYTEVECTOR_TYPE | C_wordstobytes(size + 1));
 2836  C_set_block_item(bigvec, 0, negp);
 2837  /* This needs to be allocated at ptr, not dptr, because GC moves type tag */
 2838  bignum = C_a_i_bignum_wrapper(ptr, bigvec);
 2839
 2840  retval = str_to_bignum(bignum, str, str + len, 16);
 2841  if (retval & C_FIXNUM_BIT)
 2842    C_free(dptr); /* Might have been simplified */
 2843  return retval;
 2844}
 2845
 2846C_regparm C_word C_static_lambda_info(C_word **ptr, int len, C_char *str)
 2847{
 2848  int dlen = sizeof(C_header) + C_align(len);
 2849  void *dptr = C_malloc(dlen);
 2850  C_word strblock;
 2851
 2852  if(dptr == NULL)
 2853    panic(C_text("out of memory - cannot allocate static lambda info"));
 2854
 2855  strblock = (C_word)dptr;
 2856  C_block_header_init(strblock, C_LAMBDA_INFO_TYPE | len);
 2857  C_memcpy(C_data_pointer(strblock), str, len);
 2858  return strblock;
 2859}
 2860
 2861
 2862C_regparm C_word C_bytevector(C_word **ptr, int len, C_char *str)
 2863{
 2864  C_word block = (C_word)(*ptr);
 2865  *ptr = (C_word *)((C_word)(*ptr) + sizeof(C_header) + C_align(len));
 2866  C_block_header_init(block, C_BYTEVECTOR_TYPE | len);
 2867  C_memcpy(C_data_pointer(block), str, len);
 2868  return block;
 2869}
 2870
 2871
 2872C_regparm C_word C_static_bytevector(C_word **ptr, int len, C_char *str)
 2873{
 2874  /* we need to add 4 here, as utf8_decode does 3-byte lookahead */
 2875  C_word *dptr = (C_word *)C_malloc(sizeof(C_header) + C_align(len + 4));
 2876  C_word block;
 2877
 2878  if(dptr == NULL)
 2879    panic(C_text("out of memory - cannot allocate static bytevector"));
 2880
 2881  block = (C_word)dptr;
 2882  C_block_header_init(block, C_BYTEVECTOR_TYPE | len);
 2883  C_memcpy(C_data_pointer(block), str, len);
 2884  return block;
 2885}
 2886
 2887
 2888C_regparm C_word C_pbytevector(int len, C_char *str)
 2889{
 2890  C_SCHEME_BLOCK *pbv = C_malloc(len + sizeof(C_header));
 2891
 2892  if(pbv == NULL) panic(C_text("out of memory - cannot allocate permanent bytevector"));
 2893
 2894  pbv->header = C_BYTEVECTOR_TYPE | len;
 2895  C_memcpy(pbv->data, str, len);
 2896  return (C_word)pbv;
 2897}
 2898
 2899
 2900C_regparm C_word C_string2(C_word **ptr, C_char *str)
 2901{
 2902  C_word strblock = (C_word)(*ptr);
 2903  int len;
 2904
 2905  if(str == NULL) return C_SCHEME_FALSE;
 2906
 2907  len = C_strlen(str);
 2908  return C_string(ptr, len, str);
 2909}
 2910
 2911
 2912C_regparm C_word C_string2_safe(C_word **ptr, int max, C_char *str)
 2913{
 2914  C_word strblock = (C_word)(*ptr);
 2915  int len;
 2916
 2917  if(str == NULL) return C_SCHEME_FALSE;
 2918
 2919  len = C_strlen(str);
 2920
 2921  if(len >= max) {
 2922    C_snprintf(buffer, sizeof(buffer), C_text("foreign string result exceeded maximum of %d bytes"), max);
 2923    panic(buffer);
 2924  }
 2925
 2926  return C_string(ptr, len, str);
 2927}
 2928
 2929
 2930C_word C_closure(C_word **ptr, int cells, C_word proc, ...)
 2931{
 2932  va_list va;
 2933  C_word *p = *ptr,
 2934         *p0 = p;
 2935
 2936  *p = C_CLOSURE_TYPE | cells;
 2937  *(++p) = proc;
 2938
 2939  for(va_start(va, proc); --cells; *(++p) = va_arg(va, C_word));
 2940
 2941  va_end(va);
 2942  *ptr = p + 1;
 2943  return (C_word)p0;
 2944}
 2945
 2946
 2947/* obsolete: replaced by C_a_pair in chicken.h */
 2948C_regparm C_word C_pair(C_word **ptr, C_word car, C_word cdr)
 2949{
 2950  C_word *p = *ptr,
 2951         *p0 = p;
 2952
 2953  *(p++) = C_PAIR_TYPE | (C_SIZEOF_PAIR - 1);
 2954  *(p++) = car;
 2955  *(p++) = cdr;
 2956  *ptr = p;
 2957  return (C_word)p0;
 2958}
 2959
 2960
 2961C_regparm C_word C_number(C_word **ptr, double n)
 2962{
 2963  C_word
 2964    *p = *ptr,
 2965    *p0;
 2966  double m;
 2967
 2968  if(n <= (double)C_MOST_POSITIVE_FIXNUM
 2969     && n >= (double)C_MOST_NEGATIVE_FIXNUM && modf(n, &m) == 0.0) {
 2970    return C_fix(n);
 2971  }
 2972
 2973#ifndef C_SIXTY_FOUR
 2974#ifndef C_DOUBLE_IS_32_BITS
 2975  /* Align double on 8-byte boundary: */
 2976  if(C_aligned8(p)) ++p;
 2977#endif
 2978#endif
 2979
 2980  p0 = p;
 2981  *(p++) = C_FLONUM_TAG;
 2982  *((double *)p) = n;
 2983  *ptr = p + sizeof(double) / sizeof(C_word);
 2984  return (C_word)p0;
 2985}
 2986
 2987
 2988C_regparm C_word C_mpointer(C_word **ptr, void *mp)
 2989{
 2990  C_word
 2991    *p = *ptr,
 2992    *p0 = p;
 2993
 2994  *(p++) = C_POINTER_TYPE | 1;
 2995  *((void **)p) = mp;
 2996  *ptr = p + 1;
 2997  return (C_word)p0;
 2998}
 2999
 3000
 3001C_regparm C_word C_mpointer_or_false(C_word **ptr, void *mp)
 3002{
 3003  C_word
 3004    *p = *ptr,
 3005    *p0 = p;
 3006
 3007  if(mp == NULL) return C_SCHEME_FALSE;
 3008
 3009  *(p++) = C_POINTER_TYPE | 1;
 3010  *((void **)p) = mp;
 3011  *ptr = p + 1;
 3012  return (C_word)p0;
 3013}
 3014
 3015
 3016C_regparm C_word C_taggedmpointer(C_word **ptr, C_word tag, void *mp)
 3017{
 3018  C_word
 3019    *p = *ptr,
 3020    *p0 = p;
 3021
 3022  *(p++) = C_TAGGED_POINTER_TAG;
 3023  *((void **)p) = mp;
 3024  *(++p) = tag;
 3025  *ptr = p + 1;
 3026  return (C_word)p0;
 3027}
 3028
 3029
 3030C_regparm C_word C_taggedmpointer_or_false(C_word **ptr, C_word tag, void *mp)
 3031{
 3032  C_word
 3033    *p = *ptr,
 3034    *p0 = p;
 3035
 3036  if(mp == NULL) return C_SCHEME_FALSE;
 3037
 3038  *(p++) = C_TAGGED_POINTER_TAG;
 3039  *((void **)p) = mp;
 3040  *(++p) = tag;
 3041  *ptr = p + 1;
 3042  return (C_word)p0;
 3043}
 3044
 3045
 3046C_word C_vector(C_word **ptr, int n, ...)
 3047{
 3048  va_list v;
 3049  C_word
 3050    *p = *ptr,
 3051    *p0 = p;
 3052
 3053  *(p++) = C_VECTOR_TYPE | n;
 3054  va_start(v, n);
 3055
 3056  while(n--)
 3057    *(p++) = va_arg(v, C_word);
 3058
 3059  *ptr = p;
 3060  va_end(v);
 3061  return (C_word)p0;
 3062}
 3063
 3064
 3065C_word C_structure(C_word **ptr, int n, ...)
 3066{
 3067  va_list v;
 3068  C_word *p = *ptr,
 3069         *p0 = p;
 3070
 3071  *(p++) = C_STRUCTURE_TYPE | n;
 3072  va_start(v, n);
 3073
 3074  while(n--)
 3075    *(p++) = va_arg(v, C_word);
 3076
 3077  *ptr = p;
 3078  va_end(v);
 3079  return (C_word)p0;
 3080}
 3081
 3082
 3083C_regparm C_word
 3084C_mutate_slot(C_word *slot, C_word val)
 3085{
 3086  unsigned int mssize, newmssize, bytes;
 3087
 3088  ++mutation_count;
 3089  /* Mutation stack exists to track mutations pointing from elsewhere
 3090   * into nursery.  Stuff pointing anywhere else can be skipped, as
 3091   * well as mutations on nursery objects.
 3092   */
 3093  if(C_in_stackp((C_word)slot) || (!C_in_stackp(val) && !C_in_scratchspacep(val)))
 3094    return *slot = val;
 3095
 3096#ifdef C_GC_HOOKS
 3097  if(C_gc_mutation_hook != NULL && C_gc_mutation_hook(slot, val)) return val;
 3098#endif
 3099
 3100  if(mutation_stack_top >= mutation_stack_limit) {
 3101    assert(mutation_stack_top == mutation_stack_limit);
 3102    mssize = mutation_stack_top - mutation_stack_bottom;
 3103    newmssize = mssize * 2;
 3104    bytes = newmssize * sizeof(C_word *);
 3105
 3106    if(debug_mode)
 3107      C_dbg(C_text("debug"), C_text("resizing mutation stack from %uk to %uk ...\n"),
 3108	    (mssize * sizeof(C_word *)) / 1024, bytes / 1024);
 3109
 3110    mutation_stack_bottom = (C_word **)realloc(mutation_stack_bottom, bytes);
 3111
 3112    if(mutation_stack_bottom == NULL)
 3113      panic(C_text("out of memory - cannot re-allocate mutation stack"));
 3114
 3115    mutation_stack_limit = mutation_stack_bottom + newmssize;
 3116    mutation_stack_top = mutation_stack_bottom + mssize;
 3117  }
 3118
 3119  *(mutation_stack_top++) = slot;
 3120  ++tracked_mutation_count;
 3121  return *slot = val;
 3122}
 3123
 3124/* Allocate memory in scratch space, "size" is in words, like C_alloc.
 3125 * The memory in the scratch space is laid out as follows: First,
 3126 * there's a count that indicates how big the object originally was,
 3127 * followed by a pointer to the slot in the object which points to the
 3128 * object in scratch space, finally followed by the object itself.
 3129 * The reason we store the slot pointer is so that we can figure out
 3130 * whether the object is still "live" when reallocating; that's
 3131 * because we don't have a saved continuation from where we can trace
 3132 * the live data.  The reason we store the total length of the object
 3133 * is because we may be mutating in-place the lengths of the stored
 3134 * objects, and we need to know how much to skip over while scanning.
 3135 *
 3136 * If the allocating function returns, it *must* first mark all the
 3137 * values in scratch space as reclaimable.  This is needed because
 3138 * there is no way to distinguish between a stale pointer into scratch
 3139 * space that's still somewhere on the stack in "uninitialized" memory
 3140 * versus a word that's been recycled by the next called function,
 3141 * which now holds a value that happens to have the same bit pattern
 3142 * but represents another thing entirely.
 3143 */
 3144C_regparm C_word C_scratch_alloc(C_uword size)
 3145{
 3146  C_word result;
 3147
 3148  if (C_scratchspace_top + size + 2 >= C_scratchspace_limit) {
 3149    C_word *new_scratch_start, *new_scratch_top, *new_scratch_limit;
 3150    C_uword needed = C_scratch_usage + size + 2,
 3151            new_size = nmax(scratchspace_size << 1, 2UL << C_ilen(needed));
 3152
 3153    /* Shrink if the needed size is much smaller, but not below minimum */
 3154    if (needed < (new_size >> 4)) new_size >>= 1;
 3155    new_size = nmax(new_size, DEFAULT_SCRATCH_SPACE_SIZE);
 3156
 3157    /* TODO: Maybe we should work with two semispaces to reduce mallocs? */
 3158    new_scratch_start = (C_word *)C_malloc(C_wordstobytes(new_size));
 3159    if (new_scratch_start == NULL)
 3160      panic(C_text("out of memory - cannot (re-)allocate scratch space"));
 3161    new_scratch_top = new_scratch_start;
 3162    new_scratch_limit = new_scratch_start + new_size;
 3163
 3164    if(debug_mode) {
 3165      C_dbg(C_text("debug"), C_text("resizing scratchspace dynamically from "
 3166				    UWORD_COUNT_FORMAT_STRING "k to "
 3167				    UWORD_COUNT_FORMAT_STRING "k ...\n"),
 3168	    C_wordstobytes(scratchspace_size) / 1024,
 3169            C_wordstobytes(new_size) / 1024);
 3170    }
 3171
 3172    if(gc_report_flag) {
 3173      C_dbg(C_text("GC"), C_text("(old) scratchspace: \tstart=" UWORD_FORMAT_STRING
 3174				 ", \tlimit=" UWORD_FORMAT_STRING "\n"),
 3175            (C_word)C_scratchspace_start, (C_word)C_scratchspace_limit);
 3176      C_dbg(C_text("GC"), C_text("(new) scratchspace:   \tstart=" UWORD_FORMAT_STRING
 3177                                 ", \tlimit=" UWORD_FORMAT_STRING "\n"),
 3178            (C_word)new_scratch_start, (C_word)new_scratch_limit);
 3179    }
 3180
 3181    /* Move scratch data into new space and mutate slots pointing there.
 3182     * This is basically a much-simplified version of really_mark.
 3183     */
 3184    if (C_scratchspace_start != NULL) {
 3185      C_word val, *sscan, *slot;
 3186      C_uword n, words;
 3187      C_header h;
 3188      C_SCHEME_BLOCK *p, *p2;
 3189
 3190      sscan = C_scratchspace_start;
 3191
 3192      while (sscan < C_scratchspace_top) {
 3193        words = *sscan;
 3194        slot = (C_word *)*(sscan+1);
 3195
 3196        if (*(sscan+2) == ALIGNMENT_HOLE_MARKER) val = (C_word)(sscan+3);
 3197        else val = (C_word)(sscan+2);
 3198
 3199        sscan += words + 2;
 3200
 3201        p = (C_SCHEME_BLOCK *)val;
 3202        h = p->header;
 3203        if (is_fptr(h)) /* TODO: Support scratch->scratch pointers? */
 3204          panic(C_text("Unexpected forwarding pointer in scratch space"));
 3205
 3206        p2 = (C_SCHEME_BLOCK *)(new_scratch_top+2);
 3207
 3208#ifndef C_SIXTY_FOUR
 3209        if ((h & C_8ALIGN_BIT) && C_aligned8(p2) &&
 3210            (C_word *)p2 < new_scratch_limit) {
 3211          *((C_word *)p2) = ALIGNMENT_HOLE_MARKER;
 3212          p2 = (C_SCHEME_BLOCK *)((C_word *)p2 + 1);
 3213        }
 3214#endif
 3215
 3216        /* If orig slot still points here, copy data and update it */
 3217        if (slot != NULL) {
 3218          assert(*slot == val);
 3219          n = C_header_size(p);
 3220          n = (h & C_BYTEBLOCK_BIT) ? C_bytestowords(n) : n;
 3221
 3222          *slot = (C_word)p2;
 3223          /* size = header plus block size plus optional alignment hole */
 3224          *new_scratch_top = ((C_word *)p2-(C_word *)new_scratch_top-2) + n + 1;
 3225          *(new_scratch_top+1) = (C_word)slot;
 3226
 3227          new_scratch_top = (C_word *)p2 + n + 1;
 3228          if(new_scratch_top > new_scratch_limit)
 3229            panic(C_text("out of memory - scratch space full while resizing"));
 3230
 3231          p2->header = h;
 3232          p->header = ptr_to_fptr((C_uword)p2);
 3233          C_memcpy(p2->data, p->data, C_wordstobytes(n));
 3234        }
 3235      }
 3236      free(C_scratchspace_start);
 3237    }
 3238    C_scratchspace_start = new_scratch_start;
 3239    C_scratchspace_top = new_scratch_top;
 3240    C_scratchspace_limit = new_scratch_limit;
 3241    /* Scratch space is now tightly packed */
 3242    C_scratch_usage = (new_scratch_top - new_scratch_start);
 3243    scratchspace_size = new_size;
 3244  }
 3245  assert(C_scratchspace_top + size + 2 <= C_scratchspace_limit);
 3246
 3247  *C_scratchspace_top = size;
 3248  *(C_scratchspace_top+1) = (C_word)NULL; /* Nothing points here 'til mutated */
 3249  result = (C_word)(C_scratchspace_top+2);
 3250  C_scratchspace_top += size + 2;
 3251  /* This will only be marked as "used" when it's claimed by a pointer */
 3252  /* C_scratch_usage += size + 2; */
 3253  return result;
 3254}
 3255
 3256/* Given a root object, scan its slots recursively (the objects
 3257 * themselves should be shallow and non-recursive), and migrate every
 3258 * object stored between the memory boundaries to the supplied
 3259 * pointer.  Scratch data pointed to by objects between the memory
 3260 * boundaries is updated to point to the new memory region.  If the
 3261 * supplied pointer is NULL, the scratch memory is marked reclaimable.
 3262 */
 3263C_regparm C_word
 3264C_migrate_buffer_object(C_word **ptr, C_word *start, C_word *end, C_word obj)
 3265{
 3266  C_word size, header, *data, *p = NULL, obj_in_buffer;
 3267
 3268  if (C_immediatep(obj)) return obj;
 3269
 3270  size = C_header_size(obj);
 3271  header = C_block_header(obj);
 3272  data = C_data_pointer(obj);
 3273  obj_in_buffer = (obj >= (C_word)start && obj < (C_word)end);
 3274
 3275  /* Only copy object if we have a target pointer and it's in the buffer */
 3276  if (ptr != NULL && obj_in_buffer) {
 3277    p = *ptr;
 3278    obj = (C_word)p; /* Return the object's new location at the end */
 3279  }
 3280
 3281  if (p != NULL) *p++ = header;
 3282
 3283  if (header & C_BYTEBLOCK_BIT) {
 3284    if (p != NULL) {
 3285      *ptr = (C_word *)((C_byte *)(*ptr) + sizeof(C_header) + C_align(size));
 3286      C_memcpy(p, data, size);
 3287    }
 3288  } else {
 3289    if (p != NULL) *ptr += size + 1;
 3290
 3291    if(header & C_SPECIALBLOCK_BIT) {
 3292      if (p != NULL) *(p++) = *data;
 3293      size--;
 3294      data++;
 3295    }
 3296
 3297    /* TODO: See if we can somehow make this use Cheney's algorithm */
 3298    while(size--) {
 3299      C_word slot = *data;
 3300
 3301      if(!C_immediatep(slot)) {
 3302        if (C_in_scratchspacep(slot)) {
 3303          if (obj_in_buffer) { /* Otherwise, don't touch scratch backpointer */
 3304            /* TODO: Support recursing into objects in scratch space? */
 3305            C_word *sp = (C_word *)slot;
 3306
 3307            if (*(sp-1) == ALIGNMENT_HOLE_MARKER) --sp;
 3308            if (*(sp-1) != (C_word)NULL && p == NULL)
 3309              C_scratch_usage -= *(sp-2) + 2;
 3310            *(sp-1) = (C_word)p; /* This is why we traverse even if p = NULL */
 3311
 3312            *data = C_SCHEME_UNBOUND; /* Ensure old reference is killed dead */
 3313          }
 3314        } else { /* Slot is not a scratchspace object: check sub-objects */
 3315          slot = C_migrate_buffer_object(ptr, start, end, slot);
 3316        }
 3317      }
 3318      if (p != NULL) *(p++) = slot;
 3319      else *data = slot; /* Sub-object may have moved! */
 3320      data++;
 3321    }
 3322  }
 3323  return obj; /* Should be NULL if ptr was NULL */
 3324}
 3325
 3326/* Register an object's slot as holding data to scratch space.  Only
 3327 * one slot can point to a scratch space object; the object in scratch
 3328 * space is preceded by a pointer that points to this slot (or NULL).
 3329 */
 3330C_regparm C_word C_mutate_scratch_slot(C_word *slot, C_word val)
 3331{
 3332  C_word *ptr = (C_word *)val;
 3333  assert(C_in_scratchspacep(val));
 3334/* XXX  assert(slot == NULL || C_in_stackp((C_word)slot));
 3335*/
 3336  if (*(ptr-1) == ALIGNMENT_HOLE_MARKER) --ptr;
 3337  if (*(ptr-1) == (C_word)NULL && slot != NULL)
 3338    C_scratch_usage += *(ptr-2) + 2;
 3339  if (*(ptr-1) != (C_word)NULL && slot == NULL)
 3340    C_scratch_usage -= *(ptr-2) + 2;
 3341  *(ptr-1) = (C_word)slot; /* Remember the slot pointing here, for realloc */
 3342  if (slot != NULL) *slot = val;
 3343  return val;
 3344}
 3345
 3346/* Initiate garbage collection: */
 3347
 3348
 3349void C_save_and_reclaim(void *trampoline, int n, C_word *av)
 3350{
 3351  C_word new_size = nmax((C_word)1 << C_ilen(n), DEFAULT_TEMPORARY_STACK_SIZE);
 3352
 3353  assert(av > C_temporary_stack_bottom || av < C_temporary_stack_limit);
 3354  assert(C_temporary_stack == C_temporary_stack_bottom);
 3355
 3356  /* Don't *immediately* slam back to default size */
 3357  if (new_size < temporary_stack_size / 4)
 3358    new_size = temporary_stack_size >> 1;
 3359
 3360  if (new_size != temporary_stack_size) {
 3361
 3362    if(fixed_temporary_stack_size)
 3363      panic(C_text("fixed temporary stack overflow (\"apply\" called with too many arguments?)"));
 3364
 3365    if(gc_report_flag) {
 3366      C_dbg(C_text("GC"), C_text("resizing temporary stack dynamically from " UWORD_COUNT_FORMAT_STRING "k to " UWORD_COUNT_FORMAT_STRING "k ...\n"),
 3367            C_wordstobytes(temporary_stack_size) / 1024,
 3368            C_wordstobytes(new_size) / 1024);
 3369    }
 3370
 3371    C_free(C_temporary_stack_limit);
 3372
 3373    if((C_temporary_stack_limit = (C_word *)C_malloc(new_size * sizeof(C_word))) == NULL)
 3374      panic(C_text("out of memory - could not resize temporary stack"));
 3375
 3376    C_temporary_stack_bottom = C_temporary_stack_limit + new_size;
 3377    C_temporary_stack = C_temporary_stack_bottom;
 3378    temporary_stack_size = new_size;
 3379  }
 3380
 3381  C_temporary_stack = C_temporary_stack_bottom - n;
 3382
 3383  assert(C_temporary_stack >= C_temporary_stack_limit);
 3384
 3385  C_memmove(C_temporary_stack, av, n * sizeof(C_word));
 3386  C_reclaim(trampoline, n);
 3387}
 3388
 3389
 3390void C_save_and_reclaim_args(void *trampoline, int n, ...)
 3391{
 3392  va_list v;
 3393  int i;
 3394
 3395  va_start(v, n);
 3396
 3397  for(i = 0; i < n; ++i)
 3398    C_save(va_arg(v, C_word));
 3399
 3400  va_end(v);
 3401  C_reclaim(trampoline, n);
 3402}
 3403
 3404
 3405#ifdef __SUNPRO_C
 3406static void _mark(C_word *x, C_byte *s, C_byte **t, C_byte *l) {   \
 3407  C_word *_x = (x), _val = *_x;                                   \
 3408  if(!C_immediatep(_val)) really_mark(_x,s,t,l);                  \
 3409}
 3410#else
 3411# define _mark(x,s,t,l)                                  \
 3412  C_cblock						\
 3413  C_word *_x = (x), _val = *_x;				\
 3414  if(!C_immediatep(_val)) really_mark(_x,s,t,l);	\
 3415  C_cblockend
 3416#endif
 3417
 3418/* NOTE: This macro is particularly unhygienic! */
 3419#define mark(x) _mark(x, tgt_space_start, tgt_space_top, tgt_space_limit)
 3420
 3421C_regparm void C_reclaim(void *trampoline, C_word c)
 3422{
 3423  int i, j, fcount;
 3424  C_uword count;
 3425  C_word **msp, last;
 3426  C_byte *tmp, *start;
 3427  C_GC_ROOT *gcrp;
 3428  double tgc = 0;
 3429  volatile int finalizers_checked;
 3430  FINALIZER_NODE *flist;
 3431  C_DEBUG_INFO cell;
 3432  C_byte *tgt_space_start, **tgt_space_top, *tgt_space_limit;
 3433
 3434  /* assert(C_timer_interrupt_counter >= 0); */
 3435
 3436  if(pending_interrupts_count > 0 && C_interrupts_enabled) {
 3437    stack_check_demand = 0; /* forget demand: we're not going to gc yet */
 3438    handle_interrupt(trampoline);
 3439  }
 3440
 3441  cell.enabled = 0;
 3442  cell.event = C_DEBUG_GC;
 3443  cell.loc = "<runtime>";
 3444  cell.val = "GC_MINOR";
 3445  C_debugger(&cell, 0, NULL);
 3446
 3447  /* Note: the mode argument will always be GC_MINOR or GC_REALLOC. */
 3448  if(C_pre_gc_hook != NULL) C_pre_gc_hook(GC_MINOR);
 3449
 3450  finalizers_checked = 0;
 3451  C_restart_trampoline = trampoline;
 3452  C_restart_c = c;
 3453  gc_mode = GC_MINOR;
 3454  tgt_space_start = fromspace_start;
 3455  tgt_space_top = &C_fromspace_top;
 3456  tgt_space_limit = C_fromspace_limit;
 3457  weak_pair_chain = (C_word)NULL;
 3458  locative_chain = (C_word)NULL;
 3459
 3460  start = C_fromspace_top;
 3461
 3462  /* Entry point for second-level GC (on explicit request or because of full fromspace): */
 3463#ifdef HAVE_SIGSETJMP
 3464  if(C_sigsetjmp(gc_restart, 0) || start >= C_fromspace_limit) {
 3465#else
 3466  if(C_setjmp(gc_restart) || start >= C_fromspace_limit) {
 3467#endif
 3468    if(gc_bell) {
 3469      C_putchar(7);
 3470      C_fflush(stdout);
 3471    }
 3472
 3473    tgc = C_cpu_milliseconds();
 3474
 3475    if(gc_mode == GC_REALLOC) {
 3476      cell.val = "GC_REALLOC";
 3477      C_debugger(&cell, 0, NULL);
 3478      C_rereclaim2(percentage(heap_size, C_heap_growth), 0);
 3479      gc_mode = GC_MAJOR;
 3480
 3481      tgt_space_start = tospace_start;
 3482      tgt_space_top = &tospace_top;
 3483      tgt_space_limit= tospace_limit;
 3484
 3485      count = (C_uword)tospace_top - (C_uword)tospace_start;
 3486      goto never_mind_edsger;
 3487    }
 3488
 3489    start = (C_byte *)C_align((C_uword)tospace_top);
 3490    gc_mode = GC_MAJOR;
 3491    tgt_space_start = tospace_start;
 3492    tgt_space_top = &tospace_top;
 3493    tgt_space_limit= tospace_limit;
 3494    weak_pair_chain = (C_word)NULL; /* only chain up weak pairs forwarded into tospace */
 3495    locative_chain = (C_word)NULL;  /* same for locatives */
 3496
 3497    cell.val = "GC_MAJOR";
 3498    C_debugger(&cell, 0, NULL);
 3499
 3500    mark_live_heap_only_objects(tgt_space_start, tgt_space_top, tgt_space_limit);
 3501
 3502    /* mark normal GC roots (see below for finalizer handling): */
 3503    for(gcrp = gc_root_list; gcrp != NULL; gcrp = gcrp->next) {
 3504      if(!gcrp->finalizable) mark(&gcrp->value);
 3505    }
 3506  }
 3507  else {
 3508    /* Mark mutated slots: */
 3509    for(msp = mutation_stack_bottom; msp < mutation_stack_top; ++msp)
 3510      mark(*msp);
 3511  }
 3512
 3513  mark_live_objects(tgt_space_start, tgt_space_top, tgt_space_limit);
 3514
 3515  mark_nested_objects(start, tgt_space_start, tgt_space_top, tgt_space_limit);
 3516  start = *tgt_space_top;
 3517
 3518  if(gc_mode == GC_MINOR) {
 3519    count = (C_uword)C_fromspace_top - (C_uword)start;
 3520    ++gc_count_1;
 3521    ++gc_count_1_total;
 3522    update_locatives(GC_MINOR, start, *tgt_space_top);
 3523    update_weak_pairs(GC_MINOR, start, *tgt_space_top);
 3524  }
 3525  else {
 3526    /* Mark finalizer list and remember pointers to non-forwarded items: */
 3527    last = C_block_item(pending_finalizers_symbol, 0);
 3528
 3529    if(!C_immediatep(last) && (j = C_unfix(C_block_item(last, 0))) != 0) {
 3530      /* still finalizers pending: just mark table items... */
 3531      if(gc_report_flag)
 3532        C_dbg(C_text("GC"), C_text("%d finalized item(s) still pending\n"), j);
 3533
 3534      j = fcount = 0;
 3535
 3536      for(flist = finalizer_list; flist != NULL; flist = flist->next) {
 3537        mark(&flist->item);
 3538        mark(&flist->finalizer);
 3539        ++fcount;
 3540      }
 3541
 3542      /* mark finalizable GC roots: */
 3543      for(gcrp = gc_root_list; gcrp != NULL; gcrp = gcrp->next) {
 3544        if(gcrp->finalizable) mark(&gcrp->value);
 3545      }
 3546
 3547      if(gc_report_flag && fcount > 0)
 3548        C_dbg(C_text("GC"), C_text("%d finalizer value(s) marked\n"), fcount);
 3549    }
 3550    else {
 3551      j = fcount = 0;
 3552
 3553      /* move into pending */
 3554      for(flist = finalizer_list; flist != NULL; flist = flist->next) {
 3555        if(j < C_max_pending_finalizers) {
 3556          if(!is_fptr(C_block_header(flist->item)))
 3557            pending_finalizer_indices[ j++ ] = flist;
 3558        }
 3559      }
 3560
 3561      /* mark */
 3562      for(flist = finalizer_list; flist != NULL; flist = flist->next) {
 3563        mark(&flist->item);
 3564        mark(&flist->finalizer);
 3565      }
 3566
 3567      /* mark finalizable GC roots: */
 3568      for(gcrp = gc_root_list; gcrp != NULL; gcrp = gcrp->next) {
 3569        if(gcrp->finalizable) mark(&gcrp->value);
 3570      }
 3571    }
 3572
 3573    pending_finalizer_count = j;
 3574    finalizers_checked = 1;
 3575
 3576    if(pending_finalizer_count > 0 && gc_report_flag)
 3577      C_dbg(C_text("GC"), C_text("%d finalizer(s) pending (%d live)\n"),
 3578            pending_finalizer_count, live_finalizer_count);
 3579
 3580    /* Once more mark nested objects after (maybe) copying finalizer objects: */
 3581    mark_nested_objects(start, tgt_space_start, tgt_space_top, tgt_space_limit);
 3582
 3583    /* Copy finalized items with remembered indices into `##sys#pending-finalizers'
 3584       (and release finalizer node): */
 3585    if(pending_finalizer_count > 0) {
 3586      if(gc_report_flag)
 3587        C_dbg(C_text("GC"), C_text("queueing %d finalizer(s)\n"), pending_finalizer_count);
 3588
 3589      last = C_block_item(pending_finalizers_symbol, 0);
 3590      assert(C_block_item(last, 0) == C_fix(0));
 3591      C_set_block_item(last, 0, C_fix(pending_finalizer_count));
 3592
 3593      for(i = 0; i < pending_finalizer_count; ++i) {
 3594        flist = pending_finalizer_indices[ i ];
 3595        C_set_block_item(last, 1 + i * 2, flist->item);
 3596        C_set_block_item(last, 2 + i * 2, flist->finalizer);
 3597
 3598        if(flist->previous != NULL) flist->previous->next = flist->next;
 3599        else finalizer_list = flist->next;
 3600
 3601        if(flist->next != NULL) flist->next->previous = flist->previous;
 3602
 3603        flist->next = finalizer_free_list;
 3604        flist->previous = NULL;
 3605        finalizer_free_list = flist;
 3606        --live_finalizer_count;
 3607      }
 3608    }
 3609
 3610    update_locatives(gc_mode, start, *tgt_space_top);
 3611    update_weak_pairs(gc_mode, start, *tgt_space_top);
 3612
 3613    count = (C_uword)tospace_top - (C_uword)tospace_start; // Actual used, < heap_size/2
 3614
 3615    {
 3616      C_uword min_half = count + C_heap_half_min_free;
 3617      C_uword low_half = percentage(heap_size/2, C_heap_shrinkage_used);
 3618      C_uword grown    = percentage(heap_size, C_heap_growth);
 3619      C_uword shrunk   = percentage(heap_size, C_heap_shrinkage);
 3620
 3621      if (count < low_half) {
 3622        heap_shrink_counter++;
 3623      } else {
 3624        heap_shrink_counter = 0;
 3625      }
 3626
 3627      /*** isn't gc_mode always GC_MAJOR here? */
 3628      if(gc_mode == GC_MAJOR && !C_heap_size_is_fixed &&
 3629         C_heap_shrinkage > 0 &&
 3630         // This prevents grow, shrink, grow, shrink... spam
 3631         HEAP_SHRINK_COUNTS < heap_shrink_counter &&
 3632         (min_half * 2) <= shrunk && // Min. size trumps shrinkage
 3633         heap_size > MINIMAL_HEAP_SIZE) {
 3634        if(gc_report_flag) {
 3635          C_dbg(C_text("GC"), C_text("Heap low water mark hit (%d%%), shrinking...\n"),
 3636                C_heap_shrinkage_used);
 3637        }
 3638        heap_shrink_counter = 0;
 3639        C_rereclaim2(shrunk, 0);
 3640      } else if (gc_mode == GC_MAJOR && !C_heap_size_is_fixed &&
 3641                 (heap_size / 2) < min_half) {
 3642        if(gc_report_flag) {
 3643          C_dbg(C_text("GC"), C_text("Heap high water mark hit, growing...\n"));
 3644        }
 3645        heap_shrink_counter = 0;
 3646        C_rereclaim2(grown, 0);
 3647      } else {
 3648        C_fromspace_top = tospace_top;
 3649        tmp = fromspace_start;
 3650        fromspace_start = tospace_start;
 3651        tospace_start = tospace_top = tmp;
 3652        tmp = C_fromspace_limit;
 3653        C_fromspace_limit = tospace_limit;
 3654        tospace_limit = tmp;
 3655      }
 3656    }
 3657
 3658  never_mind_edsger:
 3659    ++gc_count_2;
 3660  }
 3661
 3662  if(gc_mode == GC_MAJOR) {
 3663    tgc = C_cpu_milliseconds() - tgc;
 3664    gc_ms += tgc;
 3665    timer_accumulated_gc_ms += tgc;
 3666  }
 3667
 3668  /* Display GC report:
 3669     Note: stubbornly writes to stderr - there is no provision for other output-ports */
 3670  if(gc_report_flag == 1 || (gc_report_flag && gc_mode == GC_MAJOR)) {
 3671    C_dbg(C_text("GC"), C_text("level  %d\tgcs(minor)  %d\tgcs(major)  %d\n"),
 3672	  gc_mode, gc_count_1, gc_count_2);
 3673    i = (C_uword)C_stack_pointer;
 3674
 3675#if C_STACK_GROWS_DOWNWARD
 3676    C_dbg("GC", C_text("stack\t" UWORD_FORMAT_STRING "\t" UWORD_FORMAT_STRING "\t" UWORD_FORMAT_STRING),
 3677	  (C_uword)C_stack_limit, (C_uword)i, (C_uword)C_stack_limit + stack_size);
 3678#else
 3679    C_dbg("GC", C_text("stack\t" UWORD_FORMAT_STRING "\t" UWORD_FORMAT_STRING "\t" UWORD_FORMAT_STRING),
 3680	  (C_uword)C_stack_limit - stack_size, (C_uword)i, (C_uword)C_stack_limit);
 3681#endif
 3682
 3683    if(gc_mode == GC_MINOR)
 3684      C_fprintf(C_stderr, C_text("\t" UWORD_FORMAT_STRING), (C_uword)count);
 3685
 3686    C_fputc('\n', C_stderr);
 3687    C_dbg("GC", C_text(" from\t" UWORD_FORMAT_STRING "\t" UWORD_FORMAT_STRING "\t" UWORD_FORMAT_STRING),
 3688	  (C_uword)fromspace_start, (C_uword)C_fromspace_top, (C_uword)C_fromspace_limit);
 3689
 3690    if(gc_mode == GC_MAJOR)
 3691      C_fprintf(C_stderr, C_text("\t" UWORD_FORMAT_STRING), (C_uword)count);
 3692
 3693    C_fputc('\n', C_stderr);
 3694    C_dbg("GC", C_text("   to\t" UWORD_FORMAT_STRING "\t" UWORD_FORMAT_STRING "\t" UWORD_FORMAT_STRING" \n"),
 3695	  (C_uword)tospace_start, (C_uword)tospace_top,
 3696	  (C_uword)tospace_limit);
 3697  }
 3698
 3699  /* GC will have copied any live objects out of scratch space: clear it */
 3700  if (C_scratchspace_start != C_scratchspace_top) {
 3701    /* And drop the scratchspace in case of a major or reallocating collection */
 3702    if (gc_mode != GC_MINOR) {
 3703      C_free(C_scratchspace_start);
 3704      C_scratchspace_start = NULL;
 3705      C_scratchspace_limit = NULL;
 3706      scratchspace_size = 0;
 3707    }
 3708    C_scratchspace_top = C_scratchspace_start;
 3709    C_scratch_usage = 0;
 3710  }
 3711
 3712  if(gc_mode == GC_MAJOR) {
 3713    gc_count_1 = 0;
 3714    maximum_heap_usage = count > maximum_heap_usage ? count : maximum_heap_usage;
 3715  }
 3716
 3717  if(C_post_gc_hook != NULL) C_post_gc_hook(gc_mode, (C_long)tgc);
 3718
 3719  /* Unwind stack completely */
 3720#ifdef HAVE_SIGSETJMP
 3721  C_siglongjmp(C_restart, 1);
 3722#else
 3723  C_longjmp(C_restart, 1);
 3724#endif
 3725}
 3726
 3727
 3728/* Mark live objects which can exist in the nursery and/or the heap */
 3729static C_regparm void mark_live_objects(C_byte *tgt_space_start, C_byte **tgt_space_top, C_byte *tgt_space_limit)
 3730{
 3731  C_word *p;
 3732  TRACE_INFO *tinfo;
 3733
 3734  assert(C_temporary_stack >= C_temporary_stack_limit);
 3735
 3736  /* Mark live values from the currently running closure: */
 3737  for(p = C_temporary_stack; p < C_temporary_stack_bottom; ++p)
 3738    mark(p);
 3739
 3740  /* Clear the mutated slot stack: */
 3741  mutation_stack_top = mutation_stack_bottom;
 3742
 3743  /* Mark trace-buffer: */
 3744  for(tinfo = trace_buffer; tinfo < trace_buffer_limit; ++tinfo) {
 3745    mark(&tinfo->cooked_location);
 3746    mark(&tinfo->cooked1);
 3747    mark(&tinfo->cooked2);
 3748    mark(&tinfo->thread);
 3749  }
 3750}
 3751
 3752
 3753/*
 3754 * Mark all live *heap* objects that don't need GC mode-specific
 3755 * treatment.  Thus, no finalizers or other GC roots.
 3756 *
 3757 * Finalizers are excluded because these need special handling:
 3758 * finalizers referring to dead objects must be marked and queued.
 3759 * However, *pending* finalizers (for objects previously determined
 3760 * to be collectable) are marked so that these objects stick around
 3761 * until after the finalizer has been run.
 3762 *
 3763 * This function does not need to be called on a minor GC, since these
 3764 * objects won't ever exist in the nursery.
 3765 */
 3766static C_regparm void mark_live_heap_only_objects(C_byte *tgt_space_start, C_byte **tgt_space_top, C_byte *tgt_space_limit)
 3767{
 3768  LF_LIST *lfn;
 3769  C_word *p, **msp, last;
 3770  unsigned int i;
 3771  C_SYMBOL_TABLE *stp;
 3772
 3773  /* Mark items in forwarding table: */
 3774  for(p = forwarding_table; *p != 0; p += 2) {
 3775    last = p[ 1 ];
 3776    mark(&p[ 1 ]);
 3777    C_block_header(p[ 0 ]) = C_block_header(last);
 3778  }
 3779
 3780  /* Mark literal frames: */
 3781  for(lfn = lf_list; lfn != NULL; lfn = lfn->next)
 3782    for(i = 0; i < (unsigned int)lfn->count; ++i)
 3783      mark(&lfn->lf[i]);
 3784
 3785  /* Mark symbol tables: */
 3786  for(stp = symbol_table_list; stp != NULL; stp = stp->next)
 3787    for(i = 0; i < stp->size; ++i)
 3788      mark(&stp->table[i]);
 3789
 3790  /* Mark collectibles: */
 3791  for(msp = collectibles; msp < collectibles_top; ++msp)
 3792    if(*msp != NULL) mark(*msp);
 3793
 3794  /* Mark system globals */
 3795  mark(&core_provided_symbol);
 3796  mark(&interrupt_hook_symbol);
 3797  mark(&error_hook_symbol);
 3798  mark(&callback_continuation_stack_symbol);
 3799  mark(&pending_finalizers_symbol);
 3800  mark(&current_thread_symbol);
 3801
 3802  mark(&s8vector_symbol);
 3803  mark(&u16vector_symbol);
 3804  mark(&s16vector_symbol);
 3805  mark(&u32vector_symbol);
 3806  mark(&s32vector_symbol);
 3807  mark(&u64vector_symbol);
 3808  mark(&s64vector_symbol);
 3809  mark(&f32vector_symbol);
 3810  mark(&f64vector_symbol);
 3811}
 3812
 3813
 3814/*
 3815 * Mark nested values in already moved (i.e., marked) blocks in
 3816 * breadth-first manner (Cheney's algorithm).
 3817 */
 3818static 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)
 3819{
 3820  int n;
 3821  C_word bytes;
 3822  C_word *p;
 3823  C_header h;
 3824  C_SCHEME_BLOCK *bp;
 3825
 3826  while(heap_scan_top < *tgt_space_top) {
 3827    bp = (C_SCHEME_BLOCK *)heap_scan_top;
 3828
 3829    if(*((C_word *)bp) == ALIGNMENT_HOLE_MARKER)
 3830      bp = (C_SCHEME_BLOCK *)((C_word *)bp + 1);
 3831
 3832    n = C_header_size(bp);
 3833    h = bp->header;
 3834    bytes = (h & C_BYTEBLOCK_BIT) ? n : n * sizeof(C_word);
 3835    p = bp->data;
 3836
 3837    if(n > 0 && (h & C_BYTEBLOCK_BIT) == 0) {
 3838      if(h & C_SPECIALBLOCK_BIT) {
 3839	--n;
 3840	++p;
 3841      }
 3842
 3843      while(n--) mark(p++);
 3844    }
 3845
 3846    heap_scan_top = (C_byte *)bp + C_align(bytes) + sizeof(C_word);
 3847  }
 3848}
 3849
 3850
 3851static C_regparm void really_mark(C_word *x, C_byte *tgt_space_start, C_byte **tgt_space_top, C_byte *tgt_space_limit)
 3852{
 3853  C_word val;
 3854  C_uword n, bytes;
 3855  C_header h;
 3856  C_SCHEME_BLOCK *p, *p2;
 3857
 3858  val = *x;
 3859
 3860  if (!C_in_stackp(val) && !C_in_heapp(val) && !C_in_scratchspacep(val)) {
 3861#ifdef C_GC_HOOKS
 3862    if(C_gc_trace_hook != NULL)
 3863      C_gc_trace_hook(x, gc_mode);
 3864#endif
 3865    return;
 3866  }
 3867
 3868  p = (C_SCHEME_BLOCK *)val;
 3869  h = p->header;
 3870
 3871  while(is_fptr(h)) { /* TODO: Pass in fptr chain limit? */
 3872    val = fptr_to_ptr(h);
 3873    p = (C_SCHEME_BLOCK *)val;
 3874    h = p->header;
 3875  }
 3876
 3877  /* Already in target space, probably as result of chasing fptrs */
 3878  if ((C_uword)val >= (C_uword)tgt_space_start && (C_uword)val < (C_uword)*tgt_space_top) {
 3879    *x = val;
 3880    return;
 3881  }
 3882
 3883  p2 = (C_SCHEME_BLOCK *)C_align((C_uword)*tgt_space_top);
 3884
 3885#ifndef C_SIXTY_FOUR
 3886  if((h & C_8ALIGN_BIT) && C_aligned8(p2) && (C_byte *)p2 < tgt_space_limit) {
 3887    *((C_word *)p2) = ALIGNMENT_HOLE_MARKER;
 3888    p2 = (C_SCHEME_BLOCK *)((C_word *)p2 + 1);
 3889  }
 3890#endif
 3891
 3892  n = C_header_size(p);
 3893  bytes = (h & C_BYTEBLOCK_BIT) ? n : n * sizeof(C_word);
 3894
 3895  if(C_unlikely(((C_byte *)p2 + bytes + sizeof(C_word)) > tgt_space_limit)) {
 3896    if (gc_mode == GC_MAJOR) {
 3897      /* Detect impossibilities before GC_REALLOC to preserve state: */
 3898      if (C_in_stackp((C_word)p) && bytes > stack_size)
 3899        panic(C_text("Detected corrupted data in stack"));
 3900      if (C_in_heapp((C_word)p) && bytes > (heap_size / 2))
 3901        panic(C_text("Detected corrupted data in heap"));
 3902      if(C_heap_size_is_fixed)
 3903        panic(C_text("out of memory - heap full"));
 3904
 3905      gc_mode = GC_REALLOC;
 3906    } else if (gc_mode == GC_REALLOC) {
 3907      if (new_tospace_top > new_tospace_limit) {
 3908        panic(C_text("out of memory - heap full while resizing"));
 3909      }
 3910    }
 3911#ifdef HAVE_SIGSETJMP
 3912    C_siglongjmp(gc_restart, 1);
 3913#else
 3914    C_longjmp(gc_restart, 1);
 3915#endif
 3916  }
 3917
 3918  *tgt_space_top = (C_byte *)p2 + C_align(bytes) + sizeof(C_word);
 3919
 3920  *x = (C_word)p2;
 3921  p2->header = h;
 3922  p->header = ptr_to_fptr((C_uword)p2);
 3923  C_memcpy(p2->data, p->data, bytes);
 3924  if (h == C_WEAK_PAIR_TAG && !C_immediatep(p2->data[0])) {
 3925    p->data[0] = weak_pair_chain; /* "Recycle" the weak pair's CAR to point to prev head */
 3926    weak_pair_chain = (C_word)p;  /* Make this fwd ptr the new head of the weak pair chain */
 3927  } else if (h == C_LOCATIVE_TAG) {
 3928    p->data[0] = locative_chain; /* "Recycle" the locative pointer field to point to prev head */
 3929    locative_chain = (C_word)p;  /* Make this fwd ptr the new head of the locative chain */
 3930  }
 3931}
 3932
 3933
 3934/* Do a major GC into a freshly allocated heap: */
 3935
 3936#define remark(x)  _mark(x, new_tospace_start, &new_tospace_top, new_tospace_limit)
 3937
 3938C_regparm void C_rereclaim2(C_uword size, int relative_resize)
 3939{
 3940  int i;
 3941  C_GC_ROOT *gcrp;
 3942  FINALIZER_NODE *flist;
 3943  C_byte *new_heapspace, *start;
 3944  size_t  new_heapspace_size;
 3945
 3946  if(C_pre_gc_hook != NULL) C_pre_gc_hook(GC_REALLOC);
 3947
 3948  /*
 3949   * Normally, size is "absolute": it indicates the desired size of
 3950   * the entire new heap.  With relative_resize, size is a demanded
 3951   * increase of the heap, so we'll have to add it.  This calculation
 3952   * doubles the current heap size because heap_size is already both
 3953   * halves.  We add size*2 because we'll eventually divide the size
 3954   * by 2 for both halves.  We also add stack_size*2 because all the
 3955   * nursery data is also copied to the heap on GC, and the requested
 3956   * memory "size" must be available after the GC.
 3957   */
 3958  if(relative_resize) size = (heap_size + size + stack_size) * 2;
 3959
 3960  if(size < MINIMAL_HEAP_SIZE) size = MINIMAL_HEAP_SIZE;
 3961
 3962  /*
 3963   * When heap grows, ensure it's enough to accommodate first
 3964   * generation (nursery).  Because we're calculating the total heap
 3965   * size here (fromspace *AND* tospace), we have to double the stack
 3966   * size, otherwise we'd accommodate only half the stack in the tospace.
 3967   */
 3968  if(size > heap_size && size - heap_size < stack_size * 2)
 3969    size = heap_size + stack_size * 2;
 3970
 3971  /*
 3972   * The heap has grown but we've already hit the maximal size with the current
 3973   * heap, we can't do anything else but panic.
 3974   */
 3975  if(size > heap_size && heap_size >= C_maximal_heap_size)
 3976    panic(C_text("out of memory - heap has reached its maximum size"));
 3977
 3978  if(size > C_maximal_heap_size) size = C_maximal_heap_size;
 3979
 3980  if(debug_mode) {
 3981    C_dbg(C_text("debug"), C_text("resizing heap dynamically from "
 3982                                  UWORD_COUNT_FORMAT_STRING "k to "
 3983                                  UWORD_COUNT_FORMAT_STRING "k ...\n"),
 3984	  heap_size / 1024, size / 1024);
 3985  }
 3986
 3987  if(gc_report_flag) {
 3988    C_dbg(C_text("GC"), C_text("(old) fromspace: \tstart=" UWORD_FORMAT_STRING
 3989			       ", \tlimit=" UWORD_FORMAT_STRING "\n"),
 3990	  (C_word)fromspace_start, (C_word)C_fromspace_limit);
 3991    C_dbg(C_text("GC"), C_text("(old) tospace:   \tstart=" UWORD_FORMAT_STRING
 3992			       ", \tlimit=" UWORD_FORMAT_STRING "\n"),
 3993	  (C_word)tospace_start, (C_word)tospace_limit);
 3994  }
 3995
 3996  heap_size = size;         /* Total heap size of the two halves... */
 3997  size /= 2;                /* ...each half is this big */
 3998
 3999  /*
 4000   * Start by allocating the new heap's fromspace.  After remarking,
 4001   * allocate the other half of the new heap (its tospace).
 4002   *
 4003   * To clarify: what we call "new_space" here is what will eventually
 4004   * be cycled over to "fromspace" when re-reclamation has finished
 4005   * (that is, after the old one has been freed).
 4006   */
 4007  if ((new_heapspace = heap_alloc (size, &new_tospace_start)) == NULL)
 4008    panic(C_text("out of memory - cannot allocate heap segment"));
 4009  new_heapspace_size = size;
 4010
 4011  new_tospace_top = new_tospace_start;
 4012  new_tospace_limit = new_tospace_start + size;
 4013  start = new_tospace_top;
 4014  weak_pair_chain = (C_word)NULL; /* only chain up weak pairs forwarded into new heap */
 4015  locative_chain = (C_word)NULL;  /* same for locatives */
 4016
 4017  /* Mark standard live objects in nursery and heap */
 4018  mark_live_objects(new_tospace_start, &new_tospace_top, new_tospace_limit);
 4019  mark_live_heap_only_objects(new_tospace_start, &new_tospace_top, new_tospace_limit);
 4020
 4021  /* Mark finalizer table: */
 4022  for(flist = finalizer_list; flist != NULL; flist = flist->next) {
 4023    remark(&flist->item);
 4024    remark(&flist->finalizer);
 4025  }
 4026
 4027  /* Mark *all* GC roots */
 4028  for(gcrp = gc_root_list; gcrp != NULL; gcrp = gcrp->next) {
 4029    remark(&gcrp->value);
 4030  }
 4031
 4032  /* Mark nested values in already moved (marked) blocks in breadth-first manner: */
 4033  mark_nested_objects(start, new_tospace_start, &new_tospace_top, new_tospace_limit);
 4034  update_locatives(GC_REALLOC, new_tospace_top, new_tospace_top);
 4035  update_weak_pairs(GC_REALLOC, new_tospace_top, new_tospace_top);
 4036
 4037  heap_free (heapspace1, heapspace1_size);
 4038  heap_free (heapspace2, heapspace2_size);
 4039
 4040  if ((heapspace2 = heap_alloc (size, &tospace_start)) == NULL)
 4041    panic(C_text("out of memory - cannot allocate next heap segment"));
 4042  heapspace2_size = size;
 4043
 4044  heapspace1 = new_heapspace;
 4045  heapspace1_size = new_heapspace_size;
 4046  tospace_limit = tospace_start + size;
 4047  tospace_top = tospace_start;
 4048  fromspace_start = new_tospace_start;
 4049  C_fromspace_top = new_tospace_top;
 4050  C_fromspace_limit = new_tospace_limit;
 4051
 4052  if(gc_report_flag) {
 4053    C_dbg(C_text("GC"), C_text("resized heap to %d bytes\n"), heap_size);
 4054    C_dbg(C_text("GC"), C_text("(new) fromspace: \tstart=" UWORD_FORMAT_STRING
 4055			       ", \tlimit=" UWORD_FORMAT_STRING "\n"),
 4056	  (C_word)fromspace_start, (C_word)C_fromspace_limit);
 4057    C_dbg(C_text("GC"), C_text("(new) tospace:   \tstart=" UWORD_FORMAT_STRING
 4058			       ", \tlimit=" UWORD_FORMAT_STRING "\n"),
 4059	  (C_word)tospace_start, (C_word)tospace_limit);
 4060  }
 4061
 4062  if(C_post_gc_hook != NULL) C_post_gc_hook(GC_REALLOC, 0);
 4063}
 4064
 4065
 4066/* When a weak pair is encountered by GC, it turns it into a
 4067 * forwarding reference as usual, but then it re-uses the now-defunct
 4068 * pair's CAR field.  It clobbers that field with a plain C pointer to
 4069 * the current "weak pair chain".  Then, the weak pair chain is
 4070 * updated to point to this new forwarding pointer, creating a crude
 4071 * linked list of sorts.
 4072 *
 4073 * We can get away with this because the slots of an object are
 4074 * unused/dead when it is turned into a forwarding pointer - the
 4075 * forwarding pointer itself is just a header, but those data fields
 4076 * remain allocated.  Since the weak pair chain is a linked list that
 4077 * can *only* contain weak-pairs-turned-forwarding-pointer, we may
 4078 * freely access the first slot of such forwarding pointers.
 4079 */
 4080static C_regparm void update_weak_pairs(int mode, C_byte *undead_start, C_byte *undead_end)
 4081{
 4082  int weakn = 0;
 4083  C_word p, pair, car, h;
 4084  C_byte *car_ptr;
 4085
 4086  /* NOTE: Don't use C_block_item() because it asserts the block is
 4087   * big enough in DEBUGBUILD, but forwarding pointers have size 0.
 4088   */
 4089  for (p = weak_pair_chain; p != (C_word)NULL; p = *((C_word *)C_data_pointer(p))) {
 4090    /* NOTE: We only chain up the weak pairs' forwarding pointers into
 4091     * the new space.  This is safe because already forwarded weak
 4092     * pairs in nursery/fromspace will be forwarded *again* into
 4093     * tospace/new heap.  That forwarding pointer is chained up.
 4094     * Still-unforwarded weak pairs will be forwarded straight to the
 4095     * new space, and also chained up.
 4096     */
 4097    h = C_block_header(p);
 4098    assert(is_fptr(h));
 4099    pair = fptr_to_ptr(h);
 4100    assert(!is_fptr(C_block_header(pair)));
 4101
 4102    /* The pair itself should be live */
 4103    assert((mode == GC_MINOR && !C_in_stackp(pair)) ||
 4104           (mode == GC_MAJOR && !C_in_stackp(pair) && !C_in_fromspacep(pair)) ||
 4105           (mode == GC_REALLOC && !C_in_stackp(pair) && !C_in_heapp(pair))); /* NB: *old* heap! */
 4106
 4107    car = C_block_item(pair, 0);
 4108    assert(!C_immediatep(car)); /* should be ensured when adding it to the chain */
 4109    h = C_block_header(car);
 4110    while (is_fptr(h)) {
 4111      car = fptr_to_ptr(h);
 4112      h = C_block_header(car);
 4113    }
 4114
 4115    car_ptr = (C_byte *)(C_uword)car;
 4116    /* If the car is unreferenced by anyone else, it wasn't moved by GC.  Or, if it's in the "undead" portion of
 4117       the new heap, it was moved because it was only referenced by a revived finalizable object.  In either case, drop it: */
 4118    if((mode == GC_MINOR && C_in_stackp(car)) ||
 4119       (mode == GC_MAJOR && (C_in_stackp(car) || C_in_fromspacep(car) || (car_ptr >= undead_start && car_ptr < undead_end))) ||
 4120       (mode == GC_REALLOC && (C_in_stackp(car) || C_in_heapp(car) || (car_ptr >= undead_start && car_ptr < undead_end)))) { /* NB: *old* heap! */
 4121
 4122      C_set_block_item(pair, 0, C_SCHEME_BROKEN_WEAK_PTR);
 4123      ++weakn;
 4124    } else {
 4125      /* Might have moved, re-set the car to the target value */
 4126      C_set_block_item(pair, 0, car);
 4127    }
 4128  }
 4129  weak_pair_chain = (C_word)NULL;
 4130  if(gc_report_flag && weakn)
 4131    C_dbg("GC", C_text("%d recoverable weak pairs found\n"), weakn);
 4132}
 4133
 4134/* Same as weak pairs (see above), but for locatives.  Note that this
 4135 * also includes non-weak locatives, as these point *into* an object,
 4136 * so the updating of that pointer is not handled by the GC proper
 4137 * (which only deals with full objects).
 4138 */
 4139static C_regparm void update_locatives(int mode, C_byte *undead_start, C_byte *undead_end)
 4140{
 4141  int weakn = 0;
 4142  C_word p, loc, ptr, obj, h, offset;
 4143  C_byte *obj_ptr;
 4144
 4145  for (p = locative_chain; p != (C_word)NULL; p = *((C_word *)C_data_pointer(p))) {
 4146    h = C_block_header(p);
 4147    assert(is_fptr(h));
 4148    loc = fptr_to_ptr(h);
 4149    assert(!is_fptr(C_block_header(loc)));
 4150
 4151    /* The locative object itself should be live */
 4152    assert((mode == GC_MINOR && !C_in_stackp(loc)) ||
 4153           (mode == GC_MAJOR && !C_in_stackp(loc) && !C_in_fromspacep(loc)) ||
 4154           (mode == GC_REALLOC && !C_in_stackp(loc) && !C_in_heapp(loc))); /* NB: *old* heap! */
 4155
 4156    ptr = C_block_item(loc, 0); /* fix up ptr */
 4157    if (ptr == 0) continue; /* Skip already dropped weak locatives */
 4158    offset = C_unfix(C_block_item(loc, 1));
 4159    obj = ptr - offset;
 4160
 4161    h = C_block_header(obj);
 4162    while (is_fptr(h)) {
 4163      obj = fptr_to_ptr(h);
 4164      h = C_block_header(obj);
 4165    }
 4166
 4167    obj_ptr = (C_byte *)(C_uword)obj;
 4168    /* If the object is unreferenced by anyone else, it wasn't moved by GC.  Or, if it's in the "undead" portion of
 4169       the new heap, it was moved because it was only referenced by a revived finalizable object.  In either case, drop it: */
 4170    if((mode == GC_MINOR && C_in_stackp(obj)) ||
 4171       (mode == GC_MAJOR && (C_in_stackp(obj) || C_in_fromspacep(obj) || (obj_ptr >= undead_start && obj_ptr < undead_end))) ||
 4172       (mode == GC_REALLOC && (C_in_stackp(obj) || C_in_heapp(obj) || (obj_ptr >= undead_start && obj_ptr < undead_end)))) { /* NB: *old* heap! */
 4173
 4174      /* NOTE: This does *not* use BROKEN_WEAK_POINTER.  This slot
 4175       * holds an unaligned raw C pointer, not a Scheme object */
 4176      C_set_block_item(loc, 0, 0);
 4177      ++weakn;
 4178    } else {
 4179      /* Might have moved, re-set the object to the target value */
 4180      C_set_block_item(loc, 0, obj + offset);
 4181    }
 4182  }
 4183  locative_chain = (C_word)NULL;
 4184  if(gc_report_flag && weakn)
 4185    C_dbg("GC", C_text("%d recoverable weak locatives found\n"), weakn);
 4186}
 4187
 4188
 4189void handle_interrupt(void *trampoline)
 4190{
 4191  C_word *p, h, reason, state, proc, n;
 4192  double c;
 4193  C_word av[ 4 ];
 4194
 4195  /* Build vector with context information: */
 4196  n = C_temporary_stack_bottom - C_temporary_stack;
 4197  p = C_alloc(C_SIZEOF_VECTOR(2) + C_SIZEOF_VECTOR(n));
 4198  proc = (C_word)p;
 4199  *(p++) = C_VECTOR_TYPE | C_BYTEBLOCK_BIT | sizeof(C_word);
 4200  *(p++) = (C_word)trampoline;
 4201  state = (C_word)p;
 4202  *(p++) = C_VECTOR_TYPE | (n + 1);
 4203  *(p++) = proc;
 4204  C_memcpy(p, C_temporary_stack, n * sizeof(C_word));
 4205
 4206  /* Restore state to the one at the time of the interrupt: */
 4207  C_temporary_stack = C_temporary_stack_bottom;
 4208  C_stack_limit = C_stack_hard_limit;
 4209
 4210  /* Invoke high-level interrupt handler: */
 4211  reason = C_fix(pending_interrupts[ --pending_interrupts_count ]);
 4212  proc = C_block_item(interrupt_hook_symbol, 0);
 4213
 4214  if(C_immediatep(proc))
 4215    panic(C_text("`##sys#interrupt-hook' is not defined"));
 4216
 4217  c = C_cpu_milliseconds() - interrupt_time;
 4218  last_interrupt_latency = c;
 4219  C_timer_interrupt_counter = C_initial_timer_interrupt_period;
 4220  /* <- no continuation is passed: "##sys#interrupt-hook" may not return! */
 4221  av[ 0 ] = proc;
 4222  av[ 1 ] = C_SCHEME_UNDEFINED;
 4223  av[ 2 ] = reason;
 4224  av[ 3 ] = state;
 4225  C_do_apply(4, av);
 4226}
 4227
 4228
 4229void
 4230C_unbound_variable(C_word sym)
 4231{
 4232  barf(C_UNBOUND_VARIABLE_ERROR, NULL, sym);
 4233}
 4234
 4235
 4236void
 4237C_decoding_error(C_word str, C_word index)
 4238{
 4239  barf(C_DECODING_ERROR, NULL, str, index);
 4240}
 4241
 4242
 4243/* XXX: This needs to be given a better name.
 4244   C_retrieve used to exist but it just called C_fast_retrieve */
 4245C_regparm C_word C_retrieve2(C_word val, char *name)
 4246{
 4247  C_word *p;
 4248  int len;
 4249
 4250  if(val == C_SCHEME_UNBOUND) {
 4251    len = C_strlen(name);
 4252    /* this is ok: we won't return from `C_retrieve2'
 4253     * (or the value isn't needed). */
 4254    p = C_alloc(C_SIZEOF_STRING(len));
 4255    C_unbound_variable(C_string2(&p, name));
 4256  }
 4257
 4258  return val;
 4259}
 4260
 4261
 4262void C_ccall C_invalid_procedure(C_word c, C_word *av)
 4263{
 4264  C_word self = av[0];
 4265  barf(C_NOT_A_CLOSURE_ERROR, NULL, self);
 4266}
 4267
 4268
 4269C_regparm void *C_retrieve2_symbol_proc(C_word val, char *name)
 4270{
 4271  C_word *p;
 4272  int len;
 4273
 4274  if(val == C_SCHEME_UNBOUND) {
 4275    len = C_strlen(name);
 4276    /* this is ok: we won't return from `C_retrieve2' (or the value isn't needed). */
 4277    p = C_alloc(C_SIZEOF_STRING(len));
 4278    barf(C_UNBOUND_VARIABLE_ERROR, NULL, C_string2(&p, name));
 4279  }
 4280
 4281  return C_fast_retrieve_proc(val);
 4282}
 4283
 4284#ifdef C_NONUNIX
 4285VOID CALLBACK win_timer(PVOID data_ignored, BOOLEAN wait_or_fired)
 4286{
 4287  if (profiling) take_profile_sample();
 4288}
 4289#endif
 4290
 4291static void set_profile_timer(C_uword freq)
 4292{
 4293#ifdef C_NONUNIX
 4294  static HANDLE timer = NULL;
 4295
 4296  if (freq == 0) {
 4297    assert(timer != NULL);
 4298    if (!DeleteTimerQueueTimer(NULL, timer, NULL)) goto error;
 4299    timer = NULL;
 4300  } else if (freq < 1000) {
 4301    panic(C_text("On Windows, sampling can only be done in milliseconds"));
 4302  } else {
 4303    if (!CreateTimerQueueTimer(&timer, NULL, win_timer, NULL, 0, freq/1000, 0))
 4304      goto error;
 4305  }
 4306#else
 4307  struct itimerval itv;
 4308
 4309  itv.it_value.tv_sec = freq / 1000000;
 4310  itv.it_value.tv_usec = freq % 1000000;
 4311  itv.it_interval.tv_sec = itv.it_value.tv_sec;
 4312  itv.it_interval.tv_usec = itv.it_value.tv_usec;
 4313
 4314  if (setitimer(C_PROFILE_TIMER, &itv, NULL) == -1) goto error;
 4315#endif
 4316
 4317  return;
 4318
 4319error:
 4320  if (freq == 0) panic(C_text("error clearing timer for profiling"));
 4321  else panic(C_text("error setting timer for profiling"));
 4322}
 4323
 4324/* Bump profile count for current top of trace buffer */
 4325static void take_profile_sample()
 4326{
 4327  PROFILE_BUCKET **bp, *b;
 4328  C_char *key;
 4329  TRACE_INFO *tb;
 4330  /* To count distinct calls of a procedure, remember last call */
 4331  static C_char *prev_key = NULL;
 4332  static TRACE_INFO *prev_tb = NULL;
 4333
 4334  /* trace_buffer_top points *beyond* the topmost entry: Go back one */
 4335  if (trace_buffer_top == trace_buffer) {
 4336    if (!trace_buffer_full) return; /* No data yet */
 4337    tb = trace_buffer_limit - 1;
 4338  } else {
 4339    tb = trace_buffer_top - 1;
 4340  }
 4341
 4342  if (tb->raw_location != NULL) {
 4343    key = tb->raw_location;
 4344  } else {
 4345    key = "<eval>"; /* Location string is GCable, can't use it */
 4346  }
 4347
 4348  /* We could also just hash the pointer but that's a bit trickier */
 4349  bp = profile_table + hash_string(C_strlen(key), key, PROFILE_TABLE_SIZE, 0);
 4350  b = *bp;
 4351
 4352  /* First try to find pre-existing item in hash table */
 4353  while(b != NULL) {
 4354    if(b->key == key) {
 4355      b->sample_count++;
 4356      if (prev_key != key && prev_tb != tb)
 4357        b->call_count++;
 4358      goto done;
 4359    }
 4360    else b = b->next;
 4361  }
 4362
 4363  /* Not found, allocate a new item and use it as bucket's new head */
 4364  b = next_profile_bucket;
 4365  next_profile_bucket = NULL;
 4366
 4367  assert(b != NULL);
 4368
 4369  b->next = *bp;
 4370  b->key = key;
 4371  *bp = b;
 4372  b->sample_count = 1;
 4373  b->call_count = 1;
 4374
 4375done:
 4376  prev_tb = tb;
 4377  prev_key = key;
 4378}
 4379
 4380
 4381C_regparm void C_trace(C_char *name)
 4382{
 4383  C_word thread;
 4384
 4385  if(show_trace) {
 4386    C_fputs(name, C_stderr);
 4387    C_fputc('\n', C_stderr);
 4388  }
 4389
 4390  /*
 4391   * When profiling, pre-allocate profile bucket if necessary.  This
 4392   * is used in the signal handler, because it may not malloc.
 4393   */
 4394  if(profiling && next_profile_bucket == NULL) {
 4395    next_profile_bucket = (PROFILE_BUCKET *)C_malloc(sizeof(PROFILE_BUCKET));
 4396    if (next_profile_bucket == NULL) {
 4397      panic(C_text("out of memory - cannot allocate profile table-bucket"));
 4398    }
 4399  }
 4400
 4401  if(trace_buffer_top >= trace_buffer_limit) {
 4402    trace_buffer_top = trace_buffer;
 4403    trace_buffer_full = 1;
 4404  }
 4405
 4406  trace_buffer_top->raw_location = name;
 4407  trace_buffer_top->cooked_location = C_SCHEME_FALSE;
 4408  trace_buffer_top->cooked1 = C_SCHEME_FALSE;
 4409  trace_buffer_top->cooked2 = C_SCHEME_FALSE;
 4410  thread = C_block_item(current_thread_symbol, 0);
 4411  trace_buffer_top->thread = C_and(C_blockp(thread), C_thread_id(thread));
 4412  ++trace_buffer_top;
 4413}
 4414
 4415
 4416C_regparm C_word C_emit_trace_info2(char *raw, C_word l, C_word x, C_word y, C_word t)
 4417{
 4418  /* See above */
 4419  if(profiling && next_profile_bucket == NULL) {
 4420    next_profile_bucket = (PROFILE_BUCKET *)C_malloc(sizeof(PROFILE_BUCKET));
 4421    if (next_profile_bucket == NULL) {
 4422      panic(C_text("out of memory - cannot allocate profile table-bucket"));
 4423    }
 4424  }
 4425
 4426  if(trace_buffer_top >= trace_buffer_limit) {
 4427    trace_buffer_top = trace_buffer;
 4428    trace_buffer_full = 1;
 4429  }
 4430
 4431  trace_buffer_top->raw_location = raw;
 4432  trace_buffer_top->cooked_location = l;
 4433  trace_buffer_top->cooked1 = x;
 4434  trace_buffer_top->cooked2 = y;
 4435  trace_buffer_top->thread = t;
 4436  ++trace_buffer_top;
 4437  return x;
 4438}
 4439
 4440
 4441C_char *C_dump_trace(int start)
 4442{
 4443  TRACE_INFO *ptr;
 4444  C_char *result;
 4445  int i, result_len;
 4446
 4447  result_len = STRING_BUFFER_SIZE;
 4448  if((result = (char *)C_malloc(result_len)) == NULL)
 4449    horror(C_text("out of memory - cannot allocate trace-dump buffer"));
 4450
 4451  *result = '\0';
 4452
 4453  if(trace_buffer_top > trace_buffer || trace_buffer_full) {
 4454    if(trace_buffer_full) {
 4455      i = C_trace_buffer_size;
 4456      C_strlcat(result, C_text("...more...\n"), result_len);
 4457    }
 4458    else i = trace_buffer_top - trace_buffer;
 4459
 4460    ptr = trace_buffer_full ? trace_buffer_top : trace_buffer;
 4461    ptr += start;
 4462    i -= start;
 4463
 4464    for(;i--; ++ptr) {
 4465      if(ptr >= trace_buffer_limit) ptr = trace_buffer;
 4466
 4467      if(C_strlen(result) > STRING_BUFFER_SIZE - 32) {
 4468        result_len = C_strlen(result) * 2;
 4469        result = C_realloc(result, result_len);
 4470	if(result == NULL)
 4471	  horror(C_text("out of memory - cannot reallocate trace-dump buffer"));
 4472      }
 4473
 4474      if (ptr->raw_location != NULL) {
 4475        C_strlcat(result, ptr->raw_location, result_len);
 4476      } else if (ptr->cooked_location != C_SCHEME_FALSE) {
 4477        C_word bv = C_block_item(ptr->cooked_location, 0);
 4478        C_strlcat(result, C_c_string(bv), nmin(C_header_size(bv) - 1, result_len));
 4479      } else {
 4480        C_strlcat(result, "<unknown>", result_len);
 4481      }
 4482
 4483      if(i > 0) C_strlcat(result, "\n", result_len);
 4484      else C_strlcat(result, " \t<--\n", result_len);
 4485    }
 4486  }
 4487
 4488  return result;
 4489}
 4490
 4491
 4492C_regparm void C_clear_trace_buffer(void)
 4493{
 4494  int i, old_profiling = profiling;
 4495
 4496  profiling = 0;
 4497
 4498  if(trace_buffer == NULL) {
 4499    if(C_trace_buffer_size < MIN_TRACE_BUFFER_SIZE)
 4500      C_trace_buffer_size = MIN_TRACE_BUFFER_SIZE;
 4501
 4502    trace_buffer = (TRACE_INFO *)C_malloc(sizeof(TRACE_INFO) * C_trace_buffer_size);
 4503
 4504    if(trace_buffer == NULL)
 4505      panic(C_text("out of memory - cannot allocate trace-buffer"));
 4506  }
 4507
 4508  trace_buffer_top = trace_buffer;
 4509  trace_buffer_limit = trace_buffer + C_trace_buffer_size;
 4510  trace_buffer_full = 0;
 4511
 4512  for(i = 0; i < C_trace_buffer_size; ++i) {
 4513    trace_buffer[ i ].raw_location = NULL;
 4514    trace_buffer[ i ].cooked_location = C_SCHEME_FALSE;
 4515    trace_buffer[ i ].cooked1 = C_SCHEME_FALSE;
 4516    trace_buffer[ i ].cooked2 = C_SCHEME_FALSE;
 4517    trace_buffer[ i ].thread = C_SCHEME_FALSE;
 4518  }
 4519
 4520  profiling = old_profiling;
 4521}
 4522
 4523C_word C_resize_trace_buffer(C_word size) {
 4524  int old_size = C_trace_buffer_size, old_profiling = profiling;
 4525  assert(trace_buffer);
 4526  profiling = 0;
 4527  free(trace_buffer);
 4528  trace_buffer = NULL;
 4529  C_trace_buffer_size = C_unfix(size);
 4530  C_clear_trace_buffer();
 4531  profiling = old_profiling;
 4532  return(C_fix(old_size));
 4533}
 4534
 4535C_word C_fetch_trace(C_word starti, C_word buffer)
 4536{
 4537  TRACE_INFO *ptr;
 4538  int i, p = 0, start = C_unfix(starti);
 4539
 4540  if(trace_buffer_top > trace_buffer || trace_buffer_full) {
 4541    if(trace_buffer_full) i = C_trace_buffer_size;
 4542    else i = trace_buffer_top - trace_buffer;
 4543
 4544    ptr = trace_buffer_full ? trace_buffer_top : trace_buffer;
 4545    ptr += start;
 4546    i -= start;
 4547
 4548    if(C_header_size(buffer) < i * 5)
 4549      panic(C_text("destination buffer too small for call-chain"));
 4550
 4551    for(;i--; ++ptr) {
 4552      if(ptr >= trace_buffer_limit) ptr = trace_buffer;
 4553
 4554      /* outside-pointer, will be ignored by GC */
 4555      C_mutate(&C_block_item(buffer, p++), (C_word)ptr->raw_location);
 4556
 4557      /* subject to GC */
 4558      C_mutate(&C_block_item(buffer, p++), ptr->cooked_location);
 4559      C_mutate(&C_block_item(buffer, p++), ptr->cooked1);
 4560      C_mutate(&C_block_item(buffer, p++), ptr->cooked2);
 4561      C_mutate(&C_block_item(buffer, p++), ptr->thread);
 4562    }
 4563  }
 4564
 4565  return C_fix(p);
 4566}
 4567
 4568C_regparm C_word C_u_i_bytevector_hash(C_word str, C_word start, C_word end, C_word rnd)
 4569{
 4570  int len = C_header_size(str);
 4571  C_char *ptr = C_c_string(str);
 4572  return C_fix(hash_string(C_unfix(end) - C_unfix(start), ptr + C_unfix(start), C_MOST_POSITIVE_FIXNUM, C_unfix(rnd)));
 4573}
 4574
 4575C_regparm void C_toplevel_entry(C_char *name)
 4576{
 4577  if(debug_mode)
 4578    C_dbg(C_text("debug"), C_text("entering %s...\n"), name);
 4579}
 4580
 4581C_regparm C_word C_a_i_provide(C_word **a, int c, C_word id)
 4582{
 4583  if (debug_mode == 2) {
 4584    C_word str = C_block_item(id, 1);
 4585    C_dbg(C_text("debug"), C_text("providing %s...\n"), C_c_string(str));
 4586  }
 4587  return C_a_i_putprop(a, 3, core_provided_symbol, id, C_SCHEME_TRUE);
 4588}
 4589
 4590C_regparm C_word C_i_providedp(C_word id)
 4591{
 4592  return C_i_getprop(core_provided_symbol, id, C_SCHEME_FALSE);
 4593}
 4594
 4595C_word C_halt(C_word msg)
 4596{
 4597  C_char *dmp = msg != C_SCHEME_FALSE ? C_dump_trace(0) : NULL;
 4598
 4599  if(C_gui_mode) {
 4600    if(msg != C_SCHEME_FALSE) {
 4601      int n = C_header_size(msg);
 4602
 4603      if (n >= sizeof(buffer))
 4604	n = sizeof(buffer) - 1;
 4605      C_strlcpy(buffer, (C_char *)C_data_pointer(msg), n);
 4606      /* XXX msg isn't checked for NUL bytes, but we can't barf here either! */
 4607    }
 4608    else C_strlcpy(buffer, C_text("(aborted)"), sizeof(buffer));
 4609
 4610    C_strlcat(buffer, C_text("\n\n"), sizeof(buffer));
 4611
 4612    if(dmp != NULL) C_strlcat(buffer, dmp, sizeof(buffer));
 4613
 4614#if defined(_WIN32) && !defined(__CYGWIN__)
 4615    MessageBox(NULL, buffer, C_text("CHICKEN runtime"), MB_OK | MB_ICONERROR);
 4616    ExitProcess(1);
 4617#endif
 4618  } /* otherwise fall through */
 4619
 4620  if(msg != C_SCHEME_FALSE) {
 4621    C_fwrite(C_data_pointer(msg), C_header_size(msg), sizeof(C_char), C_stderr);
 4622    C_fputc('\n', C_stderr);
 4623  }
 4624
 4625  if(dmp != NULL)
 4626    C_dbg("", C_text("\n%s"), dmp);
 4627
 4628  C_exit_runtime(C_fix(EX_SOFTWARE));
 4629  return 0;
 4630}
 4631
 4632
 4633C_word C_message(C_word msg)
 4634{
 4635  C_word m = C_block_item(msg, 0);
 4636  unsigned int n = C_header_size(m);
 4637  /*
 4638   * Strictly speaking this isn't necessary for the non-gui-mode,
 4639   * but let's try and keep this consistent across modes.
 4640   */
 4641  if (C_memchr(C_c_string(m), '\0', n - 1) != NULL)
 4642    barf(C_ASCIIZ_REPRESENTATION_ERROR, "##sys#message", msg);
 4643
 4644  if(C_gui_mode) {
 4645    if (n >= sizeof(buffer))
 4646      n = sizeof(buffer) - 1;
 4647    C_strncpy(buffer, C_c_string(m), n);
 4648    buffer[ n ] = '\0';
 4649#if defined(_WIN32) && !defined(__CYGWIN__)
 4650    MessageBox(NULL, buffer, C_text("CHICKEN runtime"), MB_OK | MB_ICONEXCLAMATION);
 4651    return C_SCHEME_UNDEFINED;
 4652#endif
 4653  } /* fall through */
 4654
 4655  C_fwrite(C_c_string(m), n, sizeof(C_char), stdout);
 4656  C_putchar('\n');
 4657  return C_SCHEME_UNDEFINED;
 4658}
 4659
 4660
 4661C_regparm C_word C_equalp(C_word x, C_word y)
 4662{
 4663  C_header header;
 4664  C_word bits, n, i;
 4665
 4666  C_stack_check1(barf(C_CIRCULAR_DATA_ERROR, "equal?"));
 4667
 4668 loop:
 4669  if(x == y) return 1;
 4670
 4671  if(C_immediatep(x) || C_immediatep(y)) return 0;
 4672
 4673  /* NOTE: Extra check at the end is special consideration for pairs being equal to weak pairs */
 4674  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;
 4675  else if((bits = header & C_HEADER_BITS_MASK) & C_BYTEBLOCK_BIT) {
 4676    if(header == C_FLONUM_TAG && C_block_header(y) == C_FLONUM_TAG)
 4677      return C_ub_i_flonum_eqvp(C_flonum_magnitude(x),
 4678                                C_flonum_magnitude(y));
 4679    else return !C_memcmp(C_data_pointer(x), C_data_pointer(y), header & C_HEADER_SIZE_MASK);
 4680  }
 4681  else if(C_header_bits(x) == C_STRING_TYPE)
 4682    return C_equalp(C_block_item(x, 0), C_block_item(y, 0));
 4683  else if(header == C_SYMBOL_TAG) return 0;
 4684  else {
 4685    i = 0;
 4686    n = header & C_HEADER_SIZE_MASK;
 4687
 4688    if(bits & C_SPECIALBLOCK_BIT) {
 4689      /* do not recurse into closures */
 4690      if(C_header_bits(x) == C_CLOSURE_TYPE)
 4691	return !C_memcmp(C_data_pointer(x), C_data_pointer(y), n * sizeof(C_word));
 4692      else if(C_block_item(x, 0) != C_block_item(y, 0)) return 0;
 4693      else ++i;
 4694
 4695      if(n == 1) return 1;
 4696    }
 4697
 4698    if(--n < 0) return 1;
 4699
 4700    while(i < n)
 4701      if(!C_equalp(C_block_item(x, i), C_block_item(y, i))) return 0;
 4702      else ++i;
 4703
 4704    x = C_block_item(x, i);
 4705    y = C_block_item(y, i);
 4706    goto loop;
 4707  }
 4708}
 4709
 4710
 4711C_regparm C_word C_set_gc_report(C_word flag)
 4712{
 4713  if(flag == C_SCHEME_FALSE) gc_report_flag = 0;
 4714  else if(flag == C_SCHEME_TRUE) gc_report_flag = 2;
 4715  else gc_report_flag = 1;
 4716
 4717  return C_SCHEME_UNDEFINED;
 4718}
 4719
 4720C_regparm C_word C_i_accumulated_gc_time(void)
 4721{
 4722  double tgc;
 4723
 4724  tgc = timer_accumulated_gc_ms;
 4725  timer_accumulated_gc_ms = 0;
 4726  return C_fix(tgc);
 4727}
 4728
 4729C_regparm C_word C_start_timer(void)
 4730{
 4731  tracked_mutation_count = 0;
 4732  mutation_count = 0;
 4733  gc_count_1_total = 0;
 4734  gc_count_2 = 0;
 4735  timer_start_ms = C_cpu_milliseconds();
 4736  gc_ms = 0;
 4737  maximum_heap_usage = 0;
 4738  return C_SCHEME_UNDEFINED;
 4739}
 4740
 4741
 4742void C_ccall C_stop_timer(C_word c, C_word *av)
 4743{
 4744  C_word
 4745    closure = av[ 0 ],
 4746    k = av[ 1 ];
 4747  double t0 = C_cpu_milliseconds() - timer_start_ms;
 4748  C_word
 4749    ab[ WORDS_PER_FLONUM * 2 + C_SIZEOF_BIGNUM(1) + C_SIZEOF_VECTOR(7) ],
 4750    *a = ab,
 4751    elapsed = C_flonum(&a, t0 / 1000.0),
 4752    gc_time = C_flonum(&a, gc_ms / 1000.0),
 4753    heap_usage = C_unsigned_int_to_num(&a, maximum_heap_usage),
 4754    info;
 4755
 4756  info = C_vector(&a, 7, elapsed, gc_time, C_fix(mutation_count),
 4757                  C_fix(tracked_mutation_count), C_fix(gc_count_1_total),
 4758		  C_fix(gc_count_2), heap_usage);
 4759  C_kontinue(k, info);
 4760}
 4761
 4762
 4763C_word C_exit_runtime(C_word code)
 4764{
 4765  C_fflush(NULL);
 4766  C__exit(C_unfix(code));
 4767}
 4768
 4769
 4770C_regparm C_word C_set_print_precision(C_word n)
 4771{
 4772  flonum_print_precision = C_unfix(n);
 4773  return C_SCHEME_UNDEFINED;
 4774}
 4775
 4776
 4777C_regparm C_word C_get_print_precision(void)
 4778{
 4779  return C_fix(flonum_print_precision);
 4780}
 4781
 4782
 4783C_regparm C_word C_read_char(C_word port)
 4784{
 4785  C_FILEPTR fp = C_port_file(port);
 4786  C_char buf[ 5 ];
 4787  int n = 0, r, c;
 4788
 4789  do {
 4790    c = C_getc(fp);
 4791
 4792    if(c == EOF) {
 4793        if(ferror(fp)) {
 4794            clearerr(fp);
 4795            if(n == 0) return C_fix(-1);
 4796        }
 4797    /* Found here:
 4798       http://mail.python.org/pipermail/python-bugs-list/2002-July/012579.html */
 4799#if defined(_WIN32) && !defined(__CYGWIN__)
 4800        else if(GetLastError() == ERROR_OPERATION_ABORTED) {
 4801            if(n == 0) return C_fix(-1);
 4802        }
 4803#endif
 4804        else if(n == 0) return C_SCHEME_END_OF_FILE;
 4805    }
 4806
 4807    if(n == 0) r = C_utf_expect(c);
 4808    buf[ n++ ] = c;
 4809  } while(n < r);
 4810
 4811  return C_utf_decode_ptr(buf);
 4812}
 4813
 4814
 4815C_regparm C_word C_execute_shell_command(C_word string)
 4816{
 4817  C_word bv = C_block_item(string, 0);
 4818  int n = C_header_size(bv);
 4819  char *buf = buffer;
 4820
 4821  /* Windows doc says to flush all output streams before calling system.
 4822     Probably a good idea for all platforms. */
 4823  (void)fflush(NULL);
 4824
 4825  if(n >= STRING_BUFFER_SIZE) {
 4826    if((buf = (char *)C_malloc(n + 1)) == NULL)
 4827      barf(C_OUT_OF_MEMORY_ERROR, "system");
 4828  }
 4829
 4830  C_memcpy(buf, C_data_pointer(bv), n); /* includes 0 */
 4831  if (n - 1 != strlen(buf))
 4832    barf(C_ASCIIZ_REPRESENTATION_ERROR, "system", string);
 4833
 4834  n = C_system(C_OS_FILENAME(bv, 0));
 4835
 4836  if(buf != buffer) C_free(buf);
 4837
 4838  return C_fix(n);
 4839}
 4840
 4841/*
 4842 * TODO: Implement something for Windows that supports selecting on
 4843 * arbitrary fds (there, select() only works on network sockets and
 4844 * poll() is not available at all).
 4845 */
 4846C_regparm int C_check_fd_ready(int fd)
 4847{
 4848#ifdef NO_POSIX_POLL
 4849  fd_set in;
 4850  struct timeval tm;
 4851  int rv;
 4852  FD_ZERO(&in);
 4853  FD_SET(fd, &in);
 4854  tm.tv_sec = tm.tv_usec = 0;
 4855  rv = select(fd + 1, &in, NULL, NULL, &tm);
 4856  if(rv > 0) { rv = FD_ISSET(fd, &in) ? 1 : 0; }
 4857  return rv;
 4858#else
 4859  struct pollfd ps;
 4860  ps.fd = fd;
 4861  ps.events = POLLIN;
 4862  return poll(&ps, 1, 0);
 4863#endif
 4864}
 4865
 4866C_regparm C_word C_char_ready_p(C_word port)
 4867{
 4868#if defined(C_NONUNIX)
 4869  /* The best we can currently do on Windows... */
 4870  return C_SCHEME_TRUE;
 4871#else
 4872  int fd = C_fileno(C_port_file(port));
 4873  return C_mk_bool(C_check_fd_ready(fd) == 1);
 4874#endif
 4875}
 4876
 4877C_regparm C_word C_i_tty_forcedp(void)
 4878{
 4879  return C_mk_bool(fake_tty_flag);
 4880}
 4881
 4882C_regparm C_word C_i_debug_modep(void)
 4883{
 4884  return C_mk_bool(debug_mode);
 4885}
 4886
 4887C_regparm C_word C_i_dump_heap_on_exitp(void)
 4888{
 4889  return C_mk_bool(dump_heap_on_exit);
 4890}
 4891
 4892C_regparm C_word C_i_profilingp(void)
 4893{
 4894  return C_mk_bool(profiling);
 4895}
 4896
 4897C_regparm C_word C_i_live_finalizer_count(void)
 4898{
 4899  return C_fix(live_finalizer_count);
 4900}
 4901
 4902C_regparm C_word C_i_allocated_finalizer_count(void)
 4903{
 4904  return C_fix(allocated_finalizer_count);
 4905}
 4906
 4907
 4908C_regparm void C_raise_interrupt(int reason)
 4909{
 4910  if(C_interrupts_enabled) {
 4911    if(pending_interrupts_count == 0 && !handling_interrupts) {
 4912      pending_interrupts[ pending_interrupts_count++ ] = reason;
 4913      /*
 4914       * Force the next "soft" stack check to fail by faking a "full"
 4915       * stack.  This causes save_and_reclaim() to be called, which
 4916       * invokes handle_interrupt(), which restores the stack limit.
 4917       */
 4918      C_stack_limit = stack_bottom;
 4919      interrupt_time = C_cpu_milliseconds();
 4920    } else if(pending_interrupts_count < MAX_PENDING_INTERRUPTS) {
 4921      int i;
 4922      /*
 4923       * Drop signals if too many, but don't queue up multiple entries
 4924       * for the same signal.
 4925       */
 4926      for (i = 0; i < pending_interrupts_count; ++i) {
 4927        if (pending_interrupts[i] == reason)
 4928          return;
 4929      }
 4930      pending_interrupts[ pending_interrupts_count++ ] = reason;
 4931    }
 4932  }
 4933}
 4934
 4935
 4936C_regparm C_word C_enable_interrupts(void)
 4937{
 4938  C_timer_interrupt_counter = C_initial_timer_interrupt_period;
 4939  /* assert(C_timer_interrupt_counter > 0); */
 4940  C_interrupts_enabled = 1;
 4941  return C_SCHEME_UNDEFINED;
 4942}
 4943
 4944
 4945C_regparm C_word C_disable_interrupts(void)
 4946{
 4947  C_interrupts_enabled = 0;
 4948  return C_SCHEME_UNDEFINED;
 4949}
 4950
 4951
 4952C_regparm C_word C_establish_signal_handler(C_word signum, C_word reason)
 4953{
 4954  int sig = C_unfix(signum);
 4955#if defined(HAVE_SIGACTION)
 4956  struct sigaction newsig;
 4957#endif
 4958
 4959  if(reason == C_SCHEME_FALSE) C_signal(sig, SIG_IGN);
 4960  else if(reason == C_SCHEME_TRUE) C_signal(sig, SIG_DFL);
 4961  else {
 4962    signal_mapping_table[ sig ] = C_unfix(reason);
 4963#if defined(HAVE_SIGACTION)
 4964    newsig.sa_flags = 0;
 4965    /* The global signal handler is used for all signals, and
 4966       manipulates a single queue.  Don't allow other signals to
 4967       concurrently arrive while it's doing this, to avoid races. */
 4968    sigfillset(&newsig.sa_mask);
 4969    newsig.sa_handler = global_signal_handler;
 4970    C_sigaction(sig, &newsig, NULL);
 4971#else
 4972    C_signal(sig, global_signal_handler);
 4973#endif
 4974  }
 4975
 4976  return C_SCHEME_UNDEFINED;
 4977}
 4978
 4979
 4980/* Copy blocks into collected or static memory: */
 4981
 4982C_regparm C_word C_copy_block(C_word from, C_word to)
 4983{
 4984  int n = C_header_size(from);
 4985  C_long bytes;
 4986
 4987  if(C_header_bits(from) & C_BYTEBLOCK_BIT) {
 4988    bytes = n;
 4989    C_memcpy((C_SCHEME_BLOCK *)to, (C_SCHEME_BLOCK *)from, bytes + sizeof(C_header));
 4990  }
 4991  else {
 4992    bytes = C_wordstobytes(n);
 4993    C_memcpy((C_SCHEME_BLOCK *)to, (C_SCHEME_BLOCK *)from, bytes + sizeof(C_header));
 4994  }
 4995
 4996  return to;
 4997}
 4998
 4999
 5000C_regparm C_word C_evict_block(C_word from, C_word ptr)
 5001{
 5002  int n = C_header_size(from);
 5003  C_long bytes;
 5004  C_word *p = (C_word *)C_pointer_address(ptr);
 5005
 5006  if(C_header_bits(from) & C_BYTEBLOCK_BIT) bytes = n;
 5007  else bytes = C_wordstobytes(n);
 5008
 5009  C_memcpy(p, (C_SCHEME_BLOCK *)from, bytes + sizeof(C_header));
 5010  return (C_word)p;
 5011}
 5012
 5013
 5014/* Inline versions of some standard procedures: */
 5015
 5016C_regparm C_word C_i_listp(C_word x)
 5017{
 5018  C_word fast = x, slow = x;
 5019
 5020  while(fast != C_SCHEME_END_OF_LIST)
 5021    if(!C_immediatep(fast) && C_header_type(fast) == C_PAIR_TYPE) {
 5022      fast = C_u_i_cdr(fast);
 5023
 5024      if(fast == C_SCHEME_END_OF_LIST) return C_SCHEME_TRUE;
 5025      else if(!C_immediatep(fast) && C_header_type(fast) == C_PAIR_TYPE) {
 5026	fast = C_u_i_cdr(fast);
 5027	slow = C_u_i_cdr(slow);
 5028
 5029	if(fast == slow) return C_SCHEME_FALSE;
 5030      }
 5031      else return C_SCHEME_FALSE;
 5032    }
 5033    else return C_SCHEME_FALSE;
 5034
 5035  return C_SCHEME_TRUE;
 5036}
 5037
 5038C_regparm C_word C_i_s8vectorp(C_word x)
 5039{
 5040  return C_i_structurep(x, s8vector_symbol);
 5041}
 5042
 5043C_regparm C_word C_i_u16vectorp(C_word x)
 5044{
 5045  return C_i_structurep(x, u16vector_symbol);
 5046}
 5047
 5048C_regparm C_word C_i_s16vectorp(C_word x)
 5049{
 5050  return C_i_structurep(x, s16vector_symbol);
 5051}
 5052
 5053C_regparm C_word C_i_u32vectorp(C_word x)
 5054{
 5055  return C_i_structurep(x, u32vector_symbol);
 5056}
 5057
 5058C_regparm C_word C_i_s32vectorp(C_word x)
 5059{
 5060  return C_i_structurep(x, s32vector_symbol);
 5061}
 5062
 5063C_regparm C_word C_i_u64vectorp(C_word x)
 5064{
 5065  return C_i_structurep(x, u64vector_symbol);
 5066}
 5067
 5068C_regparm C_word C_i_s64vectorp(C_word x)
 5069{
 5070  return C_i_structurep(x, s64vector_symbol);
 5071}
 5072
 5073C_regparm C_word C_i_f32vectorp(C_word x)
 5074{
 5075  return C_i_structurep(x, f32vector_symbol);
 5076}
 5077
 5078C_regparm C_word C_i_f64vectorp(C_word x)
 5079{
 5080  return C_i_structurep(x, f64vector_symbol);
 5081}
 5082
 5083
 5084C_regparm C_word C_i_string_equal_p(C_word x, C_word y)
 5085{
 5086  if(C_immediatep(x) || C_header_bits(x) != C_STRING_TYPE)
 5087    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string=?", x);
 5088
 5089  if(C_immediatep(y) || C_header_bits(y) != C_STRING_TYPE)
 5090    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string=?", y);
 5091
 5092  return C_utf_equal(x, y);
 5093}
 5094
 5095
 5096C_regparm C_word C_i_string_ci_equal_p(C_word x, C_word y)
 5097{
 5098  if(C_immediatep(x) || C_header_bits(x) != C_STRING_TYPE)
 5099    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string-ci=?", x);
 5100
 5101  if(C_immediatep(y) || C_header_bits(y) != C_STRING_TYPE)
 5102    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string-ci=?", y);
 5103
 5104  return C_utf_equal_ci(x, y);
 5105}
 5106
 5107
 5108C_word C_a_i_list(C_word **a, int c, ...)
 5109{
 5110  va_list v;
 5111  C_word x, last, current,
 5112         first = C_SCHEME_END_OF_LIST;
 5113
 5114  va_start(v, c);
 5115
 5116  for(last = C_SCHEME_UNDEFINED; c--; last = current) {
 5117    x = va_arg(v, C_word);
 5118    current = C_a_pair(a, x, C_SCHEME_END_OF_LIST);
 5119
 5120    if(last != C_SCHEME_UNDEFINED)
 5121      C_set_block_item(last, 1, current);
 5122    else first = current;
 5123  }
 5124
 5125  va_end(v);
 5126  return first;
 5127}
 5128
 5129
 5130C_word C_a_i_string(C_word **a, int c, ...)
 5131{
 5132  va_list v;
 5133  C_word x, s, b;
 5134  char *p;
 5135  int len;
 5136
 5137  s = (C_word)(*a);
 5138  *a = (C_word *)((C_word)(*a) + sizeof(C_word) * 5); /* C_SIZEOF_STRING */
 5139  b = (C_word)(*a);
 5140
 5141  C_block_header_init(s, C_STRING_TAG);
 5142  C_set_block_item(s, 0, b);
 5143  C_set_block_item(s, 1, C_fix(c));
 5144  C_set_block_item(s, 2, C_fix(0));
 5145  C_set_block_item(s, 3, C_fix(0));
 5146  p = (char *)C_data_pointer(b);
 5147  va_start(v, c);
 5148
 5149  for(; c; c--) {
 5150    x = va_arg(v, C_word);
 5151
 5152    if((x & C_IMMEDIATE_TYPE_BITS) == C_CHARACTER_BITS)
 5153      p = C_utf_encode(p, C_character_code(x));
 5154    else break;
 5155  }
 5156
 5157  len = p - (char *)C_data_pointer(b) + 1;
 5158  *a = (C_word *)((C_word)(*a) + sizeof(C_header) + C_align(len));
 5159  *p = '\0';
 5160  C_block_header_init(b, C_BYTEVECTOR_TYPE | len);
 5161  va_end(v);
 5162  if (c) barf(C_BAD_ARGUMENT_TYPE_ERROR, "string", x);
 5163  return s;
 5164}
 5165
 5166
 5167C_word C_a_i_record(C_word **ptr, int n, ...)
 5168{
 5169  va_list v;
 5170  C_word *p = *ptr,
 5171         *p0 = p;
 5172
 5173  *(p++) = C_STRUCTURE_TYPE | n;
 5174  va_start(v, n);
 5175
 5176  while(n--)
 5177    *(p++) = va_arg(v, C_word);
 5178
 5179  *ptr = p;
 5180  va_end(v);
 5181  return (C_word)p0;
 5182}
 5183
 5184
 5185C_word C_a_i_port(C_word **ptr, int n)
 5186{
 5187  C_word
 5188    *p = *ptr,
 5189    *p0 = p;
 5190  int i;
 5191
 5192  *(p++) = C_PORT_TYPE | (C_SIZEOF_PORT - 1);
 5193  *(p++) = (C_word)NULL;
 5194
 5195  for(i = 0; i < C_SIZEOF_PORT - 2; ++i)
 5196    *(p++) = C_SCHEME_FALSE;
 5197
 5198  *ptr = p;
 5199  return (C_word)p0;
 5200}
 5201
 5202
 5203C_regparm C_word C_a_i_bytevector(C_word **ptr, int c, C_word num)
 5204{
 5205  C_word *p = *ptr,
 5206         *p0;
 5207  int n = C_unfix(num);
 5208
 5209#ifndef C_SIXTY_FOUR
 5210  /* Align on 8-byte boundary: */
 5211  if(C_aligned8(p)) ++p;
 5212#endif
 5213
 5214  p0 = p;
 5215  *(p++) = C_BYTEVECTOR_TYPE | C_wordstobytes(n);
 5216  *ptr = p + n;
 5217  return (C_word)p0;
 5218}
 5219
 5220
 5221C_word C_a_i_smart_mpointer(C_word **ptr, int c, C_word x)
 5222{
 5223  C_word
 5224    *p = *ptr,
 5225    *p0 = p;
 5226  void *mp;
 5227
 5228  if(C_immediatep(x)) mp = NULL;
 5229  else if((C_header_bits(x) & C_SPECIALBLOCK_BIT) != 0) mp = C_pointer_address(x);
 5230  else mp = C_data_pointer(x);
 5231
 5232  *(p++) = C_POINTER_TYPE | 1;
 5233  *((void **)p) = mp;
 5234  *ptr = p + 1;
 5235  return (C_word)p0;
 5236}
 5237
 5238C_regparm C_word C_i_nanp(C_word x)
 5239{
 5240  if (x & C_FIXNUM_BIT) {
 5241    return C_SCHEME_FALSE;
 5242  } else if (C_immediatep(x)) {
 5243    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "nan?", x);
 5244  } else if (C_block_header(x) == C_FLONUM_TAG) {
 5245    return C_u_i_flonum_nanp(x);
 5246  } else if (C_truep(C_bignump(x))) {
 5247    return C_SCHEME_FALSE;
 5248  } else if (C_block_header(x) == C_RATNUM_TAG) {
 5249    return C_SCHEME_FALSE;
 5250  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 5251    return C_mk_bool(C_truep(C_i_nanp(C_u_i_cplxnum_real(x))) ||
 5252		     C_truep(C_i_nanp(C_u_i_cplxnum_imag(x))));
 5253  } else {
 5254    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "nan?", x);
 5255  }
 5256}
 5257
 5258C_regparm C_word C_i_finitep(C_word x)
 5259{
 5260  if (x & C_FIXNUM_BIT) {
 5261    return C_SCHEME_TRUE;
 5262  } else if (C_immediatep(x)) {
 5263    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "finite?", x);
 5264  } else if (C_block_header(x) == C_FLONUM_TAG) {
 5265    return C_u_i_flonum_finitep(x);
 5266  } else if (C_truep(C_bignump(x))) {
 5267    return C_SCHEME_TRUE;
 5268  } else if (C_block_header(x) == C_RATNUM_TAG) {
 5269    return C_SCHEME_TRUE;
 5270  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 5271    return C_and(C_i_finitep(C_u_i_cplxnum_real(x)),
 5272		 C_i_finitep(C_u_i_cplxnum_imag(x)));
 5273  } else {
 5274    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "finite?", x);
 5275  }
 5276}
 5277
 5278C_regparm C_word C_i_infinitep(C_word x)
 5279{
 5280  if (x & C_FIXNUM_BIT) {
 5281    return C_SCHEME_FALSE;
 5282  } else if (C_immediatep(x)) {
 5283    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "infinite?", x);
 5284  } else if (C_block_header(x) == C_FLONUM_TAG) {
 5285    return C_u_i_flonum_infinitep(x);
 5286  } else if (C_truep(C_bignump(x))) {
 5287    return C_SCHEME_FALSE;
 5288  } else if (C_block_header(x) == C_RATNUM_TAG) {
 5289    return C_SCHEME_FALSE;
 5290  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 5291    return C_mk_bool(C_truep(C_i_infinitep(C_u_i_cplxnum_real(x))) ||
 5292                     C_truep(C_i_infinitep(C_u_i_cplxnum_imag(x))));
 5293  } else {
 5294    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "infinite?", x);
 5295  }
 5296}
 5297
 5298C_regparm C_word C_i_exactp(C_word x)
 5299{
 5300  if (x & C_FIXNUM_BIT) {
 5301    return C_SCHEME_TRUE;
 5302  } else if (C_immediatep(x)) {
 5303    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "exact?", x);
 5304  } else if (C_block_header(x) == C_FLONUM_TAG) {
 5305    return C_SCHEME_FALSE;
 5306  } else if (C_truep(C_bignump(x))) {
 5307    return C_SCHEME_TRUE;
 5308  } else if (C_block_header(x) == C_RATNUM_TAG) {
 5309    return C_SCHEME_TRUE;
 5310  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 5311    return C_i_exactp(C_u_i_cplxnum_real(x)); /* Exactness of i and r matches */
 5312  } else {
 5313    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "exact?", x);
 5314  }
 5315}
 5316
 5317
 5318C_regparm C_word C_i_inexactp(C_word x)
 5319{
 5320  if (x & C_FIXNUM_BIT) {
 5321    return C_SCHEME_FALSE;
 5322  } else if (C_immediatep(x)) {
 5323    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "inexact?", x);
 5324  } else if (C_block_header(x) == C_FLONUM_TAG) {
 5325    return C_SCHEME_TRUE;
 5326  } else if (C_truep(C_bignump(x))) {
 5327    return C_SCHEME_FALSE;
 5328  } else if (C_block_header(x) == C_RATNUM_TAG) {
 5329    return C_SCHEME_FALSE;
 5330  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 5331    return C_i_inexactp(C_u_i_cplxnum_real(x)); /* Exactness of i and r matches */
 5332  } else {
 5333    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "inexact?", x);
 5334  }
 5335}
 5336
 5337
 5338C_regparm C_word C_i_zerop(C_word x)
 5339{
 5340  if (x & C_FIXNUM_BIT) {
 5341    return C_mk_bool(x == C_fix(0));
 5342  } else if (C_immediatep(x)) {
 5343    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "zero?", x);
 5344  } else if (C_block_header(x) == C_FLONUM_TAG) {
 5345    return C_mk_bool(C_flonum_magnitude(x) == 0.0);
 5346  } else if (C_block_header(x) == C_BIGNUM_TAG ||
 5347             C_block_header(x) == C_RATNUM_TAG ||
 5348             C_block_header(x) == C_CPLXNUM_TAG) {
 5349    return C_SCHEME_FALSE;
 5350  } else {
 5351    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "zero?", x);
 5352  }
 5353}
 5354
 5355/* DEPRECATED */
 5356C_regparm C_word C_u_i_zerop(C_word x)
 5357{
 5358  return C_mk_bool(x == C_fix(0) ||
 5359                   (!C_immediatep(x) &&
 5360                    C_block_header(x) == C_FLONUM_TAG &&
 5361                    C_flonum_magnitude(x) == 0.0));
 5362}
 5363
 5364
 5365C_regparm C_word C_i_positivep(C_word x)
 5366{
 5367  if (x & C_FIXNUM_BIT)
 5368    return C_i_fixnum_positivep(x);
 5369  else if (C_immediatep(x))
 5370    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "positive?", x);
 5371  else if (C_block_header(x) == C_FLONUM_TAG)
 5372    return C_mk_bool(C_flonum_magnitude(x) > 0.0);
 5373  else if (C_truep(C_bignump(x)))
 5374    return C_mk_nbool(C_bignum_negativep(x));
 5375  else if (C_block_header(x) == C_RATNUM_TAG)
 5376    return C_i_integer_positivep(C_u_i_ratnum_num(x));
 5377  else if (C_block_header(x) == C_CPLXNUM_TAG)
 5378    barf(C_BAD_ARGUMENT_TYPE_NO_REAL_ERROR, "positive?", x);
 5379  else
 5380    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "positive?", x);
 5381}
 5382
 5383C_regparm C_word C_i_integer_positivep(C_word x)
 5384{
 5385  if (x & C_FIXNUM_BIT) return C_i_fixnum_positivep(x);
 5386  else return C_mk_nbool(C_bignum_negativep(x));
 5387}
 5388
 5389C_regparm C_word C_i_negativep(C_word x)
 5390{
 5391  if (x & C_FIXNUM_BIT)
 5392    return C_i_fixnum_negativep(x);
 5393  else if (C_immediatep(x))
 5394    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "negative?", x);
 5395  else if (C_block_header(x) == C_FLONUM_TAG)
 5396    return C_mk_bool(C_flonum_magnitude(x) < 0.0);
 5397  else if (C_truep(C_bignump(x)))
 5398    return C_mk_bool(C_bignum_negativep(x));
 5399  else if (C_block_header(x) == C_RATNUM_TAG)
 5400    return C_i_integer_negativep(C_u_i_ratnum_num(x));
 5401  else if (C_block_header(x) == C_CPLXNUM_TAG)
 5402    barf(C_BAD_ARGUMENT_TYPE_NO_REAL_ERROR, "negative?", x);
 5403  else
 5404    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "negative?", x);
 5405}
 5406
 5407
 5408C_regparm C_word C_i_integer_negativep(C_word x)
 5409{
 5410  if (x & C_FIXNUM_BIT) return C_i_fixnum_negativep(x);
 5411  else return C_mk_bool(C_bignum_negativep(x));
 5412}
 5413
 5414
 5415C_regparm C_word C_i_evenp(C_word x)
 5416{
 5417  if(x & C_FIXNUM_BIT) {
 5418    return C_i_fixnumevenp(x);
 5419  } else if(C_immediatep(x)) {
 5420    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "even?", x);
 5421  } else if (C_block_header(x) == C_FLONUM_TAG) {
 5422    double val, dummy;
 5423    val = C_flonum_magnitude(x);
 5424    if(C_isnan(val) || C_isinf(val) || C_modf(val, &dummy) != 0.0)
 5425      barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "even?", x);
 5426    else
 5427      return C_mk_bool(fmod(val, 2.0) == 0.0);
 5428  } else if (C_truep(C_bignump(x))) {
 5429    return C_mk_nbool(C_bignum_digits(x)[0] & 1);
 5430  } else { /* No need to try extended number */
 5431    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "even?", x);
 5432  }
 5433}
 5434
 5435C_regparm C_word C_i_integer_evenp(C_word x)
 5436{
 5437  if (x & C_FIXNUM_BIT) return C_i_fixnumevenp(x);
 5438  return C_mk_nbool(C_bignum_digits(x)[0] & 1);
 5439}
 5440
 5441
 5442C_regparm C_word C_i_oddp(C_word x)
 5443{
 5444  if(x & C_FIXNUM_BIT) {
 5445    return C_i_fixnumoddp(x);
 5446  } else if(C_immediatep(x)) {
 5447    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "odd?", x);
 5448  } else if(C_block_header(x) == C_FLONUM_TAG) {
 5449    double val, dummy;
 5450    val = C_flonum_magnitude(x);
 5451    if(C_isnan(val) || C_isinf(val) || C_modf(val, &dummy) != 0.0)
 5452      barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "odd?", x);
 5453    else
 5454      return C_mk_bool(fmod(val, 2.0) != 0.0);
 5455  } else if (C_truep(C_bignump(x))) {
 5456    return C_mk_bool(C_bignum_digits(x)[0] & 1);
 5457  } else {
 5458    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "odd?", x);
 5459  }
 5460}
 5461
 5462
 5463C_regparm C_word C_i_integer_oddp(C_word x)
 5464{
 5465  if (x & C_FIXNUM_BIT) return C_i_fixnumoddp(x);
 5466  return C_mk_bool(C_bignum_digits(x)[0] & 1);
 5467}
 5468
 5469
 5470C_regparm C_word C_i_car(C_word x)
 5471{
 5472  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE)
 5473    barf(C_BAD_ARGUMENT_TYPE_ERROR, "car", x);
 5474
 5475  return C_u_i_car(x);
 5476}
 5477
 5478
 5479C_regparm C_word C_i_cdr(C_word x)
 5480{
 5481  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE)
 5482    barf(C_BAD_ARGUMENT_TYPE_ERROR, "cdr", x);
 5483
 5484  return C_u_i_cdr(x);
 5485}
 5486
 5487
 5488C_regparm C_word C_i_caar(C_word x)
 5489{
 5490  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 5491  bad:
 5492    barf(C_BAD_ARGUMENT_TYPE_ERROR, "caar", x);
 5493  }
 5494
 5495  x = C_u_i_car(x);
 5496
 5497  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5498
 5499  return C_u_i_car(x);
 5500}
 5501
 5502
 5503C_regparm C_word C_i_cadr(C_word x)
 5504{
 5505  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 5506  bad:
 5507    barf(C_BAD_ARGUMENT_TYPE_ERROR, "cadr", x);
 5508  }
 5509
 5510  x = C_u_i_cdr(x);
 5511
 5512  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5513
 5514  return C_u_i_car(x);
 5515}
 5516
 5517
 5518C_regparm C_word C_i_cdar(C_word x)
 5519{
 5520  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 5521  bad:
 5522    barf(C_BAD_ARGUMENT_TYPE_ERROR, "cdar", x);
 5523  }
 5524
 5525  x = C_u_i_car(x);
 5526
 5527  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5528
 5529  return C_u_i_cdr(x);
 5530}
 5531
 5532
 5533C_regparm C_word C_i_cddr(C_word x)
 5534{
 5535  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 5536  bad:
 5537    barf(C_BAD_ARGUMENT_TYPE_ERROR, "cddr", x);
 5538  }
 5539
 5540  x = C_u_i_cdr(x);
 5541  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5542
 5543  return C_u_i_cdr(x);
 5544}
 5545
 5546
 5547C_regparm C_word C_i_caddr(C_word x)
 5548{
 5549  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 5550  bad:
 5551    barf(C_BAD_ARGUMENT_TYPE_ERROR, "caddr", x);
 5552  }
 5553
 5554  x = C_u_i_cdr(x);
 5555  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5556  x = C_u_i_cdr(x);
 5557  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5558
 5559  return C_u_i_car(x);
 5560}
 5561
 5562
 5563C_regparm C_word C_i_cdddr(C_word x)
 5564{
 5565  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 5566  bad:
 5567    barf(C_BAD_ARGUMENT_TYPE_ERROR, "cdddr", x);
 5568  }
 5569
 5570  x = C_u_i_cdr(x);
 5571  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5572  x = C_u_i_cdr(x);
 5573  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5574
 5575  return C_u_i_cdr(x);
 5576}
 5577
 5578
 5579C_regparm C_word C_i_cadddr(C_word x)
 5580{
 5581  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 5582  bad:
 5583    barf(C_BAD_ARGUMENT_TYPE_ERROR, "cadddr", x);
 5584  }
 5585
 5586  x = C_u_i_cdr(x);
 5587  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5588  x = C_u_i_cdr(x);
 5589  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5590  x = C_u_i_cdr(x);
 5591  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5592
 5593  return C_u_i_car(x);
 5594}
 5595
 5596
 5597C_regparm C_word C_i_cddddr(C_word x)
 5598{
 5599  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 5600  bad:
 5601    barf(C_BAD_ARGUMENT_TYPE_ERROR, "cddddr", x);
 5602  }
 5603
 5604  x = C_u_i_cdr(x);
 5605  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5606  x = C_u_i_cdr(x);
 5607  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5608  x = C_u_i_cdr(x);
 5609  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) goto bad;
 5610
 5611  return C_u_i_cdr(x);
 5612}
 5613
 5614
 5615C_regparm C_word C_i_list_tail(C_word lst, C_word i)
 5616{
 5617  C_word lst0 = lst;
 5618  int n;
 5619
 5620  if(lst != C_SCHEME_END_OF_LIST &&
 5621     (C_immediatep(lst) || C_header_type(lst) != C_PAIR_TYPE))
 5622    barf(C_BAD_ARGUMENT_TYPE_ERROR, "list-tail", lst);
 5623
 5624  if(i & C_FIXNUM_BIT) n = C_unfix(i);
 5625  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "list-tail", i);
 5626
 5627  while(n--) {
 5628    if(C_immediatep(lst) || C_header_type(lst) != C_PAIR_TYPE)
 5629      barf(C_OUT_OF_BOUNDS_ERROR, "list-tail", lst0, i);
 5630
 5631    lst = C_u_i_cdr(lst);
 5632  }
 5633
 5634  return lst;
 5635}
 5636
 5637
 5638C_regparm C_word C_i_vector_ref(C_word v, C_word i)
 5639{
 5640  int j;
 5641
 5642  if(C_immediatep(v) || C_header_bits(v) != C_VECTOR_TYPE)
 5643    barf(C_BAD_ARGUMENT_TYPE_ERROR, "vector-ref", v);
 5644
 5645  if(i & C_FIXNUM_BIT) {
 5646    j = C_unfix(i);
 5647
 5648    if(j < 0 || j >= C_header_size(v)) barf(C_OUT_OF_BOUNDS_ERROR, "vector-ref", v, i);
 5649
 5650    return C_block_item(v, j);
 5651  }
 5652
 5653  barf(C_BAD_ARGUMENT_TYPE_ERROR, "vector-ref", i);
 5654  return C_SCHEME_UNDEFINED;
 5655}
 5656
 5657C_regparm C_word C_i_bytevector_ref(C_word v, C_word i)
 5658{
 5659  int j;
 5660
 5661  if(!C_truep(C_bytevectorp(v)))
 5662    barf(C_BAD_ARGUMENT_TYPE_ERROR, "bytevector-u8-ref", v);
 5663
 5664  if(i & C_FIXNUM_BIT) {
 5665    j = C_unfix(i);
 5666
 5667    if(j < 0 || j >= C_header_size(v))
 5668    	barf(C_OUT_OF_BOUNDS_ERROR, "bytevector-u8-ref", v, i);
 5669
 5670    return C_fix(((unsigned char *)C_data_pointer(v))[j]);
 5671  }
 5672
 5673  barf(C_BAD_ARGUMENT_TYPE_ERROR, "bytevector-u8-ref", i);
 5674  return C_SCHEME_UNDEFINED;
 5675}
 5676
 5677C_regparm C_word C_i_s8vector_ref(C_word v, C_word i)
 5678{
 5679  int j;
 5680
 5681  if(!C_truep(C_i_s8vectorp(v)))
 5682    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s8vector-ref", v);
 5683
 5684  if(i & C_FIXNUM_BIT) {
 5685    j = C_unfix(i);
 5686
 5687    if(j < 0 || j >= C_header_size(C_block_item(v, 1)))
 5688    	barf(C_OUT_OF_BOUNDS_ERROR, "s8vector-ref", v, i);
 5689
 5690    return C_fix(((signed char *)C_data_pointer(C_block_item(v, 1)))[j]);
 5691  }
 5692
 5693  barf(C_BAD_ARGUMENT_TYPE_ERROR, "s8vector-ref", i);
 5694  return C_SCHEME_UNDEFINED;
 5695}
 5696
 5697C_regparm C_word C_i_u16vector_ref(C_word v, C_word i)
 5698{
 5699  int j;
 5700
 5701  if(!C_truep(C_i_u16vectorp(v)))
 5702    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u16vector-ref", v);
 5703
 5704  if(i & C_FIXNUM_BIT) {
 5705    j = C_unfix(i);
 5706
 5707    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 1))
 5708    	barf(C_OUT_OF_BOUNDS_ERROR, "u16vector-ref", v, i);
 5709
 5710    return C_fix(((unsigned short *)C_data_pointer(C_block_item(v, 1)))[j]);
 5711  }
 5712
 5713  barf(C_BAD_ARGUMENT_TYPE_ERROR, "u16vector-ref", i);
 5714  return C_SCHEME_UNDEFINED;
 5715}
 5716
 5717C_regparm C_word C_i_s16vector_ref(C_word v, C_word i)
 5718{
 5719  C_word size;
 5720  int j;
 5721
 5722  if(C_immediatep(v) || C_header_bits(v) != C_STRUCTURE_TYPE ||
 5723     C_header_size(v) != 2 || C_block_item(v, 0) != s16vector_symbol)
 5724    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s16vector-ref", v);
 5725
 5726  if(i & C_FIXNUM_BIT) {
 5727    j = C_unfix(i);
 5728
 5729    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 1))
 5730    	barf(C_OUT_OF_BOUNDS_ERROR, "u16vector-ref", v, i);
 5731
 5732    return C_fix(((signed short *)C_data_pointer(C_block_item(v, 1)))[j]);
 5733  }
 5734
 5735  barf(C_BAD_ARGUMENT_TYPE_ERROR, "s16vector-ref", i);
 5736  return C_SCHEME_UNDEFINED;
 5737}
 5738
 5739C_regparm C_word C_a_i_u32vector_ref(C_word **ptr, C_word c, C_word v, C_word i)
 5740{
 5741  int j;
 5742
 5743  if(!C_truep(C_i_u32vectorp(v)))
 5744    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u32vector-ref", v);
 5745
 5746  if(i & C_FIXNUM_BIT) {
 5747    j = C_unfix(i);
 5748
 5749    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 2))
 5750    	barf(C_OUT_OF_BOUNDS_ERROR, "u32vector-ref", v, i);
 5751
 5752    return C_unsigned_int_to_num(ptr, ((C_u32 *)C_data_pointer(C_block_item(v, 1)))[j]);
 5753  }
 5754
 5755  barf(C_BAD_ARGUMENT_TYPE_ERROR, "u32vector-ref", i);
 5756  return C_SCHEME_UNDEFINED;
 5757}
 5758
 5759C_regparm C_word C_a_i_s32vector_ref(C_word **ptr, C_word c, C_word v, C_word i)
 5760{
 5761  int j;
 5762
 5763  if(!C_truep(C_i_s32vectorp(v)))
 5764    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s32vector-ref", v);
 5765
 5766  if(i & C_FIXNUM_BIT) {
 5767    j = C_unfix(i);
 5768
 5769    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 2))
 5770    	barf(C_OUT_OF_BOUNDS_ERROR, "s32vector-ref", v, i);
 5771
 5772    return C_int_to_num(ptr, ((C_s32 *)C_data_pointer(C_block_item(v, 1)))[j]);
 5773  }
 5774
 5775  barf(C_BAD_ARGUMENT_TYPE_ERROR, "s32vector-ref", i);
 5776  return C_SCHEME_UNDEFINED;
 5777}
 5778
 5779C_regparm C_word C_a_i_u64vector_ref(C_word **ptr, C_word c, C_word v, C_word i)
 5780{
 5781  int j;
 5782
 5783  if(!C_truep(C_i_u64vectorp(v)))
 5784    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u64vector-ref", v);
 5785
 5786  if(i & C_FIXNUM_BIT) {
 5787    j = C_unfix(i);
 5788
 5789    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 3))
 5790    	barf(C_OUT_OF_BOUNDS_ERROR, "u64vector-ref", v, i);
 5791
 5792    return C_uint64_to_num(ptr, ((C_u64 *)C_data_pointer(C_block_item(v, 1)))[j]);
 5793  }
 5794
 5795  barf(C_BAD_ARGUMENT_TYPE_ERROR, "u64vector-ref", i);
 5796  return C_SCHEME_UNDEFINED;
 5797}
 5798
 5799C_regparm C_word C_a_i_s64vector_ref(C_word **ptr, C_word c, C_word v, C_word i)
 5800{
 5801  int j;
 5802
 5803  if(!C_truep(C_i_s64vectorp(v)))
 5804    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s64vector-ref", v);
 5805
 5806  if(i & C_FIXNUM_BIT) {
 5807    j = C_unfix(i);
 5808
 5809    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 3))
 5810    	barf(C_OUT_OF_BOUNDS_ERROR, "s64vector-ref", v, i);
 5811
 5812    return C_int64_to_num(ptr, ((C_s64 *)C_data_pointer(C_block_item(v, 1)))[j]);
 5813  }
 5814
 5815  barf(C_BAD_ARGUMENT_TYPE_ERROR, "s64vector-ref", i);
 5816  return C_SCHEME_UNDEFINED;
 5817}
 5818
 5819C_regparm C_word C_a_i_f32vector_ref(C_word **ptr, C_word c, C_word v, C_word i)
 5820{
 5821  int j;
 5822
 5823  if(!C_truep(C_i_f32vectorp(v)))
 5824    barf(C_BAD_ARGUMENT_TYPE_ERROR, "f32vector-ref", v);
 5825
 5826  if(i & C_FIXNUM_BIT) {
 5827    j = C_unfix(i);
 5828
 5829    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 2))
 5830    	barf(C_OUT_OF_BOUNDS_ERROR, "f32vector-ref", v, i);
 5831
 5832    return C_flonum(ptr, ((float *)C_data_pointer(C_block_item(v, 1)))[j]);
 5833  }
 5834
 5835  barf(C_BAD_ARGUMENT_TYPE_ERROR, "f32vector-ref", i);
 5836  return C_SCHEME_UNDEFINED;
 5837}
 5838
 5839C_regparm C_word C_a_i_f64vector_ref(C_word **ptr, C_word c, C_word v, C_word i)
 5840{
 5841  C_word size;
 5842  int j;
 5843
 5844  if(!C_truep(C_i_f64vectorp(v)))
 5845    barf(C_BAD_ARGUMENT_TYPE_ERROR, "f64vector-ref", v);
 5846
 5847  if(i & C_FIXNUM_BIT) {
 5848    j = C_unfix(i);
 5849
 5850    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 3))
 5851    	barf(C_OUT_OF_BOUNDS_ERROR, "f64vector-ref", v, i);
 5852
 5853    return C_flonum(ptr, ((double *)C_data_pointer(C_block_item(v, 1)))[j]);
 5854  }
 5855
 5856  barf(C_BAD_ARGUMENT_TYPE_ERROR, "f64vector-ref", i);
 5857  return C_SCHEME_UNDEFINED;
 5858}
 5859
 5860
 5861C_regparm C_word C_i_block_ref(C_word x, C_word i)
 5862{
 5863  int j;
 5864
 5865  if(C_immediatep(x) || (C_header_bits(x) & C_BYTEBLOCK_BIT) != 0)
 5866    barf(C_BAD_ARGUMENT_TYPE_NO_BLOCK_ERROR, "##sys#block-ref", x);
 5867
 5868  if(i & C_FIXNUM_BIT) {
 5869    j = C_unfix(i);
 5870
 5871    if(j < 0 || j >= C_header_size(x))
 5872    	barf(C_OUT_OF_BOUNDS_ERROR, "##sys#block-ref", x, i);
 5873
 5874    return C_block_item(x, j);
 5875  }
 5876
 5877  barf(C_BAD_ARGUMENT_TYPE_ERROR, "##sys#block-ref", i);
 5878  return C_SCHEME_UNDEFINED;
 5879}
 5880
 5881
 5882C_regparm C_word C_i_string_set(C_word s, C_word i, C_word c)
 5883{
 5884  int j;
 5885
 5886  if(C_immediatep(s) || C_header_bits(s) != C_STRING_TYPE)
 5887    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string-set!", s);
 5888
 5889  if(!C_immediatep(c) || (c & C_IMMEDIATE_TYPE_BITS) != C_CHARACTER_BITS)
 5890    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string-set!", c);
 5891
 5892  if(i & C_FIXNUM_BIT) {
 5893    j = C_unfix(i);
 5894
 5895    if(j < 0 || j >= C_unfix(C_block_item(s, 1)))
 5896        barf(C_OUT_OF_BOUNDS_ERROR, "string-set!", s, i);
 5897
 5898    return C_utf_setsubchar(s, i, c);
 5899  }
 5900
 5901  barf(C_BAD_ARGUMENT_TYPE_ERROR, "string-set!", i);
 5902  return C_SCHEME_UNDEFINED;
 5903}
 5904
 5905
 5906C_regparm C_word C_i_string_ref(C_word s, C_word i)
 5907{
 5908  int j;
 5909
 5910  if(C_immediatep(s) || C_header_bits(s) != C_STRING_TYPE)
 5911    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string-ref", s);
 5912
 5913  if(i & C_FIXNUM_BIT) {
 5914    j = C_unfix(i);
 5915
 5916    if(j < 0 || j >= C_unfix(C_block_item(s, 1)))
 5917        barf(C_OUT_OF_BOUNDS_ERROR, "string-ref", s, i);
 5918
 5919    return C_utf_subchar(s, i);
 5920  }
 5921
 5922  barf(C_BAD_ARGUMENT_TYPE_ERROR, "string-ref", i);
 5923  return C_SCHEME_UNDEFINED;
 5924}
 5925
 5926
 5927C_regparm C_word C_i_vector_length(C_word v)
 5928{
 5929  if(C_immediatep(v) || C_header_bits(v) != C_VECTOR_TYPE)
 5930    barf(C_BAD_ARGUMENT_TYPE_ERROR, "vector-length", v);
 5931
 5932  return C_fix(C_header_size(v));
 5933}
 5934
 5935C_regparm C_word C_i_bytevector_length(C_word v)
 5936{
 5937  if(C_immediatep(v) || !C_truep(C_bytevectorp(v)))
 5938    barf(C_BAD_ARGUMENT_TYPE_ERROR, "bytevector-length", v);
 5939
 5940  return C_fix(C_header_size(v));
 5941}
 5942
 5943C_regparm C_word C_i_s8vector_length(C_word v)
 5944{
 5945  if(!C_truep(C_i_s8vectorp(v)))
 5946    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s8vector-length", v);
 5947
 5948  return C_fix(C_header_size(C_block_item(v, 1)));
 5949}
 5950
 5951C_regparm C_word C_i_u16vector_length(C_word v)
 5952{
 5953  if(!C_truep(C_i_u16vectorp(v)))
 5954    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u16vector-length", v);
 5955
 5956  return C_fix(C_header_size(C_block_item(v, 1)) >> 1);
 5957}
 5958
 5959C_regparm C_word C_i_s16vector_length(C_word v)
 5960{
 5961  if(!C_truep(C_i_s16vectorp(v)))
 5962    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s16vector-length", v);
 5963
 5964  return C_fix(C_header_size(C_block_item(v, 1)) >> 1);
 5965}
 5966
 5967C_regparm C_word C_i_u32vector_length(C_word v)
 5968{
 5969  if(!C_truep(C_i_u32vectorp(v)))
 5970    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u32vector-length", v);
 5971
 5972  return C_fix(C_header_size(C_block_item(v, 1)) >> 2);
 5973}
 5974
 5975C_regparm C_word C_i_s32vector_length(C_word v)
 5976{
 5977  if(!C_truep(C_i_s32vectorp(v)))
 5978    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s32vector-length", v);
 5979
 5980  return C_fix(C_header_size(C_block_item(v, 1)) >> 2);
 5981}
 5982
 5983C_regparm C_word C_i_u64vector_length(C_word v)
 5984{
 5985  if(!C_truep(C_i_u64vectorp(v)))
 5986    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u64vector-length", v);
 5987
 5988  return C_fix(C_header_size(C_block_item(v, 1)) >> 3);
 5989}
 5990
 5991C_regparm C_word C_i_s64vector_length(C_word v)
 5992{
 5993  if(!C_truep(C_i_s64vectorp(v)))
 5994    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s64vector-length", v);
 5995
 5996  return C_fix(C_header_size(C_block_item(v, 1)) >> 3);
 5997}
 5998
 5999
 6000C_regparm C_word C_i_f32vector_length(C_word v)
 6001{
 6002  if(!C_truep(C_i_f32vectorp(v)))
 6003    barf(C_BAD_ARGUMENT_TYPE_ERROR, "f32vector-length", v);
 6004
 6005  return C_fix(C_header_size(C_block_item(v, 1)) >> 2);
 6006}
 6007
 6008C_regparm C_word C_i_f64vector_length(C_word v)
 6009{
 6010  if(!C_truep(C_i_f64vectorp(v)))
 6011    barf(C_BAD_ARGUMENT_TYPE_ERROR, "f64vector-length", v);
 6012
 6013  return C_fix(C_header_size(C_block_item(v, 1)) >> 3);
 6014}
 6015
 6016
 6017C_regparm C_word C_i_string_length(C_word s)
 6018{
 6019  if(C_immediatep(s) || C_header_bits(s) != C_STRING_TYPE)
 6020    barf(C_BAD_ARGUMENT_TYPE_ERROR, "string-length", s);
 6021
 6022  return C_block_item(s, 1);
 6023}
 6024
 6025
 6026C_regparm C_word C_i_length(C_word lst)
 6027{
 6028  C_word fast = lst, slow = lst;
 6029  int n = 0;
 6030
 6031  while(slow != C_SCHEME_END_OF_LIST) {
 6032    if(fast != C_SCHEME_END_OF_LIST) {
 6033      if(!C_immediatep(fast) && C_header_type(fast) == C_PAIR_TYPE) {
 6034	fast = C_u_i_cdr(fast);
 6035
 6036	if(fast != C_SCHEME_END_OF_LIST) {
 6037	  if(!C_immediatep(fast) && C_header_type(fast) == C_PAIR_TYPE) {
 6038	    fast = C_u_i_cdr(fast);
 6039	  }
 6040	  else barf(C_NOT_A_PROPER_LIST_ERROR, "length", lst);
 6041	}
 6042
 6043	if(fast == slow)
 6044	  barf(C_BAD_ARGUMENT_TYPE_CYCLIC_LIST_ERROR, "length", lst);
 6045      }
 6046    }
 6047
 6048    if(C_immediatep(slow) || C_header_type(slow) != C_PAIR_TYPE)
 6049      barf(C_NOT_A_PROPER_LIST_ERROR, "length", lst);
 6050
 6051    slow = C_u_i_cdr(slow);
 6052    ++n;
 6053  }
 6054
 6055  return C_fix(n);
 6056}
 6057
 6058
 6059C_regparm C_word C_u_i_length(C_word lst)
 6060{
 6061  int n = 0;
 6062
 6063  while(!C_immediatep(lst) && C_header_type(lst) == C_PAIR_TYPE) {
 6064    lst = C_u_i_cdr(lst);
 6065    ++n;
 6066  }
 6067
 6068  return C_fix(n);
 6069}
 6070
 6071C_regparm C_word C_i_set_car(C_word x, C_word val)
 6072{
 6073  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE)
 6074    barf(C_BAD_ARGUMENT_TYPE_ERROR, "set-car!", x);
 6075
 6076  C_mutate(&C_u_i_car(x), val);
 6077  return C_SCHEME_UNDEFINED;
 6078}
 6079
 6080
 6081C_regparm C_word C_i_set_cdr(C_word x, C_word val)
 6082{
 6083  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE)
 6084    barf(C_BAD_ARGUMENT_TYPE_ERROR, "set-cdr!", x);
 6085
 6086  C_mutate(&C_u_i_cdr(x), val);
 6087  return C_SCHEME_UNDEFINED;
 6088}
 6089
 6090
 6091C_regparm C_word C_i_vector_set(C_word v, C_word i, C_word x)
 6092{
 6093  int j;
 6094
 6095  if(C_immediatep(v) || C_header_bits(v) != C_VECTOR_TYPE)
 6096    barf(C_BAD_ARGUMENT_TYPE_ERROR, "vector-set!", v);
 6097
 6098  if(i & C_FIXNUM_BIT) {
 6099    j = C_unfix(i);
 6100
 6101    if(j < 0 || j >= C_header_size(v))
 6102    	barf(C_OUT_OF_BOUNDS_ERROR, "vector-set!", v, i);
 6103
 6104    C_mutate(&C_block_item(v, j), x);
 6105  }
 6106  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "vector-set!", i);
 6107
 6108  return C_SCHEME_UNDEFINED;
 6109}
 6110
 6111C_regparm C_word C_i_bytevector_set(C_word v, C_word i, C_word x)
 6112{
 6113  int j;
 6114  C_word n;
 6115
 6116  if(!C_truep(C_bytevectorp(v)))
 6117    barf(C_BAD_ARGUMENT_TYPE_ERROR, "bytevector-set!", v);
 6118
 6119  if(i & C_FIXNUM_BIT) {
 6120    j = C_unfix(i);
 6121
 6122    if(j < 0 || j >= C_header_size(v))
 6123    	barf(C_OUT_OF_BOUNDS_ERROR, "bytevector-u8-set!", v, i);
 6124
 6125    if(x & C_FIXNUM_BIT) {
 6126      if (C_unfix(C_i_fixnum_length(x)) <= 8) n = C_unfix(x);
 6127      else barf(C_BAD_ARGUMENT_TYPE_NUMERIC_RANGE_ERROR, "bytevector-u8-set!", x);
 6128    }
 6129    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "bytevector-u8-set!", x);
 6130  }
 6131  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "bytevector-u8-set!", i);
 6132
 6133  ((signed char *)C_data_pointer(v))[j] = n;
 6134  return C_SCHEME_UNDEFINED;
 6135}
 6136
 6137C_regparm C_word C_i_s8vector_set(C_word v, C_word i, C_word x)
 6138{
 6139  int j;
 6140  C_word n;
 6141
 6142  if(!C_truep(C_i_s8vectorp(v)))
 6143    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s8vector-set!", v);
 6144
 6145  if(i & C_FIXNUM_BIT) {
 6146    j = C_unfix(i);
 6147
 6148    if(j < 0 || j >= C_header_size(C_block_item(v, 1)))
 6149    	barf(C_OUT_OF_BOUNDS_ERROR, "s8vector-set!", v, i);
 6150
 6151    if(x & C_FIXNUM_BIT) {
 6152      if (C_unfix(C_i_fixnum_length(x)) <= 8) n = C_unfix(x);
 6153      else barf(C_BAD_ARGUMENT_TYPE_NUMERIC_RANGE_ERROR, "s8vector-set!", x);
 6154    }
 6155    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s8vector-set!", x);
 6156  }
 6157  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s8vector-set!", i);
 6158
 6159  ((signed char *)C_data_pointer(C_block_item(v, 1)))[j] = n;
 6160  return C_SCHEME_UNDEFINED;
 6161}
 6162
 6163C_regparm C_word C_i_u16vector_set(C_word v, C_word i, C_word x)
 6164{
 6165  int j;
 6166  C_word n;
 6167
 6168  if(!C_truep(C_i_u16vectorp(v)))
 6169    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u16vector-set!", v);
 6170
 6171  if(i & C_FIXNUM_BIT) {
 6172    j = C_unfix(i);
 6173
 6174    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 1))
 6175    	barf(C_OUT_OF_BOUNDS_ERROR, "u16vector-set!", v, i);
 6176
 6177    if(x & C_FIXNUM_BIT) {
 6178      if (!(x & C_INT_SIGN_BIT) && C_ilen(C_unfix(x)) <= 16) n = C_unfix(x);
 6179      else barf(C_BAD_ARGUMENT_TYPE_NUMERIC_RANGE_ERROR, "u16vector-set!", x);
 6180    }
 6181    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "u16vector-set!", x);
 6182  }
 6183  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "u16vector-set!", i);
 6184
 6185  ((unsigned short *)C_data_pointer(C_block_item(v, 1)))[j] = n;
 6186  return C_SCHEME_UNDEFINED;
 6187}
 6188
 6189C_regparm C_word C_i_s16vector_set(C_word v, C_word i, C_word x)
 6190{
 6191  int j;
 6192  C_word n;
 6193
 6194  if(!C_truep(C_i_s16vectorp(v)))
 6195    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s16vector-set!", v);
 6196
 6197  if(i & C_FIXNUM_BIT) {
 6198    j = C_unfix(i);
 6199
 6200    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 1))
 6201    	barf(C_OUT_OF_BOUNDS_ERROR, "u16vector-set!", v, i);
 6202
 6203    if(x & C_FIXNUM_BIT) {
 6204      if (C_unfix(C_i_fixnum_length(x)) <= 16) n = C_unfix(x);
 6205      else barf(C_BAD_ARGUMENT_TYPE_NUMERIC_RANGE_ERROR, "s16vector-set!", x);
 6206    }
 6207    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s16vector-set!", x);
 6208  }
 6209  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s16vector-set!", i);
 6210
 6211  ((short *)C_data_pointer(C_block_item(v, 1)))[j] = n;
 6212  return C_SCHEME_UNDEFINED;
 6213}
 6214
 6215C_regparm C_word C_i_u32vector_set(C_word v, C_word i, C_word x)
 6216{
 6217  int j;
 6218  C_u32 n;
 6219
 6220  if(!C_truep(C_i_u32vectorp(v)))
 6221    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u32vector-set!", v);
 6222
 6223  if(i & C_FIXNUM_BIT) {
 6224    j = C_unfix(i);
 6225
 6226    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 2))
 6227    	barf(C_OUT_OF_BOUNDS_ERROR, "u32vector-set!", v, i);
 6228
 6229    if(C_truep(C_i_exact_integerp(x))) {
 6230      if (C_unfix(C_i_integer_length(x)) <= 32) n = C_num_to_unsigned_int(x);
 6231      else barf(C_BAD_ARGUMENT_TYPE_NUMERIC_RANGE_ERROR, "u32vector-set!", x);
 6232    }
 6233    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "u32vector-set!", x);
 6234  }
 6235  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "u32vector-set!", i);
 6236
 6237  ((C_u32 *)C_data_pointer(C_block_item(v, 1)))[j] = n;
 6238  return C_SCHEME_UNDEFINED;
 6239}
 6240
 6241C_regparm C_word C_i_s32vector_set(C_word v, C_word i, C_word x)
 6242{
 6243  int j;
 6244  C_s32 n;
 6245
 6246  if(!C_truep(C_i_s32vectorp(v)))
 6247    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s32vector-set!", v);
 6248
 6249  if(i & C_FIXNUM_BIT) {
 6250    j = C_unfix(i);
 6251
 6252    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 2))
 6253    	barf(C_OUT_OF_BOUNDS_ERROR, "s32vector-set!", v, i);
 6254
 6255    if(C_truep(C_i_exact_integerp(x))) {
 6256      if (C_unfix(C_i_integer_length(x)) <= 32) n = C_num_to_int(x);
 6257      else barf(C_BAD_ARGUMENT_TYPE_NUMERIC_RANGE_ERROR, "s32vector-set!", x);
 6258    }
 6259    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s32vector-set!", x);
 6260  }
 6261  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s32vector-set!", i);
 6262
 6263  ((C_s32 *)C_data_pointer(C_block_item(v, 1)))[j] = n;
 6264  return C_SCHEME_UNDEFINED;
 6265}
 6266
 6267C_regparm C_word C_i_u64vector_set(C_word v, C_word i, C_word x)
 6268{
 6269  int j;
 6270  C_u64 n;
 6271
 6272  if(!C_truep(C_i_u64vectorp(v)))
 6273    barf(C_BAD_ARGUMENT_TYPE_ERROR, "u64vector-set!", v);
 6274
 6275  if(i & C_FIXNUM_BIT) {
 6276    j = C_unfix(i);
 6277
 6278    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 3))
 6279    	barf(C_OUT_OF_BOUNDS_ERROR, "u64vector-set!", v, i);
 6280
 6281    if(C_truep(C_i_exact_integerp(x))) {
 6282      if (C_unfix(C_i_integer_length(x)) <= 64) n = C_num_to_uint64(x);
 6283      else barf(C_BAD_ARGUMENT_TYPE_NUMERIC_RANGE_ERROR, "u64vector-set!", x);
 6284    }
 6285    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "u64vector-set!", x);
 6286  }
 6287  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "u64vector-set!", i);
 6288
 6289  ((C_u64 *)C_data_pointer(C_block_item(v, 1)))[j] = n;
 6290  return C_SCHEME_UNDEFINED;
 6291}
 6292
 6293C_regparm C_word C_i_s64vector_set(C_word v, C_word i, C_word x)
 6294{
 6295  int j;
 6296  C_s64 n;
 6297
 6298  if(!C_truep(C_i_s64vectorp(v)))
 6299    barf(C_BAD_ARGUMENT_TYPE_ERROR, "s64vector-set!", v);
 6300
 6301  if(i & C_FIXNUM_BIT) {
 6302    j = C_unfix(i);
 6303
 6304    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 3))
 6305    	barf(C_OUT_OF_BOUNDS_ERROR, "s64vector-set!", v, i);
 6306
 6307    if(C_truep(C_i_exact_integerp(x))) {
 6308      if (C_unfix(C_i_integer_length(x)) <= 64) n = C_num_to_int64(x);
 6309      else barf(C_BAD_ARGUMENT_TYPE_NUMERIC_RANGE_ERROR, "s64vector-set!", x);
 6310    }
 6311    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s64vector-set!", x);
 6312  }
 6313  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "s64vector-set!", i);
 6314
 6315  ((C_s64 *)C_data_pointer(C_block_item(v, 1)))[j] = n;
 6316  return C_SCHEME_UNDEFINED;
 6317}
 6318
 6319C_regparm C_word C_i_f32vector_set(C_word v, C_word i, C_word x)
 6320{
 6321  int j;
 6322  double f;
 6323
 6324  if(!C_truep(C_i_f32vectorp(v)))
 6325    barf(C_BAD_ARGUMENT_TYPE_ERROR, "f32vector-set!", v);
 6326
 6327  if(i & C_FIXNUM_BIT) {
 6328    j = C_unfix(i);
 6329
 6330    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 2))
 6331    	barf(C_OUT_OF_BOUNDS_ERROR, "f32vector-set!", v, i);
 6332
 6333    if(C_truep(C_i_flonump(x))) f = C_flonum_magnitude(x);
 6334    else if(x & C_FIXNUM_BIT) f = C_unfix(x);
 6335    else if (C_truep(C_i_bignump(x))) f = C_bignum_to_double(x);
 6336    else barf(C_BAD_ARGUMENT_TYPE_NUMERIC_RANGE_ERROR, "f32vector-set!", x);
 6337  }
 6338  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "f32vector-set!", i);
 6339
 6340  ((float *)C_data_pointer(C_block_item(v, 1)))[j] = (float)f;
 6341  return C_SCHEME_UNDEFINED;
 6342}
 6343
 6344C_regparm C_word C_i_f64vector_set(C_word v, C_word i, C_word x)
 6345{
 6346  int j;
 6347  double f;
 6348
 6349  if(!C_truep(C_i_f64vectorp(v)))
 6350    barf(C_BAD_ARGUMENT_TYPE_ERROR, "f64vector-set!", v);
 6351
 6352  if(i & C_FIXNUM_BIT) {
 6353    j = C_unfix(i);
 6354
 6355    if(j < 0 || j >= (C_header_size(C_block_item(v, 1)) >> 3))
 6356    	barf(C_OUT_OF_BOUNDS_ERROR, "f64vector-set!", v, i);
 6357
 6358    if(C_truep(C_i_flonump(x))) f = C_flonum_magnitude(x);
 6359    else if(x & C_FIXNUM_BIT) f = C_unfix(x);
 6360    else if (C_truep(C_i_bignump(x))) f = C_bignum_to_double(x);
 6361    else barf(C_BAD_ARGUMENT_TYPE_NUMERIC_RANGE_ERROR, "f64vector-set!", x);
 6362
 6363  }
 6364  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "f64vector-set!", i);
 6365
 6366  ((double *)C_data_pointer(C_block_item(v, 1)))[j] = f;
 6367  return C_SCHEME_UNDEFINED;
 6368}
 6369
 6370
 6371/* This needs at most C_SIZEOF_FIX_BIGNUM + max(C_SIZEOF_RATNUM, C_SIZEOF_CPLXNUM) so 7 words */
 6372C_regparm C_word
 6373C_s_a_i_abs(C_word **ptr, C_word n, C_word x)
 6374{
 6375  if (x & C_FIXNUM_BIT) {
 6376    return C_a_i_fixnum_abs(ptr, 1, x);
 6377  } else if (C_immediatep(x)) {
 6378    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "abs", x);
 6379  } else if (C_block_header(x) == C_FLONUM_TAG) {
 6380    return C_a_i_flonum_abs(ptr, 1, x);
 6381  } else if (C_truep(C_bignump(x))) {
 6382    return C_s_a_u_i_integer_abs(ptr, 1, x);
 6383  } else if (C_block_header(x) == C_RATNUM_TAG) {
 6384    return C_ratnum(ptr, C_s_a_u_i_integer_abs(ptr, 1, C_u_i_ratnum_num(x)),
 6385                    C_u_i_ratnum_denom(x));
 6386  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 6387    barf(C_BAD_ARGUMENT_TYPE_COMPLEX_ABS, "abs", x);
 6388  } else {
 6389    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "abs", x);
 6390  }
 6391}
 6392
 6393void C_ccall C_signum(C_word c, C_word *av)
 6394{
 6395  C_word k = av[ 1 ], x, y;
 6396
 6397  if (c != 3) C_bad_argc_2(c, 3, av[ 0 ]);
 6398
 6399  x = av[ 2 ];
 6400  y = av[ 3 ];
 6401
 6402  if (x & C_FIXNUM_BIT) {
 6403    C_kontinue(k, C_i_fixnum_signum(x));
 6404  } else if (C_immediatep(x)) {
 6405    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "signum", x);
 6406  } else if (C_block_header(x) == C_FLONUM_TAG) {
 6407    C_word *a = C_alloc(C_SIZEOF_FLONUM);
 6408    C_kontinue(k, C_a_u_i_flonum_signum(&a, 1, x));
 6409  } else if (C_truep(C_bignump(x))) {
 6410    C_kontinue(k, C_bignum_negativep(x) ? C_fix(-1) : C_fix(1));
 6411  } else {
 6412    try_extended_number("##sys#extended-signum", 2, k, x);
 6413  }
 6414}
 6415
 6416
 6417/* The maximum this can allocate is a cplxnum which consists of two
 6418 * ratnums that consist of 2 fix bignums each.  So that's
 6419 * C_SIZEOF_CPLXNUM + C_SIZEOF_RATNUM * 2 + C_SIZEOF_FIX_BIGNUM * 4 = 29 words!
 6420 */
 6421C_regparm C_word
 6422C_s_a_i_negate(C_word **ptr, C_word n, C_word x)
 6423{
 6424  if (x & C_FIXNUM_BIT) {
 6425    return C_a_i_fixnum_negate(ptr, 1, x);
 6426  } else if (C_immediatep(x)) {
 6427    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", x);
 6428  } else if (C_block_header(x) == C_FLONUM_TAG) {
 6429    return C_a_i_flonum_negate(ptr, 1, x);
 6430  } else if (C_truep(C_bignump(x))) {
 6431    return C_s_a_u_i_integer_negate(ptr, 1, x);
 6432  } else if (C_block_header(x) == C_RATNUM_TAG) {
 6433    return C_ratnum(ptr, C_s_a_u_i_integer_negate(ptr, 1, C_u_i_ratnum_num(x)),
 6434                    C_u_i_ratnum_denom(x));
 6435  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 6436    return C_cplxnum(ptr, C_s_a_i_negate(ptr, 1, C_u_i_cplxnum_real(x)),
 6437                     C_s_a_i_negate(ptr, 1, C_u_i_cplxnum_imag(x)));
 6438  } else {
 6439    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", x);
 6440  }
 6441}
 6442
 6443/* Copy all the digits from source to target, obliterating what was
 6444 * there.  If target is larger than source, the most significant
 6445 * digits will remain untouched.
 6446 */
 6447inline static void bignum_digits_destructive_copy(C_word target, C_word source)
 6448{
 6449  C_memcpy(C_bignum_digits(target), C_bignum_digits(source),
 6450           C_wordstobytes(C_bignum_size(source)));
 6451}
 6452
 6453C_regparm C_word
 6454C_s_a_u_i_integer_negate(C_word **ptr, C_word n, C_word x)
 6455{
 6456  if (x & C_FIXNUM_BIT) {
 6457    return C_a_i_fixnum_negate(ptr, 1, x);
 6458  } else {
 6459    if (C_bignum_negated_fitsinfixnump(x)) {
 6460      return C_fix(C_MOST_NEGATIVE_FIXNUM);
 6461    } else {
 6462      C_word res, negp = C_mk_nbool(C_bignum_negativep(x)),
 6463             size = C_fix(C_bignum_size(x));
 6464      res = C_allocate_scratch_bignum(ptr, size, negp, C_SCHEME_FALSE);
 6465      bignum_digits_destructive_copy(res, x);
 6466      return C_bignum_simplify(res);
 6467    }
 6468  }
 6469}
 6470
 6471
 6472/* Faster version that ignores sign */
 6473inline static int integer_length_abs(C_word x)
 6474{
 6475  if (x & C_FIXNUM_BIT) {
 6476    return C_ilen(C_wabs(C_unfix(x)));
 6477  } else {
 6478    C_uword result = (C_bignum_size(x) - 1) * C_BIGNUM_DIGIT_LENGTH,
 6479            *last_digit = C_bignum_digits(x) + C_bignum_size(x) - 1,
 6480            last_digit_length = C_ilen(*last_digit);
 6481    return result + last_digit_length;
 6482  }
 6483}
 6484
 6485C_regparm C_word C_i_integer_length(C_word x)
 6486{
 6487  if (x & C_FIXNUM_BIT) {
 6488    return C_i_fixnum_length(x);
 6489  } else if (C_truep(C_i_bignump(x))) {
 6490    C_uword result = (C_bignum_size(x) - 1) * C_BIGNUM_DIGIT_LENGTH,
 6491            *last_digit = C_bignum_digits(x) + C_bignum_size(x) - 1,
 6492            last_digit_length = C_ilen(*last_digit);
 6493
 6494    /* If *only* the highest bit is set, negating will give one less bit */
 6495    if (C_bignum_negativep(x) &&
 6496        *last_digit == ((C_uword)1 << (last_digit_length-1))) {
 6497      C_uword *startx = C_bignum_digits(x);
 6498      while (startx < last_digit && *startx == 0) ++startx;
 6499      if (startx == last_digit) result--;
 6500    }
 6501    return C_fix(result + last_digit_length);
 6502  } else {
 6503    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "integer-length", x);
 6504  }
 6505}
 6506
 6507/* This is currently only used by Karatsuba multiplication and
 6508 * Burnikel-Ziegler division. */
 6509static C_regparm C_word
 6510bignum_extract_digits(C_word **ptr, C_word n, C_word x, C_word start, C_word end)
 6511{
 6512  if (x & C_FIXNUM_BIT) { /* Needed? */
 6513    if (C_unfix(start) == 0 && (end == C_SCHEME_FALSE || C_unfix(end) > 0))
 6514      return x;
 6515    else
 6516      return C_fix(0);
 6517  } else {
 6518    C_word negp, size;
 6519
 6520    negp = C_mk_bool(C_bignum_negativep(x)); /* Always false */
 6521
 6522    start = C_unfix(start);
 6523    /* We might get passed larger values than actually fits; pad w/ zeroes */
 6524    if (end == C_SCHEME_FALSE) end = C_bignum_size(x);
 6525    else end = nmin(C_unfix(end), C_bignum_size(x));
 6526    assert(start >= 0);
 6527
 6528    size = end - start;
 6529
 6530    if (size == 0 || start >= C_bignum_size(x)) {
 6531      return C_fix(0);
 6532    } else {
 6533      C_uword res, *res_digits, *x_digits;
 6534      res = C_allocate_scratch_bignum(ptr, C_fix(size), negp, C_SCHEME_FALSE);
 6535      res_digits = C_bignum_digits(res);
 6536      x_digits = C_bignum_digits(x);
 6537      /* Can't use bignum_digits_destructive_copy because that assumes
 6538       * target is at least as big as source.
 6539       */
 6540      C_memcpy(res_digits, x_digits + start, C_wordstobytes(end - start));
 6541      return C_bignum_simplify(res);
 6542    }
 6543  }
 6544}
 6545
 6546/* This returns a tmp bignum negated copy of X (must be freed!) when
 6547 * the number is negative, or #f if it doesn't need to be negated.
 6548 * The size can be larger or smaller than X (it may be 1-padded).
 6549 */
 6550inline static C_word maybe_negate_bignum_for_bitwise_op(C_word x, C_word size)
 6551{
 6552  C_word nx = C_SCHEME_FALSE, xsize;
 6553  if (C_bignum_negativep(x)) {
 6554    nx = allocate_tmp_bignum(C_fix(size), C_SCHEME_FALSE, C_SCHEME_FALSE);
 6555    xsize = C_bignum_size(x);
 6556    /* Copy up until requested size, and init any remaining upper digits */
 6557    C_memcpy(C_bignum_digits(nx), C_bignum_digits(x),
 6558             C_wordstobytes(nmin(size, xsize)));
 6559    if (size > xsize)
 6560      C_memset(C_bignum_digits(nx)+xsize, 0, C_wordstobytes(size-xsize));
 6561    bignum_digits_destructive_negate(nx);
 6562  }
 6563  return nx;
 6564}
 6565
 6566/* DEPRECATED */
 6567C_regparm C_word C_i_bit_to_bool(C_word n, C_word i)
 6568{
 6569  if (!C_truep(C_i_exact_integerp(n))) {
 6570    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bit->boolean", n);
 6571  } else if (!(i & C_FIXNUM_BIT)) {
 6572    if (!C_immediatep(i) && C_truep(C_bignump(i)) && !C_bignum_negativep(i)) {
 6573      return C_i_integer_negativep(n); /* A bit silly, but strictly correct */
 6574    } else {
 6575      barf(C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR, "bit->boolean", i);
 6576    }
 6577  } else if (i & C_INT_SIGN_BIT) {
 6578    barf(C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR, "bit->boolean", i);
 6579  } else {
 6580    i = C_unfix(i);
 6581    if (n & C_FIXNUM_BIT) {
 6582      if (i >= C_WORD_SIZE) return C_mk_bool(n & C_INT_SIGN_BIT);
 6583      else return C_mk_bool((C_unfix(n) & ((C_word)1 << i)) != 0);
 6584    } else {
 6585      C_word nn, d;
 6586      d = i / C_BIGNUM_DIGIT_LENGTH;
 6587      if (d >= C_bignum_size(n)) return C_mk_bool(C_bignum_negativep(n));
 6588
 6589      /* TODO: this isn't necessary, is it? */
 6590      if (C_truep(nn = maybe_negate_bignum_for_bitwise_op(n, d))) n = nn;
 6591
 6592      i %= C_BIGNUM_DIGIT_LENGTH;
 6593      d = C_mk_bool((C_bignum_digits(n)[d] & (C_uword)1 << i) != 0);
 6594      if (C_truep(nn)) free_tmp_bignum(nn);
 6595      return d;
 6596    }
 6597  }
 6598}
 6599
 6600C_regparm C_word
 6601C_s_a_i_bitwise_and(C_word **ptr, C_word n, C_word x, C_word y)
 6602{
 6603  if ((x & y) & C_FIXNUM_BIT) {
 6604    return C_u_fixnum_and(x, y);
 6605  } else if (!C_truep(C_i_exact_integerp(x))) {
 6606    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-and", x);
 6607  } else if (!C_truep(C_i_exact_integerp(y))) {
 6608    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-and", y);
 6609  } else {
 6610    C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, negp, size, res, nx, ny;
 6611    C_uword *scanr, *endr, *scans1, *ends1, *scans2;
 6612
 6613    if (x & C_FIXNUM_BIT) x = C_a_u_i_fix_to_big(&a, x);
 6614    if (y & C_FIXNUM_BIT) y = C_a_u_i_fix_to_big(&a, y);
 6615
 6616    negp = C_mk_bool(C_bignum_negativep(x) && C_bignum_negativep(y));
 6617    /* Allow negative 1-bits to propagate */
 6618    if (C_bignum_negativep(x) || C_bignum_negativep(y))
 6619      size = nmax(C_bignum_size(x), C_bignum_size(y)) + 1;
 6620    else
 6621      size = nmin(C_bignum_size(x), C_bignum_size(y));
 6622
 6623    res = C_allocate_scratch_bignum(ptr, C_fix(size), negp, C_SCHEME_FALSE);
 6624    scanr = C_bignum_digits(res);
 6625    endr = scanr + C_bignum_size(res);
 6626
 6627    if (C_truep(nx = maybe_negate_bignum_for_bitwise_op(x, size))) x = nx;
 6628    if (C_truep(ny = maybe_negate_bignum_for_bitwise_op(y, size))) y = ny;
 6629
 6630    if (C_bignum_size(x) < C_bignum_size(y)) {
 6631      scans1 = C_bignum_digits(x); ends1 = scans1 + C_bignum_size(x);
 6632      scans2 = C_bignum_digits(y);
 6633    } else {
 6634      scans1 = C_bignum_digits(y); ends1 = scans1 + C_bignum_size(y);
 6635      scans2 = C_bignum_digits(x);
 6636    }
 6637
 6638    while (scans1 < ends1) *scanr++ = *scans1++ & *scans2++;
 6639    C_memset(scanr, 0, C_wordstobytes(endr - scanr));
 6640
 6641    if (C_truep(nx)) free_tmp_bignum(nx);
 6642    if (C_truep(ny)) free_tmp_bignum(ny);
 6643    if (C_bignum_negativep(res)) bignum_digits_destructive_negate(res);
 6644
 6645    return C_bignum_simplify(res);
 6646  }
 6647}
 6648
 6649void C_ccall C_bitwise_and(C_word c, C_word *av)
 6650{
 6651  /* C_word closure = av[ 0 ]; */
 6652  C_word k = av[ 1 ];
 6653  C_word next_val, result, prev_result;
 6654  C_word ab[2][C_SIZEOF_BIGNUM_WRAPPER], *a;
 6655
 6656  c -= 2;
 6657  av += 2;
 6658
 6659  if (c == 0) C_kontinue(k, C_fix(-1));
 6660
 6661  prev_result = result = *(av++);
 6662
 6663  if (c-- == 1 && !C_truep(C_i_exact_integerp(result)))
 6664    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-and", result);
 6665
 6666  while (c--) {
 6667    next_val = *(av++);
 6668    a = ab[c&1]; /* One may hold last iteration result, the other is unused */
 6669    result = C_s_a_i_bitwise_and(&a, 2, result, next_val);
 6670    result = move_buffer_object(&a, ab[(c+1)&1], result);
 6671    clear_buffer_object(ab[(c+1)&1], prev_result);
 6672    prev_result = result;
 6673  }
 6674
 6675  C_kontinue(k, result);
 6676}
 6677
 6678C_regparm C_word
 6679C_s_a_i_bitwise_ior(C_word **ptr, C_word n, C_word x, C_word y)
 6680{
 6681  if ((x & y) & C_FIXNUM_BIT) {
 6682    return C_u_fixnum_or(x, y);
 6683  } else if (!C_truep(C_i_exact_integerp(x))) {
 6684    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-ior", x);
 6685  } else if (!C_truep(C_i_exact_integerp(y))) {
 6686    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-ior", y);
 6687  } else {
 6688    C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, negp, size, res, nx, ny;
 6689    C_uword *scanr, *endr, *scans1, *ends1, *scans2, *ends2;
 6690
 6691    if (x & C_FIXNUM_BIT) x = C_a_u_i_fix_to_big(&a, x);
 6692    if (y & C_FIXNUM_BIT) y = C_a_u_i_fix_to_big(&a, y);
 6693
 6694    negp = C_mk_bool(C_bignum_negativep(x) || C_bignum_negativep(y));
 6695    size = nmax(C_bignum_size(x), C_bignum_size(y)) + 1;
 6696    res = C_allocate_scratch_bignum(ptr, C_fix(size), negp, C_SCHEME_FALSE);
 6697    scanr = C_bignum_digits(res);
 6698    endr = scanr + C_bignum_size(res);
 6699
 6700    if (C_truep(nx = maybe_negate_bignum_for_bitwise_op(x, size))) x = nx;
 6701    if (C_truep(ny = maybe_negate_bignum_for_bitwise_op(y, size))) y = ny;
 6702
 6703    if (C_bignum_size(x) < C_bignum_size(y)) {
 6704      scans1 = C_bignum_digits(x); ends1 = scans1 + C_bignum_size(x);
 6705      scans2 = C_bignum_digits(y); ends2 = scans2 + C_bignum_size(y);
 6706    } else {
 6707      scans1 = C_bignum_digits(y); ends1 = scans1 + C_bignum_size(y);
 6708      scans2 = C_bignum_digits(x); ends2 = scans2 + C_bignum_size(x);
 6709    }
 6710
 6711    while (scans1 < ends1) *scanr++ = *scans1++ | *scans2++;
 6712    while (scans2 < ends2) *scanr++ = *scans2++;
 6713    if (scanr < endr) *scanr++ = 0; /* Only done when result is positive */
 6714    assert(scanr == endr);
 6715
 6716    if (C_truep(nx)) free_tmp_bignum(nx);
 6717    if (C_truep(ny)) free_tmp_bignum(ny);
 6718    if (C_bignum_negativep(res)) bignum_digits_destructive_negate(res);
 6719
 6720    return C_bignum_simplify(res);
 6721  }
 6722}
 6723
 6724void C_ccall C_bitwise_ior(C_word c, C_word *av)
 6725{
 6726  /* C_word closure = av[ 0 ]; */
 6727  C_word k = av[ 1 ];
 6728  C_word next_val, result, prev_result;
 6729  C_word ab[2][C_SIZEOF_BIGNUM_WRAPPER], *a;
 6730
 6731  c -= 2;
 6732  av += 2;
 6733
 6734  if (c == 0) C_kontinue(k, C_fix(0));
 6735
 6736  prev_result = result = *(av++);
 6737
 6738  if (c-- == 1 && !C_truep(C_i_exact_integerp(result)))
 6739    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-ior", result);
 6740
 6741  while (c--) {
 6742    next_val = *(av++);
 6743    a = ab[c&1]; /* One may hold prev iteration result, the other is unused */
 6744    result = C_s_a_i_bitwise_ior(&a, 2, result, next_val);
 6745    result = move_buffer_object(&a, ab[(c+1)&1], result);
 6746    clear_buffer_object(ab[(c+1)&1], prev_result);
 6747    prev_result = result;
 6748  }
 6749
 6750  C_kontinue(k, result);
 6751}
 6752
 6753C_regparm C_word
 6754C_s_a_i_bitwise_xor(C_word **ptr, C_word n, C_word x, C_word y)
 6755{
 6756  if ((x & y) & C_FIXNUM_BIT) {
 6757    return C_fixnum_xor(x, y);
 6758  } else if (!C_truep(C_i_exact_integerp(x))) {
 6759    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-xor", x);
 6760  } else if (!C_truep(C_i_exact_integerp(y))) {
 6761    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-xor", y);
 6762  } else {
 6763    C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, negp, size, res, nx, ny;
 6764    C_uword *scanr, *endr, *scans1, *ends1, *scans2, *ends2;
 6765
 6766    if (x & C_FIXNUM_BIT) x = C_a_u_i_fix_to_big(&a, x);
 6767    if (y & C_FIXNUM_BIT) y = C_a_u_i_fix_to_big(&a, y);
 6768
 6769    size = nmax(C_bignum_size(x), C_bignum_size(y)) + 1;
 6770    negp = C_mk_bool(C_bignum_negativep(x) != C_bignum_negativep(y));
 6771    res = C_allocate_scratch_bignum(ptr, C_fix(size), negp, C_SCHEME_FALSE);
 6772    scanr = C_bignum_digits(res);
 6773    endr = scanr + C_bignum_size(res);
 6774
 6775    if (C_truep(nx = maybe_negate_bignum_for_bitwise_op(x, size))) x = nx;
 6776    if (C_truep(ny = maybe_negate_bignum_for_bitwise_op(y, size))) y = ny;
 6777
 6778    if (C_bignum_size(x) < C_bignum_size(y)) {
 6779      scans1 = C_bignum_digits(x); ends1 = scans1 + C_bignum_size(x);
 6780      scans2 = C_bignum_digits(y); ends2 = scans2 + C_bignum_size(y);
 6781    } else {
 6782      scans1 = C_bignum_digits(y); ends1 = scans1 + C_bignum_size(y);
 6783      scans2 = C_bignum_digits(x); ends2 = scans2 + C_bignum_size(x);
 6784    }
 6785
 6786    while (scans1 < ends1) *scanr++ = *scans1++ ^ *scans2++;
 6787    while (scans2 < ends2) *scanr++ = *scans2++;
 6788    if (scanr < endr) *scanr++ = 0; /* Only done when result is positive */
 6789    assert(scanr == endr);
 6790
 6791    if (C_truep(nx)) free_tmp_bignum(nx);
 6792    if (C_truep(ny)) free_tmp_bignum(ny);
 6793    if (C_bignum_negativep(res)) bignum_digits_destructive_negate(res);
 6794
 6795    return C_bignum_simplify(res);
 6796  }
 6797}
 6798
 6799void C_ccall C_bitwise_xor(C_word c, C_word *av)
 6800{
 6801  /* C_word closure = av[ 0 ]; */
 6802  C_word k = av[ 1 ];
 6803  C_word next_val, result, prev_result;
 6804  C_word ab[2][C_SIZEOF_BIGNUM_WRAPPER], *a;
 6805
 6806  c -= 2;
 6807  av += 2;
 6808
 6809  if (c == 0) C_kontinue(k, C_fix(0));
 6810
 6811  prev_result = result = *(av++);
 6812
 6813  if (c-- == 1 && !C_truep(C_i_exact_integerp(result)))
 6814    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-xor", result);
 6815
 6816  while (c--) {
 6817    next_val = *(av++);
 6818    a = ab[c&1]; /* One may hold prev iteration result, the other is unused */
 6819    result = C_s_a_i_bitwise_xor(&a, 2, result, next_val);
 6820    result = move_buffer_object(&a, ab[(c+1)&1], result);
 6821    clear_buffer_object(ab[(c+1)&1], prev_result);
 6822    prev_result = result;
 6823  }
 6824
 6825  C_kontinue(k, result);
 6826}
 6827
 6828C_regparm C_word
 6829C_s_a_i_bitwise_not(C_word **ptr, C_word n, C_word x)
 6830{
 6831  if (!C_truep(C_i_exact_integerp(x))) {
 6832    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-not", x);
 6833  } else {
 6834    return C_s_a_u_i_integer_minus(ptr, 2, C_fix(-1), x);
 6835  }
 6836}
 6837
 6838C_regparm C_word
 6839C_s_a_i_arithmetic_shift(C_word **ptr, C_word n, C_word x, C_word y)
 6840{
 6841  C_word ab[C_SIZEOF_FIX_BIGNUM], *a = ab, size, negp, res,
 6842         digit_offset, bit_offset;
 6843
 6844  if (!(y & C_FIXNUM_BIT))
 6845    barf(C_BAD_ARGUMENT_TYPE_NO_FIXNUM_ERROR, "arithmetic-shift", y);
 6846
 6847  y = C_unfix(y);
 6848  if (y == 0 || x == C_fix(0)) { /* Done (no shift) */
 6849    return x;
 6850  } else if (x & C_FIXNUM_BIT) {
 6851    if (y < 0) {
 6852      /* Don't shift more than a word's length (that's undefined in C!) */
 6853      if (-y < C_WORD_SIZE) {
 6854        return C_fix(C_unfix(x) >> -y);
 6855      } else {
 6856        return (x < 0) ? C_fix(-1) : C_fix(0);
 6857      }
 6858    } else if (y > 0 && y < C_WORD_SIZE-2 &&
 6859               /* After shifting, the length still fits a fixnum */
 6860               (C_ilen(C_unfix(x)) + y) < C_WORD_SIZE-2) {
 6861      return C_fix((C_uword)C_unfix(x) << y);
 6862    } else {
 6863      x = C_a_u_i_fix_to_big(&a, x);
 6864    }
 6865  } else if (!C_truep(C_i_bignump(x))) {
 6866    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "arithmetic-shift", x);
 6867  }
 6868
 6869  negp = C_mk_bool(C_bignum_negativep(x));
 6870
 6871  if (y > 0) {                  /* Shift left */
 6872    C_uword *startr, *startx, *endx, *endr;
 6873
 6874    digit_offset = y / C_BIGNUM_DIGIT_LENGTH;
 6875    bit_offset =   y % C_BIGNUM_DIGIT_LENGTH;
 6876
 6877    size = C_fix(C_bignum_size(x) + digit_offset + 1);
 6878    res = C_allocate_scratch_bignum(ptr, size, negp, C_SCHEME_FALSE);
 6879
 6880    startr = C_bignum_digits(res);
 6881    endr = startr + C_bignum_size(res);
 6882
 6883    startx = C_bignum_digits(x);
 6884    endx = startx + C_bignum_size(x);
 6885
 6886    /* Initialize only the lower digits we're skipping and the MSD */
 6887    C_memset(startr, 0, C_wordstobytes(digit_offset));
 6888    *(endr-1) = 0;
 6889    startr += digit_offset;
 6890    /* Can't use bignum_digits_destructive_copy because it assumes
 6891     * we want to copy from the start.
 6892     */
 6893    C_memcpy(startr, startx, C_wordstobytes(endx-startx));
 6894    if(bit_offset > 0)
 6895      bignum_digits_destructive_shift_left(startr, endr, bit_offset);
 6896
 6897    return C_bignum_simplify(res);
 6898  } else if (-y >= C_bignum_size(x) * (C_word)C_BIGNUM_DIGIT_LENGTH) {
 6899    /* All bits are shifted out, just return 0 or -1 */
 6900    return C_truep(negp) ? C_fix(-1) : C_fix(0);
 6901  } else {                      /* Shift right */
 6902    C_uword *startr, *startx, *endr;
 6903    C_word nx;
 6904
 6905    digit_offset = -y / C_BIGNUM_DIGIT_LENGTH;
 6906    bit_offset =   -y % C_BIGNUM_DIGIT_LENGTH;
 6907
 6908    size = C_fix(C_bignum_size(x) - digit_offset);
 6909    res = C_allocate_scratch_bignum(ptr, size, negp, C_SCHEME_FALSE);
 6910
 6911    startr = C_bignum_digits(res);
 6912    endr = startr + C_bignum_size(res);
 6913
 6914    size = C_bignum_size(x) + 1;
 6915    if (C_truep(nx = maybe_negate_bignum_for_bitwise_op(x, size))) {
 6916      startx = C_bignum_digits(nx) + digit_offset;
 6917    } else {
 6918      startx = C_bignum_digits(x) + digit_offset;
 6919    }
 6920    /* Can't use bignum_digits_destructive_copy because that assumes
 6921     * target is at least as big as source.
 6922     */
 6923    C_memcpy(startr, startx, C_wordstobytes(endr-startr));
 6924    if(bit_offset > 0)
 6925      bignum_digits_destructive_shift_right(startr,endr,bit_offset,C_truep(nx));
 6926
 6927    if (C_truep(nx)) {
 6928      free_tmp_bignum(nx);
 6929      bignum_digits_destructive_negate(res);
 6930    }
 6931    return C_bignum_simplify(res);
 6932  }
 6933}
 6934
 6935
 6936C_regparm C_word C_a_i_exp(C_word **a, int c, C_word n)
 6937{
 6938  double f;
 6939
 6940  C_check_real(n, "exp", f);
 6941  return C_flonum(a, C_exp(f));
 6942}
 6943
 6944
 6945C_regparm C_word C_a_i_log(C_word **a, int c, C_word n)
 6946{
 6947  double f;
 6948
 6949  C_check_real(n, "log", f);
 6950  return C_flonum(a, C_log(f));
 6951}
 6952
 6953
 6954C_regparm C_word C_a_i_sin(C_word **a, int c, C_word n)
 6955{
 6956  double f;
 6957
 6958  C_check_real(n, "sin", f);
 6959  return C_flonum(a, C_sin(f));
 6960}
 6961
 6962
 6963C_regparm C_word C_a_i_cos(C_word **a, int c, C_word n)
 6964{
 6965  double f;
 6966
 6967  C_check_real(n, "cos", f);
 6968  return C_flonum(a, C_cos(f));
 6969}
 6970
 6971
 6972C_regparm C_word C_a_i_tan(C_word **a, int c, C_word n)
 6973{
 6974  double f;
 6975
 6976  C_check_real(n, "tan", f);
 6977  return C_flonum(a, C_tan(f));
 6978}
 6979
 6980
 6981C_regparm C_word C_a_i_asin(C_word **a, int c, C_word n)
 6982{
 6983  double f;
 6984
 6985  C_check_real(n, "asin", f);
 6986  return C_flonum(a, C_asin(f));
 6987}
 6988
 6989
 6990C_regparm C_word C_a_i_acos(C_word **a, int c, C_word n)
 6991{
 6992  double f;
 6993
 6994  C_check_real(n, "acos", f);
 6995  return C_flonum(a, C_acos(f));
 6996}
 6997
 6998
 6999C_regparm C_word C_a_i_atan(C_word **a, int c, C_word n)
 7000{
 7001  double f;
 7002
 7003  C_check_real(n, "atan", f);
 7004  return C_flonum(a, C_atan(f));
 7005}
 7006
 7007
 7008C_regparm C_word C_a_i_atan2(C_word **a, int c, C_word n1, C_word n2)
 7009{
 7010  double f1, f2;
 7011
 7012  C_check_real(n1, "atan", f1);
 7013  C_check_real(n2, "atan", f2);
 7014  return C_flonum(a, C_atan2(f1, f2));
 7015}
 7016
 7017
 7018C_regparm C_word C_a_i_sinh(C_word **a, int c, C_word n)
 7019{
 7020  double f;
 7021
 7022  C_check_real(n, "sinh", f);
 7023  return C_flonum(a, C_sinh(f));
 7024}
 7025
 7026
 7027C_regparm C_word C_a_i_cosh(C_word **a, int c, C_word n)
 7028{
 7029  double f;
 7030
 7031  C_check_real(n, "cosh", f);
 7032  return C_flonum(a, C_cosh(f));
 7033}
 7034
 7035
 7036C_regparm C_word C_a_i_tanh(C_word **a, int c, C_word n)
 7037{
 7038  double f;
 7039
 7040  C_check_real(n, "tanh", f);
 7041  return C_flonum(a, C_tanh(f));
 7042}
 7043
 7044
 7045C_regparm C_word C_a_i_asinh(C_word **a, int c, C_word n)
 7046{
 7047  double f;
 7048
 7049  C_check_real(n, "asinh", f);
 7050  return C_flonum(a, C_asinh(f));
 7051}
 7052
 7053
 7054C_regparm C_word C_a_i_acosh(C_word **a, int c, C_word n)
 7055{
 7056  double f;
 7057
 7058  C_check_real(n, "acosh", f);
 7059  return C_flonum(a, C_acosh(f));
 7060}
 7061
 7062
 7063C_regparm C_word C_a_i_atanh(C_word **a, int c, C_word n)
 7064{
 7065  double f;
 7066
 7067  C_check_real(n, "atanh", f);
 7068  return C_flonum(a, C_atanh(f));
 7069}
 7070
 7071
 7072C_regparm C_word C_a_i_sqrt(C_word **a, int c, C_word n)
 7073{
 7074  double f;
 7075
 7076  C_check_real(n, "sqrt", f);
 7077  return C_flonum(a, C_sqrt(f));
 7078}
 7079
 7080
 7081C_regparm C_word C_i_assq(C_word x, C_word lst)
 7082{
 7083  C_word a;
 7084
 7085  while(!C_immediatep(lst) && C_header_type(lst) == C_PAIR_TYPE) {
 7086    a = C_u_i_car(lst);
 7087
 7088    if(!C_immediatep(a) && C_header_type(a) == C_PAIR_TYPE) {
 7089      if(C_u_i_car(a) == x) return a;
 7090    }
 7091    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "assq", a);
 7092
 7093    lst = C_u_i_cdr(lst);
 7094  }
 7095
 7096  if(lst!=C_SCHEME_END_OF_LIST)
 7097    barf(C_BAD_ARGUMENT_TYPE_ERROR, "assq", lst);
 7098
 7099  return C_SCHEME_FALSE;
 7100}
 7101
 7102
 7103C_regparm C_word C_i_assv(C_word x, C_word lst)
 7104{
 7105  C_word a;
 7106
 7107  while(!C_immediatep(lst) && C_header_type(lst) == C_PAIR_TYPE) {
 7108    a = C_u_i_car(lst);
 7109
 7110    if(!C_immediatep(a) && C_header_type(a) == C_PAIR_TYPE) {
 7111      if(C_truep(C_i_eqvp(C_u_i_car(a), x))) return a;
 7112    }
 7113    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "assv", a);
 7114
 7115    lst = C_u_i_cdr(lst);
 7116  }
 7117
 7118  if(lst!=C_SCHEME_END_OF_LIST)
 7119    barf(C_BAD_ARGUMENT_TYPE_ERROR, "assv", lst);
 7120
 7121  return C_SCHEME_FALSE;
 7122}
 7123
 7124
 7125C_regparm C_word C_i_assoc(C_word x, C_word lst)
 7126{
 7127  C_word a;
 7128
 7129  while(!C_immediatep(lst) && C_header_type(lst) == C_PAIR_TYPE) {
 7130    a = C_u_i_car(lst);
 7131
 7132    if(!C_immediatep(a) && C_header_type(a) == C_PAIR_TYPE) {
 7133      if(C_equalp(C_u_i_car(a), x)) return a;
 7134    }
 7135    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "assoc", a);
 7136
 7137    lst = C_u_i_cdr(lst);
 7138  }
 7139
 7140  if(lst!=C_SCHEME_END_OF_LIST)
 7141    barf(C_BAD_ARGUMENT_TYPE_ERROR, "assoc", lst);
 7142
 7143  return C_SCHEME_FALSE;
 7144}
 7145
 7146
 7147C_regparm C_word C_i_memq(C_word x, C_word lst)
 7148{
 7149  while(!C_immediatep(lst) && C_header_type(lst) == C_PAIR_TYPE) {
 7150    if(C_u_i_car(lst) == x) return lst;
 7151    else lst = C_u_i_cdr(lst);
 7152  }
 7153
 7154  if(lst!=C_SCHEME_END_OF_LIST)
 7155    barf(C_BAD_ARGUMENT_TYPE_ERROR, "memq", lst);
 7156
 7157  return C_SCHEME_FALSE;
 7158}
 7159
 7160
 7161C_regparm C_word C_u_i_memq(C_word x, C_word lst)
 7162{
 7163  while(!C_immediatep(lst)) {
 7164    if(C_u_i_car(lst) == x) return lst;
 7165    else lst = C_u_i_cdr(lst);
 7166  }
 7167
 7168  return C_SCHEME_FALSE;
 7169}
 7170
 7171
 7172C_regparm C_word C_i_memv(C_word x, C_word lst)
 7173{
 7174  while(!C_immediatep(lst) && C_header_type(lst) == C_PAIR_TYPE) {
 7175    if(C_truep(C_i_eqvp(C_u_i_car(lst), x))) return lst;
 7176    else lst = C_u_i_cdr(lst);
 7177  }
 7178
 7179  if(lst!=C_SCHEME_END_OF_LIST)
 7180    barf(C_BAD_ARGUMENT_TYPE_ERROR, "memv", lst);
 7181
 7182  return C_SCHEME_FALSE;
 7183}
 7184
 7185
 7186C_regparm C_word C_i_member(C_word x, C_word lst)
 7187{
 7188  while(!C_immediatep(lst) && C_header_type(lst) == C_PAIR_TYPE) {
 7189    if(C_equalp(C_u_i_car(lst), x)) return lst;
 7190    else lst = C_u_i_cdr(lst);
 7191  }
 7192
 7193  if(lst!=C_SCHEME_END_OF_LIST)
 7194    barf(C_BAD_ARGUMENT_TYPE_ERROR, "member", lst);
 7195
 7196  return C_SCHEME_FALSE;
 7197}
 7198
 7199
 7200/* Inline routines for extended bindings: */
 7201
 7202C_regparm C_word C_i_check_closure_2(C_word x, C_word loc)
 7203{
 7204  if(C_immediatep(x) || (C_header_bits(x) != C_CLOSURE_TYPE)) {
 7205    error_location = loc;
 7206    barf(C_BAD_ARGUMENT_TYPE_NO_CLOSURE_ERROR, NULL, x);
 7207  }
 7208
 7209  return C_SCHEME_UNDEFINED;
 7210}
 7211
 7212C_regparm C_word C_i_check_fixnum_2(C_word x, C_word loc)
 7213{
 7214  if(!(x & C_FIXNUM_BIT)) {
 7215    error_location = loc;
 7216    barf(C_BAD_ARGUMENT_TYPE_NO_FIXNUM_ERROR, NULL, x);
 7217  }
 7218
 7219  return C_SCHEME_UNDEFINED;
 7220}
 7221
 7222/* DEPRECATED */
 7223C_regparm C_word C_i_check_exact_2(C_word x, C_word loc)
 7224{
 7225  if(C_u_i_exactp(x) == C_SCHEME_FALSE) {
 7226    error_location = loc;
 7227    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_ERROR, NULL, x);
 7228  }
 7229
 7230  return C_SCHEME_UNDEFINED;
 7231}
 7232
 7233
 7234C_regparm C_word C_i_check_inexact_2(C_word x, C_word loc)
 7235{
 7236  if(C_immediatep(x) || C_block_header(x) != C_FLONUM_TAG) {
 7237    error_location = loc;
 7238    barf(C_BAD_ARGUMENT_TYPE_NO_INEXACT_ERROR, NULL, x);
 7239  }
 7240
 7241  return C_SCHEME_UNDEFINED;
 7242}
 7243
 7244
 7245C_regparm C_word C_i_check_char_2(C_word x, C_word loc)
 7246{
 7247  if((x & C_IMMEDIATE_TYPE_BITS) != C_CHARACTER_BITS) {
 7248    error_location = loc;
 7249    barf(C_BAD_ARGUMENT_TYPE_NO_CHAR_ERROR, NULL, x);
 7250  }
 7251
 7252  return C_SCHEME_UNDEFINED;
 7253}
 7254
 7255
 7256C_regparm C_word C_i_check_number_2(C_word x, C_word loc)
 7257{
 7258  if (C_i_numberp(x) == C_SCHEME_FALSE) {
 7259    error_location = loc;
 7260    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, NULL, x);
 7261  }
 7262
 7263  return C_SCHEME_UNDEFINED;
 7264}
 7265
 7266
 7267C_regparm C_word C_i_check_string_2(C_word x, C_word loc)
 7268{
 7269  if(C_immediatep(x) || C_header_bits(x) != C_STRING_TYPE) {
 7270    error_location = loc;
 7271    barf(C_BAD_ARGUMENT_TYPE_NO_STRING_ERROR, NULL, x);
 7272  }
 7273
 7274  return C_SCHEME_UNDEFINED;
 7275}
 7276
 7277
 7278C_regparm C_word C_i_check_bytevector_2(C_word x, C_word loc)
 7279{
 7280  if(C_immediatep(x) || C_header_bits(x) != C_BYTEVECTOR_TYPE) {
 7281    error_location = loc;
 7282    barf(C_BAD_ARGUMENT_TYPE_NO_BYTEVECTOR_ERROR, NULL, x);
 7283  }
 7284
 7285  return C_SCHEME_UNDEFINED;
 7286}
 7287
 7288
 7289C_regparm C_word C_i_check_vector_2(C_word x, C_word loc)
 7290{
 7291  if(C_immediatep(x) || C_header_bits(x) != C_VECTOR_TYPE) {
 7292    error_location = loc;
 7293    barf(C_BAD_ARGUMENT_TYPE_NO_VECTOR_ERROR, NULL, x);
 7294  }
 7295
 7296  return C_SCHEME_UNDEFINED;
 7297}
 7298
 7299
 7300C_regparm C_word C_i_check_structure_2(C_word x, C_word st, C_word loc)
 7301{
 7302  if(C_immediatep(x) || C_header_bits(x) != C_STRUCTURE_TYPE || C_block_item(x,0) != st) {
 7303    error_location = loc;
 7304    barf(C_BAD_ARGUMENT_TYPE_BAD_STRUCT_ERROR, NULL, x, st);
 7305  }
 7306
 7307  return C_SCHEME_UNDEFINED;
 7308}
 7309
 7310
 7311C_regparm C_word C_i_check_pair_2(C_word x, C_word loc)
 7312{
 7313  if(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE) {
 7314    error_location = loc;
 7315    barf(C_BAD_ARGUMENT_TYPE_NO_PAIR_ERROR, NULL, x);
 7316  }
 7317
 7318  return C_SCHEME_UNDEFINED;
 7319}
 7320
 7321
 7322C_regparm C_word C_i_check_boolean_2(C_word x, C_word loc)
 7323{
 7324  if((x & C_IMMEDIATE_TYPE_BITS) != C_BOOLEAN_BITS) {
 7325    error_location = loc;
 7326    barf(C_BAD_ARGUMENT_TYPE_NO_BOOLEAN_ERROR, NULL, x);
 7327  }
 7328
 7329  return C_SCHEME_UNDEFINED;
 7330}
 7331
 7332
 7333C_regparm C_word C_i_check_locative_2(C_word x, C_word loc)
 7334{
 7335  if(C_immediatep(x) || C_block_header(x) != C_LOCATIVE_TAG) {
 7336    error_location = loc;
 7337    barf(C_BAD_ARGUMENT_TYPE_NO_LOCATIVE_ERROR, NULL, x);
 7338  }
 7339
 7340  return C_SCHEME_UNDEFINED;
 7341}
 7342
 7343
 7344C_regparm C_word C_i_check_symbol_2(C_word x, C_word loc)
 7345{
 7346  if(!C_truep(C_i_symbolp(x))) {
 7347    error_location = loc;
 7348    barf(C_BAD_ARGUMENT_TYPE_NO_SYMBOL_ERROR, NULL, x);
 7349  }
 7350
 7351  return C_SCHEME_UNDEFINED;
 7352}
 7353
 7354
 7355C_regparm C_word C_i_check_keyword_2(C_word x, C_word loc)
 7356{
 7357  if(!C_truep(C_i_keywordp(x))) {
 7358    error_location = loc;
 7359    barf(C_BAD_ARGUMENT_TYPE_NO_KEYWORD_ERROR, NULL, x);
 7360  }
 7361
 7362  return C_SCHEME_UNDEFINED;
 7363}
 7364
 7365C_regparm C_word C_i_check_list_2(C_word x, C_word loc)
 7366{
 7367  if(x != C_SCHEME_END_OF_LIST && (C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE)) {
 7368    error_location = loc;
 7369    barf(C_BAD_ARGUMENT_TYPE_NO_LIST_ERROR, NULL, x);
 7370  }
 7371
 7372  return C_SCHEME_UNDEFINED;
 7373}
 7374
 7375
 7376C_regparm C_word C_i_check_port_2(C_word x, C_word dir, C_word open, C_word loc)
 7377{
 7378
 7379  if(C_immediatep(x) || C_header_bits(x) != C_PORT_TYPE) {
 7380    error_location = loc;
 7381    barf(C_BAD_ARGUMENT_TYPE_NO_PORT_ERROR, NULL, x);
 7382  }
 7383
 7384  if((C_block_item(x, 1) & dir) != dir) {	/* slot #1: I/O direction mask */
 7385    error_location = loc;
 7386    switch (dir) {
 7387    case C_fix(1):
 7388      barf(C_BAD_ARGUMENT_TYPE_PORT_NO_INPUT_ERROR, NULL, x);
 7389    case C_fix(2):
 7390      barf(C_BAD_ARGUMENT_TYPE_PORT_NO_OUTPUT_ERROR, NULL, x);
 7391    default:
 7392      barf(C_BAD_ARGUMENT_TYPE_PORT_DIRECTION_ERROR, NULL, x);
 7393    }
 7394  }
 7395
 7396  if(open == C_SCHEME_TRUE) {
 7397    if(C_block_item(x, 8) == C_FIXNUM_BIT) {	/* slot #8: closed mask */
 7398      error_location = loc;
 7399      barf(C_PORT_CLOSED_ERROR, NULL, x);
 7400    }
 7401  }
 7402
 7403  return C_SCHEME_UNDEFINED;
 7404}
 7405
 7406
 7407C_regparm C_word C_i_check_range_2(C_word i, C_word f, C_word t, C_word loc)
 7408{
 7409  if(!(i & C_FIXNUM_BIT)) {
 7410    error_location = loc;
 7411    barf(C_BAD_ARGUMENT_TYPE_NO_FIXNUM_ERROR, NULL, i);
 7412  }
 7413
 7414  int index = C_unfix(i);
 7415
 7416  if(index < C_unfix(f)) {
 7417    error_location = loc;
 7418    barf(C_OUT_OF_BOUNDS_ERROR, NULL, f, i);
 7419  }
 7420
 7421  if(index >= C_unfix(t)) {
 7422    error_location = loc;
 7423    barf(C_OUT_OF_BOUNDS_ERROR, NULL, t, i);
 7424  }
 7425
 7426  return C_SCHEME_UNDEFINED;
 7427}
 7428
 7429
 7430C_regparm C_word C_i_check_range_including_2(C_word i, C_word f, C_word t, C_word loc)
 7431{
 7432  if(!(i & C_FIXNUM_BIT)) {
 7433    error_location = loc;
 7434    barf(C_BAD_ARGUMENT_TYPE_NO_FIXNUM_ERROR, NULL, i);
 7435  }
 7436
 7437  int index = C_unfix(i);
 7438
 7439  if(index < C_unfix(f)) {
 7440    error_location = loc;
 7441    barf(C_OUT_OF_BOUNDS_ERROR, NULL, f, i);
 7442  }
 7443
 7444  if(index > C_unfix(t)) {
 7445    error_location = loc;
 7446    barf(C_OUT_OF_BOUNDS_ERROR, NULL, t, i);
 7447  }
 7448
 7449  return C_SCHEME_UNDEFINED;
 7450}
 7451
 7452
 7453/*XXX these are not correctly named */
 7454C_regparm C_word C_i_foreign_char_argumentp(C_word x)
 7455{
 7456  if((x & C_IMMEDIATE_TYPE_BITS) != C_CHARACTER_BITS)
 7457    barf(C_BAD_ARGUMENT_TYPE_NO_CHAR_ERROR, NULL, x);
 7458
 7459  return x;
 7460}
 7461
 7462
 7463C_regparm C_word C_i_foreign_fixnum_argumentp(C_word x)
 7464{
 7465  if((x & C_FIXNUM_BIT) == 0)
 7466    barf(C_BAD_ARGUMENT_TYPE_NO_FIXNUM_ERROR, NULL, x);
 7467
 7468  return x;
 7469}
 7470
 7471
 7472C_regparm C_word C_i_foreign_flonum_argumentp(C_word x)
 7473{
 7474  if((x & C_FIXNUM_BIT) != 0) return x;
 7475
 7476  if(C_immediatep(x) || C_block_header(x) != C_FLONUM_TAG)
 7477    barf(C_BAD_ARGUMENT_TYPE_NO_FLONUM_ERROR, NULL, x);
 7478
 7479  return x;
 7480}
 7481
 7482
 7483C_regparm C_word C_i_foreign_cplxnum_argumentp(C_word x)
 7484{
 7485  if((x & C_FIXNUM_BIT) != 0) return x;
 7486
 7487  if(C_immediatep(x) || C_block_header(x) != C_FLONUM_TAG)
 7488    barf(C_BAD_ARGUMENT_TYPE_NO_FLONUM_ERROR, NULL, x);
 7489
 7490  return x;
 7491}
 7492
 7493
 7494C_regparm C_word C_i_foreign_block_argumentp(C_word x)
 7495{
 7496  if(C_immediatep(x))
 7497    barf(C_BAD_ARGUMENT_TYPE_NO_BLOCK_ERROR, NULL, x);
 7498
 7499  return x;
 7500}
 7501
 7502
 7503C_regparm C_word C_i_foreign_struct_wrapper_argumentp(C_word t, C_word x)
 7504{
 7505  if(C_immediatep(x) || C_header_bits(x) != C_STRUCTURE_TYPE || C_block_item(x, 0) != t)
 7506    barf(C_BAD_ARGUMENT_TYPE_BAD_STRUCT_ERROR, NULL, t, x);
 7507
 7508  return x;
 7509}
 7510
 7511
 7512C_regparm C_word C_i_foreign_string_argumentp(C_word x)
 7513{
 7514  if(C_immediatep(x) || C_header_bits(x) != C_STRING_TYPE)
 7515    barf(C_BAD_ARGUMENT_TYPE_NO_STRING_ERROR, NULL, x);
 7516
 7517  return x;
 7518}
 7519
 7520
 7521C_regparm C_word C_i_foreign_symbol_argumentp(C_word x)
 7522{
 7523  if(C_immediatep(x) || C_header_bits(x) != C_SYMBOL_TYPE)
 7524    barf(C_BAD_ARGUMENT_TYPE_NO_SYMBOL_ERROR, NULL, x);
 7525
 7526  return x;
 7527}
 7528
 7529
 7530C_regparm C_word C_i_foreign_pointer_argumentp(C_word x)
 7531{
 7532  if(C_immediatep(x) || (C_header_bits(x) & C_SPECIALBLOCK_BIT) == 0)
 7533    barf(C_BAD_ARGUMENT_TYPE_NO_POINTER_ERROR, NULL, x);
 7534
 7535  return x;
 7536}
 7537
 7538
 7539/* TODO: Is this used? */
 7540C_regparm C_word C_i_foreign_scheme_or_c_pointer_argumentp(C_word x)
 7541{
 7542  if(C_immediatep(x) || (C_header_bits(x) & C_SPECIALBLOCK_BIT) == 0)
 7543    barf(C_BAD_ARGUMENT_TYPE_NO_POINTER_ERROR, NULL, x);
 7544
 7545  return x;
 7546}
 7547
 7548
 7549C_regparm C_word C_i_foreign_tagged_pointer_argumentp(C_word x, C_word t)
 7550{
 7551  if(C_immediatep(x) || (C_header_bits(x) & C_SPECIALBLOCK_BIT) == 0
 7552     || (t != C_SCHEME_FALSE && !C_equalp(C_block_item(x, 1), t)))
 7553    barf(C_BAD_ARGUMENT_TYPE_NO_TAGGED_POINTER_ERROR, NULL, x, t);
 7554
 7555  return x;
 7556}
 7557
 7558C_regparm C_word C_i_foreign_ranged_integer_argumentp(C_word x, C_word bits)
 7559{
 7560  if((x & C_FIXNUM_BIT) != 0) {
 7561    if (C_truep(C_fixnum_lessp(C_i_fixnum_length(x), bits))) return x;
 7562    else barf(C_BAD_ARGUMENT_TYPE_FOREIGN_LIMITATION, NULL, x);
 7563  } else if (C_truep(C_i_bignump(x))) {
 7564    if (C_truep(C_fixnum_lessp(C_i_integer_length(x), bits))) return x;
 7565    else barf(C_BAD_ARGUMENT_TYPE_FOREIGN_LIMITATION, NULL, x);
 7566  } else {
 7567    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, NULL, x);
 7568  }
 7569}
 7570
 7571C_regparm C_word C_i_foreign_unsigned_ranged_integer_argumentp(C_word x, C_word bits)
 7572{
 7573  if((x & C_FIXNUM_BIT) != 0) {
 7574    if(x & C_INT_SIGN_BIT) barf(C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR, NULL, x);
 7575    else if(C_ilen(C_unfix(x)) <= C_unfix(bits)) return x;
 7576    else barf(C_BAD_ARGUMENT_TYPE_FOREIGN_LIMITATION, NULL, x);
 7577  } else if(C_truep(C_i_bignump(x))) {
 7578    if(C_bignum_negativep(x)) barf(C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR, NULL, x);
 7579    else if(integer_length_abs(x) <= C_unfix(bits)) return x;
 7580    else barf(C_BAD_ARGUMENT_TYPE_FOREIGN_LIMITATION, NULL, x);
 7581  } else {
 7582    barf(C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR, NULL, x);
 7583  }
 7584}
 7585
 7586/* I */
 7587C_regparm C_word C_i_not_pair_p_2(C_word x)
 7588{
 7589  return C_mk_bool(C_immediatep(x) || C_header_type(x) != C_PAIR_TYPE);
 7590}
 7591
 7592
 7593C_regparm C_word C_i_null_list_p(C_word x)
 7594{
 7595  if(x == C_SCHEME_END_OF_LIST) return C_SCHEME_TRUE;
 7596  else if(!C_immediatep(x) && C_header_type(x) == C_PAIR_TYPE) return C_SCHEME_FALSE;
 7597  else {
 7598    barf(C_BAD_ARGUMENT_TYPE_NO_LIST_ERROR, "null-list?", x);
 7599    return C_SCHEME_FALSE;
 7600  }
 7601}
 7602
 7603
 7604C_regparm C_word C_i_string_null_p(C_word x)
 7605{
 7606  if(!C_immediatep(x) && C_header_bits(x) == C_STRING_TYPE)
 7607    return C_mk_bool(C_unfix(C_block_item(x, 1)) == 0);
 7608  else {
 7609    barf(C_BAD_ARGUMENT_TYPE_NO_STRING_ERROR, "string-null?", x);
 7610    return C_SCHEME_FALSE;
 7611  }
 7612}
 7613
 7614
 7615C_regparm C_word C_i_null_pointerp(C_word x)
 7616{
 7617  if(!C_immediatep(x) && (C_header_bits(x) & C_SPECIALBLOCK_BIT) != 0)
 7618    return C_null_pointerp(x);
 7619
 7620  barf(C_BAD_ARGUMENT_TYPE_ERROR, "null-pointer?", x);
 7621  return C_SCHEME_FALSE;
 7622}
 7623
 7624/* only used here for char comparators below: */
 7625static C_word check_char_internal(C_word x, C_char *loc)
 7626{
 7627  if((x & C_IMMEDIATE_TYPE_BITS) != C_CHARACTER_BITS) {
 7628    error_location = intern0(loc);
 7629    barf(C_BAD_ARGUMENT_TYPE_NO_CHAR_ERROR, NULL, x);
 7630  }
 7631
 7632  return C_SCHEME_UNDEFINED;
 7633}
 7634
 7635C_regparm C_word C_i_char_equalp(C_word x, C_word y)
 7636{
 7637  check_char_internal(x, "char=?");
 7638  check_char_internal(y, "char=?");
 7639  return C_u_i_char_equalp(x, y);
 7640}
 7641
 7642C_regparm C_word C_i_char_greaterp(C_word x, C_word y)
 7643{
 7644  check_char_internal(x, "char>?");
 7645  check_char_internal(y, "char>?");
 7646  return C_u_i_char_greaterp(x, y);
 7647}
 7648
 7649C_regparm C_word C_i_char_lessp(C_word x, C_word y)
 7650{
 7651  check_char_internal(x, "char<?");
 7652  check_char_internal(y, "char<?");
 7653  return C_u_i_char_lessp(x, y);
 7654}
 7655
 7656C_regparm C_word C_i_char_greater_or_equal_p(C_word x, C_word y)
 7657{
 7658  check_char_internal(x, "char>=?");
 7659  check_char_internal(y, "char>=?");
 7660  return C_u_i_char_greater_or_equal_p(x, y);
 7661}
 7662
 7663C_regparm C_word C_i_char_less_or_equal_p(C_word x, C_word y)
 7664{
 7665  check_char_internal(x, "char<=?");
 7666  check_char_internal(y, "char<=?");
 7667  return C_u_i_char_less_or_equal_p(x, y);
 7668}
 7669
 7670
 7671/* Primitives: */
 7672
 7673void C_ccall C_apply(C_word c, C_word *av)
 7674{
 7675  C_word
 7676    /* closure = av[ 0 ] */
 7677    k = av[ 1 ],
 7678    fn = av[ 2 ];
 7679  int av2_size, i, n = c - 3;
 7680  int non_list_args = n - 1;
 7681  C_word lst, len, *ptr, *av2;
 7682
 7683  if(c < 4) C_bad_min_argc(c, 4);
 7684
 7685  if(C_immediatep(fn) || C_header_bits(fn) != C_CLOSURE_TYPE)
 7686    barf(C_NOT_A_CLOSURE_ERROR, "apply", fn);
 7687
 7688  lst = av[ c - 1 ];
 7689  if(lst != C_SCHEME_END_OF_LIST && (C_immediatep(lst) || C_header_type(lst) != C_PAIR_TYPE))
 7690    barf(C_BAD_ARGUMENT_TYPE_ERROR, "apply", lst);
 7691
 7692  len = C_unfix(C_u_i_length(lst));
 7693  av2_size = 2 + non_list_args + len;
 7694
 7695  if(C_demand(av2_size))
 7696    stack_check_demand = 0;
 7697  else if(stack_check_demand)
 7698    C_stack_overflow("apply");
 7699  else {
 7700    stack_check_demand = av2_size;
 7701    C_save_and_reclaim((void *)C_apply, c, av);
 7702  }
 7703
 7704  av2 = ptr = C_alloc(av2_size);
 7705  *(ptr++) = fn;
 7706  *(ptr++) = k;
 7707
 7708  if(non_list_args > 0) {
 7709    C_memcpy(ptr, av + 3, non_list_args * sizeof(C_word));
 7710    ptr += non_list_args;
 7711  }
 7712
 7713  while(len--) {
 7714    *(ptr++) = C_u_i_car(lst);
 7715    lst = C_u_i_cdr(lst);
 7716  }
 7717
 7718  assert((ptr - av2) == av2_size);
 7719
 7720  ((C_proc)(void *)C_block_item(fn, 0))(av2_size, av2);
 7721}
 7722
 7723
 7724void C_ccall C_call_cc(C_word c, C_word *av)
 7725{
 7726  C_word
 7727    /* closure = av[ 0 ] */
 7728    k = av[ 1 ],
 7729    cont = av[ 2 ],
 7730    *a = C_alloc(C_SIZEOF_CLOSURE(2)),
 7731    wrapper;
 7732  void *pr = (void *)C_block_item(cont,0);
 7733  C_word av2[ 3 ];
 7734
 7735  if(C_immediatep(cont) || C_header_bits(cont) != C_CLOSURE_TYPE)
 7736    barf(C_BAD_ARGUMENT_TYPE_ERROR, "call-with-current-continuation", cont);
 7737
 7738  /* Check for values-continuation: */
 7739  if(C_block_item(k, 0) == (C_word)values_continuation)
 7740    wrapper = C_closure(&a, 2, (C_word)call_cc_values_wrapper, k);
 7741  else wrapper = C_closure(&a, 2, (C_word)call_cc_wrapper, k);
 7742
 7743  av2[ 0 ] = cont;
 7744  av2[ 1 ] = k;
 7745  av2[ 2 ] = wrapper;
 7746  ((C_proc)pr)(3, av2);
 7747}
 7748
 7749
 7750void C_ccall call_cc_wrapper(C_word c, C_word *av)
 7751{
 7752  C_word
 7753    closure = av[ 0 ],
 7754    /* av[ 1 ] is current k and ignored */
 7755    result,
 7756    k = C_block_item(closure, 1);
 7757
 7758  if(c != 3) C_bad_argc(c, 3);
 7759
 7760  result = av[ 2 ];
 7761  C_kontinue(k, result);
 7762}
 7763
 7764
 7765void C_ccall call_cc_values_wrapper(C_word c, C_word *av)
 7766{
 7767  C_word
 7768    closure = av[ 0 ],
 7769    /* av[ 1 ] is current k and ignored */
 7770    k = C_block_item(closure, 1),
 7771    x1,
 7772    n = c;
 7773
 7774  av[ 0 ] = k;               /* reuse av */
 7775  C_memmove(av + 1, av + 2, (n - 1) * sizeof(C_word));
 7776  C_do_apply(n - 1, av);
 7777}
 7778
 7779
 7780void C_ccall C_continuation_graft(C_word c, C_word *av)
 7781{
 7782  C_word
 7783    /* self = av[ 0 ] */
 7784    /* k = av[ 1 ] */
 7785    kk = av[ 2 ],
 7786    proc = av[ 3 ];
 7787
 7788  av[ 0 ] = proc;               /* reuse av */
 7789  av[ 1 ] = C_block_item(kk, 1);
 7790  ((C_proc)C_fast_retrieve_proc(proc))(2, av);
 7791}
 7792
 7793
 7794void C_ccall C_values(C_word c, C_word *av)
 7795{
 7796  C_word
 7797    /* closure = av[ 0 ] */
 7798    k = av[ 1 ],
 7799    n = c;
 7800
 7801  if(c < 2) C_bad_min_argc(c, 2);
 7802
 7803  /* Check continuation whether it receives multiple values: */
 7804  if(C_block_item(k, 0) == (C_word)values_continuation) {
 7805    av[ 0 ] = k;                /* reuse av */
 7806    C_memmove(av + 1, av + 2, (c - 2) * sizeof(C_word));
 7807    C_do_apply(c - 1, av);
 7808  }
 7809
 7810  if(c != 3) {
 7811#ifdef RELAX_MULTIVAL_CHECK
 7812    if(c == 2) n = C_SCHEME_UNDEFINED;
 7813    else n = av[ 2 ];
 7814#else
 7815    barf(C_CONTINUATION_CANT_RECEIVE_VALUES_ERROR, "values", k);
 7816#endif
 7817  }
 7818  else n = av[ 2 ];
 7819
 7820  C_kontinue(k, n);
 7821}
 7822
 7823
 7824void C_ccall C_apply_values(C_word c, C_word *av)
 7825{
 7826  C_word
 7827    /* closure = av[ 0 ] */
 7828    k = av[ 1 ],
 7829    lst, len, n;
 7830
 7831  if(c != 3) C_bad_argc(c, 3);
 7832
 7833  lst = av[ 2 ];
 7834
 7835  if(lst != C_SCHEME_END_OF_LIST && (C_immediatep(lst) || C_header_type(lst) != C_PAIR_TYPE))
 7836    barf(C_BAD_ARGUMENT_TYPE_ERROR, "apply", lst);
 7837
 7838  /* Check whether continuation receives multiple values: */
 7839  if(C_block_item(k, 0) == (C_word)values_continuation) {
 7840    C_word *av2, *ptr;
 7841
 7842    len = C_unfix(C_u_i_length(lst));
 7843    n = len + 1;
 7844
 7845    if(C_demand(n))
 7846      stack_check_demand = 0;
 7847    else if(stack_check_demand)
 7848      C_stack_overflow("apply");
 7849    else {
 7850      stack_check_demand = n;
 7851      C_save_and_reclaim((void *)C_apply_values, c, av);
 7852    }
 7853
 7854    av2 = C_alloc(n);
 7855    av2[ 0 ] = k;
 7856    ptr = av2 + 1;
 7857    while(len--) {
 7858      *(ptr++) = C_u_i_car(lst);
 7859      lst = C_u_i_cdr(lst);
 7860    }
 7861
 7862    C_do_apply(n, av2);
 7863  }
 7864
 7865  if(C_immediatep(lst)) {
 7866#ifdef RELAX_MULTIVAL_CHECK
 7867    n = C_SCHEME_UNDEFINED;
 7868#else
 7869    barf(C_CONTINUATION_CANT_RECEIVE_VALUES_ERROR, "values", k);
 7870#endif
 7871  }
 7872  else if(C_header_type(lst) == C_PAIR_TYPE) {
 7873    if(C_u_i_cdr(lst) == C_SCHEME_END_OF_LIST)
 7874      n = C_u_i_car(lst);
 7875    else {
 7876#ifdef RELAX_MULTIVAL_CHECK
 7877      n = C_u_i_car(lst);
 7878#else
 7879      barf(C_CONTINUATION_CANT_RECEIVE_VALUES_ERROR, "values", k);
 7880#endif
 7881    }
 7882  }
 7883  else barf(C_BAD_ARGUMENT_TYPE_ERROR, "apply", lst);
 7884
 7885  C_kontinue(k, n);
 7886}
 7887
 7888
 7889void C_ccall C_call_with_values(C_word c, C_word *av)
 7890{
 7891  C_word
 7892    /* closure = av[ 0 ] */
 7893    k = av[ 1 ],
 7894    thunk,
 7895    kont,
 7896    *a = C_alloc(C_SIZEOF_CLOSURE(3)),
 7897    kk;
 7898
 7899  if(c != 4) C_bad_argc(c, 4);
 7900
 7901  thunk = av[ 2 ];
 7902  kont = av[ 3 ];
 7903
 7904  if(C_immediatep(thunk) || C_header_bits(thunk) != C_CLOSURE_TYPE)
 7905    barf(C_BAD_ARGUMENT_TYPE_ERROR, "call-with-values", thunk);
 7906
 7907  if(C_immediatep(kont) || C_header_bits(kont) != C_CLOSURE_TYPE)
 7908    barf(C_BAD_ARGUMENT_TYPE_ERROR, "call-with-values", kont);
 7909
 7910  kk = C_closure(&a, 3, (C_word)values_continuation, kont, k);
 7911  av[ 0 ] = thunk;              /* reuse av */
 7912  av[ 1 ] = kk;
 7913  C_do_apply(2, av);
 7914}
 7915
 7916
 7917void C_ccall C_u_call_with_values(C_word c, C_word *av)
 7918{
 7919  C_word
 7920    /* closure = av[ 0 ] */
 7921    k = av[ 1 ],
 7922    thunk = av[ 2 ],
 7923    kont = av[ 3 ],
 7924    *a = C_alloc(C_SIZEOF_CLOSURE(3)),
 7925    kk;
 7926
 7927  kk = C_closure(&a, 3, (C_word)values_continuation, kont, k);
 7928  av[ 0 ] = thunk;              /* reuse av */
 7929  av[ 1 ] = kk;
 7930  C_do_apply(2, av);
 7931}
 7932
 7933
 7934void C_ccall values_continuation(C_word c, C_word *av)
 7935{
 7936  C_word
 7937    closure = av[ 0 ],
 7938    kont = C_block_item(closure, 1),
 7939    k = C_block_item(closure, 2),
 7940    *av2 = C_alloc(c + 1);
 7941
 7942  av2[ 0 ] = kont;
 7943  av2[ 1 ] = k;
 7944  C_memcpy(av2 + 2, av + 1, (c - 1) * sizeof(C_word));
 7945  C_do_apply(c + 1, av2);
 7946}
 7947
 7948static C_word rat_times_integer(C_word **ptr, C_word rat, C_word i)
 7949{
 7950  C_word ab[C_SIZEOF_FIX_BIGNUM * 2], *a = ab, num, denom, gcd, a_div_g;
 7951
 7952  switch (i) {
 7953  case C_fix(0): return C_fix(0);
 7954  case C_fix(1): return rat;
 7955  case C_fix(-1):
 7956    num = C_s_a_u_i_integer_negate(ptr, 1, C_u_i_ratnum_num(rat));
 7957    return C_ratnum(ptr, num , C_u_i_ratnum_denom(rat));
 7958  /* default: CONTINUE BELOW */
 7959  }
 7960
 7961  num = C_u_i_ratnum_num(rat);
 7962  denom = C_u_i_ratnum_denom(rat);
 7963
 7964  /* a/b * c/d = a*c / b*d  [with b = 1] */
 7965  /*  =  ((a / g) * c) / (d / g) */
 7966  /* With   g = gcd(a, d)   and  a = x   [Knuth, 4.5.1] */
 7967  gcd = C_s_a_u_i_integer_gcd(&a, 2, i, denom);
 7968
 7969  /* Calculate a/g  (= i/gcd), which will later be multiplied by y */
 7970  a_div_g = C_s_a_u_i_integer_quotient(&a, 2, i, gcd);
 7971  if (a_div_g == C_fix(0)) {
 7972    clear_buffer_object(ab, gcd);
 7973    return C_fix(0); /* Save some work */
 7974  }
 7975
 7976  /* Final numerator = a/g * c  (= a_div_g * num) */
 7977  num = C_s_a_u_i_integer_times(ptr, 2, a_div_g, num);
 7978
 7979  /* Final denominator = d/g  (= denom/gcd) */
 7980  denom = C_s_a_u_i_integer_quotient(ptr, 2, denom, gcd);
 7981
 7982  num = move_buffer_object(ptr, ab, num);
 7983  denom = move_buffer_object(ptr, ab, denom);
 7984
 7985  clear_buffer_object(ab, gcd);
 7986  clear_buffer_object(ab, a_div_g);
 7987
 7988  if (denom == C_fix(1)) return num;
 7989  else return C_ratnum(ptr, num, denom);
 7990}
 7991
 7992static C_word rat_times_rat(C_word **ptr, C_word x, C_word y)
 7993{
 7994  C_word ab[C_SIZEOF_FIX_BIGNUM * 6], *a = ab,
 7995         num, denom, xnum, xdenom, ynum, ydenom,
 7996         g1, g2, a_div_g1, b_div_g2, c_div_g2, d_div_g1;
 7997
 7998  xnum = C_u_i_ratnum_num(x);
 7999  xdenom = C_u_i_ratnum_denom(x);
 8000  ynum = C_u_i_ratnum_num(y);
 8001  ydenom = C_u_i_ratnum_denom(y);
 8002
 8003  /* a/b * c/d = a*c / b*d  [generic] */
 8004  /*   = ((a / g1) * (c / g2)) / ((b / g2) * (d / g1)) */
 8005  /* With  g1 = gcd(a, d)  and   g2 = gcd(b, c) [Knuth, 4.5.1] */
 8006  g1 = C_s_a_u_i_integer_gcd(&a, 2, xnum, ydenom);
 8007  g2 = C_s_a_u_i_integer_gcd(&a, 2, ynum, xdenom);
 8008
 8009  /* Calculate a/g1  (= xnum/g1), which will later be multiplied by c/g2 */
 8010  a_div_g1 = C_s_a_u_i_integer_quotient(&a, 2, xnum, g1);
 8011
 8012  /* Calculate c/g2  (= ynum/g2), which will later be multiplied by a/g1 */
 8013  c_div_g2 = C_s_a_u_i_integer_quotient(&a, 2, ynum, g2);
 8014
 8015  /* Final numerator = a/g1 * c/g2 */
 8016  num = C_s_a_u_i_integer_times(ptr, 2, a_div_g1, c_div_g2);
 8017
 8018  /* Now, do the same for the denominator.... */
 8019
 8020  /* Calculate b/g2  (= xdenom/g2), which will later be multiplied by d/g1 */
 8021  b_div_g2 = C_s_a_u_i_integer_quotient(&a, 2, xdenom, g2);
 8022
 8023  /* Calculate d/g1  (= ydenom/g1), which will later be multiplied by b/g2 */
 8024  d_div_g1 = C_s_a_u_i_integer_quotient(&a, 2, ydenom, g1);
 8025
 8026  /* Final denominator = b/g2 * d/g1 */
 8027  denom = C_s_a_u_i_integer_times(ptr, 2, b_div_g2, d_div_g1);
 8028
 8029  num = move_buffer_object(ptr, ab, num);
 8030  denom = move_buffer_object(ptr, ab, denom);
 8031
 8032  clear_buffer_object(ab, g1);
 8033  clear_buffer_object(ab, g2);
 8034  clear_buffer_object(ab, a_div_g1);
 8035  clear_buffer_object(ab, b_div_g2);
 8036  clear_buffer_object(ab, c_div_g2);
 8037  clear_buffer_object(ab, d_div_g1);
 8038
 8039  if (denom == C_fix(1)) return num;
 8040  else return C_ratnum(ptr, num, denom);
 8041}
 8042
 8043static C_word
 8044cplx_times(C_word **ptr, C_word rx, C_word ix, C_word ry, C_word iy)
 8045{
 8046  /* Allocation here is kind of tricky: Each intermediate result can
 8047   * be at most a ratnum consisting of two bignums (2 digits), so
 8048   * C_SIZEOF_RATNUM + C_SIZEOF_BIGNUM(2) = 9 words
 8049   */
 8050  C_word ab[(C_SIZEOF_RATNUM + C_SIZEOF_BIGNUM(2))*6], *a = ab,
 8051         r1, r2, i1, i2, r, i;
 8052
 8053  /* a+bi * c+di = (a*c - b*d) + (a*d + b*c)i */
 8054  /* We call these:  r1 = a*c, r2 = b*d, i1 = a*d, i2 = b*c */
 8055  r1 = C_s_a_i_times(&a, 2, rx, ry);
 8056  r2 = C_s_a_i_times(&a, 2, ix, iy);
 8057  i1 = C_s_a_i_times(&a, 2, rx, iy);
 8058  i2 = C_s_a_i_times(&a, 2, ix, ry);
 8059
 8060  r = C_s_a_i_minus(ptr, 2, r1, r2);
 8061  i = C_s_a_i_plus(ptr, 2, i1, i2);
 8062
 8063  r = move_buffer_object(ptr, ab, r);
 8064  i = move_buffer_object(ptr, ab, i);
 8065
 8066  clear_buffer_object(ab, r1);
 8067  clear_buffer_object(ab, r2);
 8068  clear_buffer_object(ab, i1);
 8069  clear_buffer_object(ab, i2);
 8070
 8071  if (C_truep(C_u_i_zerop2(i))) return r;
 8072  else return C_cplxnum(ptr, r, i);
 8073}
 8074
 8075/* The maximum size this needs is that required to store a complex
 8076 * number result, where both real and imag parts consist of ratnums.
 8077 * The maximum size of those ratnums is if they consist of two bignums
 8078 * from a fixnum multiplication (2 digits each), so we're looking at
 8079 * C_SIZEOF_RATNUM * 3 + C_SIZEOF_BIGNUM(2) * 4 = 33 words!
 8080 */
 8081C_regparm C_word
 8082C_s_a_i_times(C_word **ptr, C_word n, C_word x, C_word y)
 8083{
 8084  if (x & C_FIXNUM_BIT) {
 8085    if (y & C_FIXNUM_BIT) {
 8086      return C_a_i_fixnum_times(ptr, 2, x, y);
 8087    } else if (C_immediatep(y)) {
 8088      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", y);
 8089    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8090      return C_flonum(ptr, (double)C_unfix(x) * C_flonum_magnitude(y));
 8091    } else if (C_truep(C_bignump(y))) {
 8092      return C_s_a_u_i_integer_times(ptr, 2, x, y);
 8093    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8094      return rat_times_integer(ptr, y, x);
 8095    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8096      return cplx_times(ptr, x, C_fix(0),
 8097                        C_u_i_cplxnum_real(y), C_u_i_cplxnum_imag(y));
 8098    } else {
 8099      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", y);
 8100    }
 8101  } else if (C_immediatep(x)) {
 8102    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", x);
 8103  } else if (C_block_header(x) == C_FLONUM_TAG) {
 8104    if (y & C_FIXNUM_BIT) {
 8105      return C_flonum(ptr, C_flonum_magnitude(x) * (double)C_unfix(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_a_i_flonum_times(ptr, 2, x, y);
 8110    } else if (C_truep(C_bignump(y))) {
 8111      return C_flonum(ptr, C_flonum_magnitude(x) * C_bignum_to_double(y));
 8112    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8113      return C_s_a_i_times(ptr, 2, x, C_a_i_exact_to_inexact(ptr, 1, y));
 8114    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8115      C_word ab[C_SIZEOF_FLONUM], *a = ab;
 8116      return cplx_times(ptr, x, C_flonum(&a, 0.0),
 8117                        C_u_i_cplxnum_real(y), C_u_i_cplxnum_imag(y));
 8118    } else {
 8119      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", y);
 8120    }
 8121  } else if (C_truep(C_bignump(x))) {
 8122    if (y & C_FIXNUM_BIT) {
 8123      return C_s_a_u_i_integer_times(ptr, 2, x, y);
 8124    } else if (C_immediatep(y)) {
 8125      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", x);
 8126    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8127      return C_flonum(ptr, C_bignum_to_double(x) * C_flonum_magnitude(y));
 8128    } else if (C_truep(C_bignump(y))) {
 8129      return C_s_a_u_i_integer_times(ptr, 2, x, y);
 8130    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8131      return rat_times_integer(ptr, y, x);
 8132    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8133      return cplx_times(ptr, x, C_fix(0),
 8134                        C_u_i_cplxnum_real(y), C_u_i_cplxnum_imag(y));
 8135    } else {
 8136      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", y);
 8137    }
 8138  } else if (C_block_header(x) == C_RATNUM_TAG) {
 8139    if (y & C_FIXNUM_BIT) {
 8140      return rat_times_integer(ptr, x, y);
 8141    } else if (C_immediatep(y)) {
 8142      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", y);
 8143    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8144      return C_s_a_i_times(ptr, 2, C_a_i_exact_to_inexact(ptr, 1, x), y);
 8145    } else if (C_truep(C_bignump(y))) {
 8146      return rat_times_integer(ptr, x, y);
 8147    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8148        return rat_times_rat(ptr, x, y);
 8149    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8150      return cplx_times(ptr, x, C_fix(0),
 8151                        C_u_i_cplxnum_real(y), C_u_i_cplxnum_imag(y));
 8152    } else {
 8153      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", y);
 8154    }
 8155  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 8156    if (!C_immediatep(y) && C_block_header(y) == C_CPLXNUM_TAG) {
 8157      return cplx_times(ptr, C_u_i_cplxnum_real(x), C_u_i_cplxnum_imag(x),
 8158                        C_u_i_cplxnum_real(y), C_u_i_cplxnum_imag(y));
 8159    } else {
 8160      C_word ab[C_SIZEOF_FLONUM], *a = ab, yi;
 8161      yi = C_truep(C_i_flonump(y)) ? C_flonum(&a,0) : C_fix(0);
 8162      return cplx_times(ptr, C_u_i_ratnum_num(x), C_u_i_ratnum_denom(x), y, yi);
 8163    }
 8164  } else {
 8165    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "*", x);
 8166  }
 8167}
 8168
 8169
 8170C_regparm C_word
 8171C_s_a_u_i_integer_times(C_word **ptr, C_word n, C_word x, C_word y)
 8172{
 8173  if (x & C_FIXNUM_BIT) {
 8174    if (y & C_FIXNUM_BIT) {
 8175      return C_a_i_fixnum_times(ptr, 2, x, y);
 8176    } else {
 8177      C_word tmp = x; /* swap to ensure x is a bignum and y a fixnum */
 8178      x = y;
 8179      y = tmp;
 8180    }
 8181  }
 8182  /* Here, we know for sure that X is a bignum */
 8183  if (y == C_fix(0)) {
 8184    return C_fix(0);
 8185  } else if (y == C_fix(1)) {
 8186    return x;
 8187  } else if (y == C_fix(-1)) {
 8188    return C_s_a_u_i_integer_negate(ptr, 1, x);
 8189  } else if (y & C_FIXNUM_BIT) { /* Any other fixnum */
 8190    C_word absy = (y & C_INT_SIGN_BIT) ? -C_unfix(y) : C_unfix(y),
 8191           negp = C_mk_bool((y & C_INT_SIGN_BIT) ?
 8192                            !C_bignum_negativep(x) :
 8193                            C_bignum_negativep(x));
 8194
 8195    if (C_fitsinbignumhalfdigitp(absy) ||
 8196        (((C_uword)1 << (C_ilen(absy)-1)) == absy && C_fitsinfixnump(absy))) {
 8197      C_word size, res;
 8198      C_uword *startr, *endr;
 8199      int shift;
 8200      size = C_bignum_size(x) + 1; /* Needs _at most_ one more digit */
 8201      res = C_allocate_scratch_bignum(ptr, C_fix(size), negp, C_SCHEME_FALSE);
 8202
 8203      bignum_digits_destructive_copy(res, x);
 8204
 8205      startr = C_bignum_digits(res);
 8206      endr = startr + size - 1;
 8207      /* Scale up, and sanitise the result. */
 8208      shift = C_ilen(absy) - 1;
 8209      if (((C_uword)1 << shift) == absy) { /* Power of two? */
 8210        *endr = bignum_digits_destructive_shift_left(startr, endr, shift);
 8211      } else {
 8212        *endr = bignum_digits_destructive_scale_up_with_carry(startr, endr,
 8213                                                              absy, 0);
 8214      }
 8215      return C_bignum_simplify(res);
 8216    } else {
 8217      C_word *a = C_alloc(C_SIZEOF_FIX_BIGNUM);
 8218      y = C_a_u_i_fix_to_big(&a, y);
 8219      return bignum_times_bignum_unsigned(ptr, x, y, negp);
 8220    }
 8221  } else {
 8222    C_word negp = C_bignum_negativep(x) ?
 8223                  !C_bignum_negativep(y) :
 8224                  C_bignum_negativep(y);
 8225    return bignum_times_bignum_unsigned(ptr, x, y, C_mk_bool(negp));
 8226  }
 8227}
 8228
 8229static C_regparm C_word
 8230bignum_times_bignum_unsigned(C_word **ptr, C_word x, C_word y, C_word negp)
 8231{
 8232  C_word size, res = C_SCHEME_FALSE;
 8233  if (C_bignum_size(y) < C_bignum_size(x)) { /* Ensure size(x) <= size(y) */
 8234    C_word z = x;
 8235    x = y;
 8236    y = z;
 8237  }
 8238
 8239  if (C_bignum_size(x) >= C_KARATSUBA_THRESHOLD)
 8240    res = bignum_times_bignum_karatsuba(ptr, x, y, negp);
 8241
 8242  if (!C_truep(res)) {
 8243    size = C_bignum_size(x) + C_bignum_size(y);
 8244    res = C_allocate_scratch_bignum(ptr, C_fix(size), negp, C_SCHEME_TRUE);
 8245    bignum_digits_multiply(x, y, res);
 8246    res = C_bignum_simplify(res);
 8247  }
 8248  return res;
 8249}
 8250
 8251/* Karatsuba multiplication: invoked when the two numbers are large
 8252 * enough to make it worthwhile, and we still have enough stack left.
 8253 * Complexity is O(n^log2(3)), where n is max(len(x), len(y)).  The
 8254 * description in [Knuth, 4.3.3] leaves a lot to be desired.  [MCA,
 8255 * 1.3.2] and [MpNT, 3.2] are a bit easier to understand.  We assume
 8256 * that length(x) <= length(y).
 8257 */
 8258static C_regparm C_word
 8259bignum_times_bignum_karatsuba(C_word **ptr, C_word x, C_word y, C_word negp)
 8260{
 8261   C_word kab[C_SIZEOF_FIX_BIGNUM*15+C_SIZEOF_BIGNUM(2)*3], *ka = kab, o[18],
 8262          xhi, xlo, xmid, yhi, ylo, ymid, a, b, c, n, bits;
 8263   int i = 0;
 8264
 8265   /* Ran out of stack?  Fall back to non-recursive multiplication */
 8266   C_stack_check1(return C_SCHEME_FALSE);
 8267
 8268   /* Split |x| in half: <xhi,xlo> and |y|: <yhi,ylo> with len(ylo)=len(xlo) */
 8269   x = o[i++] = C_s_a_u_i_integer_abs(&ka, 1, x);
 8270   y = o[i++] = C_s_a_u_i_integer_abs(&ka, 1, y);
 8271   n = C_fix(C_bignum_size(y) >> 1);
 8272   xhi = o[i++] = bignum_extract_digits(&ka, 3, x, n, C_SCHEME_FALSE);
 8273   xlo = o[i++] = bignum_extract_digits(&ka, 3, x, C_fix(0), n);
 8274   yhi = o[i++] = bignum_extract_digits(&ka, 3, y, n, C_SCHEME_FALSE);
 8275   ylo = o[i++] = bignum_extract_digits(&ka, 3, y, C_fix(0), n);
 8276
 8277   /* a = xhi * yhi, b = xlo * ylo, c = (xhi - xlo) * (yhi - ylo) */
 8278   a = o[i++] = C_s_a_u_i_integer_times(&ka, 2, xhi, yhi);
 8279   b = o[i++] = C_s_a_u_i_integer_times(&ka, 2, xlo, ylo);
 8280   xmid = o[i++] = C_s_a_u_i_integer_minus(&ka, 2, xhi, xlo);
 8281   ymid = o[i++] = C_s_a_u_i_integer_minus(&ka, 2, yhi, ylo);
 8282   c = o[i++] = C_s_a_u_i_integer_times(&ka, 2, xmid, ymid);
 8283
 8284   /* top(x) = a << (bits - 1)  and  bottom(y) = ((b + (a - c)) << bits) + b */
 8285   bits = C_unfix(n) * C_BIGNUM_DIGIT_LENGTH;
 8286   x = o[i++] = C_s_a_i_arithmetic_shift(&ka, 2, a, C_fix((C_uword)bits << 1));
 8287   c = o[i++] = C_s_a_u_i_integer_minus(&ka, 2, a, c);
 8288   c = o[i++] = C_s_a_u_i_integer_plus(&ka, 2, b, c);
 8289   c = o[i++] = C_s_a_i_arithmetic_shift(&ka, 2, c, C_fix(bits));
 8290   y = o[i++] = C_s_a_u_i_integer_plus(&ka, 2, c, b);
 8291   /* Finally, return top + bottom, and correct for negative */
 8292   n = o[i++] = C_s_a_u_i_integer_plus(&ka, 2, x, y);
 8293   if (C_truep(negp)) n = o[i++] = C_s_a_u_i_integer_negate(&ka, 1, n);
 8294
 8295   n = move_buffer_object(ptr, kab, n);
 8296   while(i--) clear_buffer_object(kab, o[i]);
 8297   return n;
 8298}
 8299
 8300void C_ccall C_times(C_word c, C_word *av)
 8301{
 8302  /* C_word closure = av[ 0 ]; */
 8303  C_word k = av[ 1 ];
 8304  C_word next_val,
 8305    result = C_fix(1),
 8306    prev_result = result;
 8307  C_word ab[2][C_SIZEOF_CPLXNUM + C_SIZEOF_RATNUM*2 + C_SIZEOF_BIGNUM(2) * 4], *a;
 8308
 8309  c -= 2;
 8310  av += 2;
 8311
 8312  while (c--) {
 8313    next_val = *(av++);
 8314    a = ab[c&1]; /* One may hold prev iteration result, the other is unused */
 8315    result = C_s_a_i_times(&a, 2, result, next_val);
 8316    result = move_buffer_object(&a, ab[(c+1)&1], result);
 8317    clear_buffer_object(ab[(c+1)&1], prev_result);
 8318    prev_result = result;
 8319  }
 8320
 8321  C_kontinue(k, result);
 8322}
 8323
 8324
 8325static C_word bignum_plus_unsigned(C_word **ptr, C_word x, C_word y, C_word negp)
 8326{
 8327  C_word size, result;
 8328  C_uword sum, digit, *scan_y, *end_y, *scan_r, *end_r;
 8329  int carry = 0;
 8330
 8331  if (C_bignum_size(y) > C_bignum_size(x)) {  /* Ensure size(y) <= size(x) */
 8332    C_word z = x;
 8333    x = y;
 8334    y = z;
 8335  }
 8336
 8337  size = C_fix(C_bignum_size(x) + 1); /* One more digit, for possible carry. */
 8338  result = C_allocate_scratch_bignum(ptr, size, negp, C_SCHEME_FALSE);
 8339
 8340  scan_y = C_bignum_digits(y);
 8341  end_y = scan_y + C_bignum_size(y);
 8342  scan_r = C_bignum_digits(result);
 8343  end_r = scan_r + C_bignum_size(result);
 8344
 8345  /* Copy x into r so we can operate on two pointers, which is faster
 8346   * than three, and we can stop earlier after adding y.  It's slower
 8347   * if x and y have equal length.  On average it's slightly faster.
 8348   */
 8349  bignum_digits_destructive_copy(result, x);
 8350  *(end_r-1) = 0; /* Ensure most significant digit is initialised */
 8351
 8352  /* Move over x and y simultaneously, destructively adding digits w/ carry. */
 8353  while (scan_y < end_y) {
 8354    digit = *scan_r;
 8355    if (carry) {
 8356      sum = digit + *scan_y++ + 1;
 8357      carry = sum <= digit;
 8358    } else {
 8359      sum = digit + *scan_y++;
 8360      carry = sum < digit;
 8361    }
 8362    (*scan_r++) = sum;
 8363  }
 8364
 8365  /* The end of y, the smaller number.  Propagate carry into the rest of x. */
 8366  while (carry) {
 8367    sum = (*scan_r) + 1;
 8368    carry = (sum == 0);
 8369    (*scan_r++) = sum;
 8370  }
 8371  assert(scan_r <= end_r);
 8372
 8373  return C_bignum_simplify(result);
 8374}
 8375
 8376static C_word rat_plusmin_integer(C_word **ptr, C_word rat, C_word i, integer_plusmin_op plusmin_op)
 8377{
 8378  C_word ab[C_SIZEOF_FIX_BIGNUM+C_SIZEOF_BIGNUM(2)], *a = ab,
 8379         num, denom, tmp, res;
 8380
 8381  if (i == C_fix(0)) return rat;
 8382
 8383  num = C_u_i_ratnum_num(rat);
 8384  denom = C_u_i_ratnum_denom(rat);
 8385
 8386  /* a/b [+-] c/d = (a*d [+-] b*c)/(b*d) | d = 1: (num + denom * i) / denom */
 8387  tmp = C_s_a_u_i_integer_times(&a, 2, denom, i);
 8388  res = plusmin_op(&a, 2, num, tmp);
 8389  res = move_buffer_object(ptr, ab, res);
 8390  clear_buffer_object(ab, tmp);
 8391  return C_ratnum(ptr, res, denom);
 8392}
 8393
 8394/* This is needed only for minus: plus is commutative but minus isn't. */
 8395static C_word integer_minus_rat(C_word **ptr, C_word i, C_word rat)
 8396{
 8397  C_word ab[C_SIZEOF_FIX_BIGNUM+C_SIZEOF_BIGNUM(2)], *a = ab,
 8398         num, denom, tmp, res;
 8399
 8400  num = C_u_i_ratnum_num(rat);
 8401  denom = C_u_i_ratnum_denom(rat);
 8402
 8403  if (i == C_fix(0))
 8404    return C_ratnum(ptr, C_s_a_u_i_integer_negate(ptr, 1, num), denom);
 8405
 8406  /* a/b - c/d = (a*d - b*c)/(b*d) | b = 1: (denom * i - num) / denom */
 8407  tmp = C_s_a_u_i_integer_times(&a, 2, denom, i);
 8408  res = C_s_a_u_i_integer_minus(&a, 2, tmp, num);
 8409  res = move_buffer_object(ptr, ab, res);
 8410  clear_buffer_object(ab, tmp);
 8411  return C_ratnum(ptr, res, denom);
 8412}
 8413
 8414/* This is pretty braindead and ugly */
 8415static C_word rat_plusmin_rat(C_word **ptr, C_word x, C_word y, integer_plusmin_op plusmin_op)
 8416{
 8417  C_word ab[C_SIZEOF_FIX_BIGNUM*6 + C_SIZEOF_BIGNUM(2)*2], *a = ab,
 8418         xnum = C_u_i_ratnum_num(x), ynum = C_u_i_ratnum_num(y),
 8419         xdenom = C_u_i_ratnum_denom(x), ydenom = C_u_i_ratnum_denom(y),
 8420         xnorm, ynorm, tmp_r, g1, ydenom_g1, xdenom_g1, norm_sum, g2, len,
 8421         res_num, res_denom;
 8422
 8423  /* Knuth, 4.5.1.  Start with g1 = gcd(xdenom, ydenom) */
 8424  g1 = C_s_a_u_i_integer_gcd(&a, 2, xdenom, ydenom);
 8425
 8426  /* xnorm = xnum * (ydenom/g1) */
 8427  ydenom_g1 = C_s_a_u_i_integer_quotient(&a, 2, ydenom, g1);
 8428  xnorm = C_s_a_u_i_integer_times(&a, 2, xnum, ydenom_g1);
 8429
 8430  /* ynorm = ynum * (xdenom/g1) */
 8431  xdenom_g1 = C_s_a_u_i_integer_quotient(&a, 2, xdenom, g1);
 8432  ynorm = C_s_a_u_i_integer_times(&a, 2, ynum, xdenom_g1);
 8433
 8434  /* norm_sum = xnorm [+-] ynorm */
 8435  norm_sum = plusmin_op(&a, 2, xnorm, ynorm);
 8436
 8437  /* g2 = gcd(norm_sum, g1) */
 8438  g2 = C_s_a_u_i_integer_gcd(&a, 2, norm_sum, g1);
 8439
 8440  /* res_num = norm_sum / g2 */
 8441  res_num = C_s_a_u_i_integer_quotient(ptr, 2, norm_sum, g2);
 8442  if (res_num == C_fix(0)) {
 8443    res_denom = C_fix(0); /* No need to calculate denom: we'll return 0 */
 8444  } else {
 8445    /* res_denom = xdenom_g1 * (ydenom / g2) */
 8446    C_word res_tmp_denom = C_s_a_u_i_integer_quotient(&a, 2, ydenom, g2);
 8447    res_denom = C_s_a_u_i_integer_times(ptr, 2, xdenom_g1, res_tmp_denom);
 8448
 8449    /* Ensure they're allocated in the correct place */
 8450    res_num = move_buffer_object(ptr, ab, res_num);
 8451    res_denom = move_buffer_object(ptr, ab, res_denom);
 8452    clear_buffer_object(ab, res_tmp_denom);
 8453  }
 8454
 8455  clear_buffer_object(ab, xdenom_g1);
 8456  clear_buffer_object(ab, ydenom_g1);
 8457  clear_buffer_object(ab, xnorm);
 8458  clear_buffer_object(ab, ynorm);
 8459  clear_buffer_object(ab, norm_sum);
 8460  clear_buffer_object(ab, g1);
 8461  clear_buffer_object(ab, g2);
 8462
 8463  switch (res_denom) {
 8464  case C_fix(0): return C_fix(0);
 8465  case C_fix(1): return res_num;
 8466  default: return C_ratnum(ptr, res_num, res_denom);
 8467  }
 8468}
 8469
 8470/* The maximum size this needs is that required to store a complex
 8471 * number result, where both real and imag parts consist of ratnums.
 8472 * The maximum size of those ratnums is if they consist of two "fix
 8473 * bignums", so we're looking at C_SIZEOF_CPLXNUM + C_SIZEOF_RATNUM *
 8474 * 2 + C_SIZEOF_FIX_BIGNUM * 4 = 29 words!
 8475 */
 8476C_regparm C_word
 8477C_s_a_i_plus(C_word **ptr, C_word n, C_word x, C_word y)
 8478{
 8479  if (x & C_FIXNUM_BIT) {
 8480    if (y & C_FIXNUM_BIT) {
 8481      return C_a_i_fixnum_plus(ptr, 2, x, y);
 8482    } else if (C_immediatep(y)) {
 8483      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", y);
 8484    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8485      return C_flonum(ptr, (double)C_unfix(x) + C_flonum_magnitude(y));
 8486    } else if (C_truep(C_bignump(y))) {
 8487      return C_s_a_u_i_integer_plus(ptr, 2, x, y);
 8488    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8489      return rat_plusmin_integer(ptr, y, x, C_s_a_u_i_integer_plus);
 8490    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8491      C_word real_sum = C_s_a_i_plus(ptr, 2, x, C_u_i_cplxnum_real(y)),
 8492             imag = C_u_i_cplxnum_imag(y);
 8493      if (C_truep(C_u_i_inexactp(real_sum)))
 8494        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8495      return C_cplxnum(ptr, real_sum, imag);
 8496    } else {
 8497      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", y);
 8498    }
 8499  } else if (C_immediatep(x)) {
 8500    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", x);
 8501  } else if (C_block_header(x) == C_FLONUM_TAG) {
 8502    if (y & C_FIXNUM_BIT) {
 8503      return C_flonum(ptr, C_flonum_magnitude(x) + (double)C_unfix(y));
 8504    } else if (C_immediatep(y)) {
 8505      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", y);
 8506    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8507      return C_a_i_flonum_plus(ptr, 2, x, y);
 8508    } else if (C_truep(C_bignump(y))) {
 8509      return C_flonum(ptr, C_flonum_magnitude(x)+C_bignum_to_double(y));
 8510    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8511      return C_s_a_i_plus(ptr, 2, x, C_a_i_exact_to_inexact(ptr, 1, y));
 8512    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8513      C_word real_sum = C_s_a_i_plus(ptr, 2, x, C_u_i_cplxnum_real(y)),
 8514             imag = C_u_i_cplxnum_imag(y);
 8515      if (C_truep(C_u_i_inexactp(real_sum)))
 8516        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8517      return C_cplxnum(ptr, real_sum, imag);
 8518    } else {
 8519      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", y);
 8520    }
 8521  } else if (C_truep(C_bignump(x))) {
 8522    if (y & C_FIXNUM_BIT) {
 8523      return C_s_a_u_i_integer_plus(ptr, 2, x, y);
 8524    } else if (C_immediatep(y)) {
 8525      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", y);
 8526    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8527      return C_flonum(ptr, C_bignum_to_double(x)+C_flonum_magnitude(y));
 8528    } else if (C_truep(C_bignump(y))) {
 8529      return C_s_a_u_i_integer_plus(ptr, 2, x, y);
 8530    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8531      return rat_plusmin_integer(ptr, y, x, C_s_a_u_i_integer_plus);
 8532    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8533      C_word real_sum = C_s_a_i_plus(ptr, 2, x, C_u_i_cplxnum_real(y)),
 8534             imag = C_u_i_cplxnum_imag(y);
 8535      if (C_truep(C_u_i_inexactp(real_sum)))
 8536        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8537      return C_cplxnum(ptr, real_sum, imag);
 8538    } else {
 8539      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", y);
 8540    }
 8541  } else if (C_block_header(x) == C_RATNUM_TAG) {
 8542    if (y & C_FIXNUM_BIT) {
 8543      return rat_plusmin_integer(ptr, x, y, C_s_a_u_i_integer_plus);
 8544    } else if (C_immediatep(y)) {
 8545      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", y);
 8546    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8547      return C_s_a_i_plus(ptr, 2, C_a_i_exact_to_inexact(ptr, 1, x), y);
 8548    } else if (C_truep(C_bignump(y))) {
 8549      return rat_plusmin_integer(ptr, x, y, C_s_a_u_i_integer_plus);
 8550    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8551      return rat_plusmin_rat(ptr, x, y, C_s_a_u_i_integer_plus);
 8552    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8553      C_word real_sum = C_s_a_i_plus(ptr, 2, x, C_u_i_cplxnum_real(y)),
 8554             imag = C_u_i_cplxnum_imag(y);
 8555      if (C_truep(C_u_i_inexactp(real_sum)))
 8556        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8557      return C_cplxnum(ptr, real_sum, imag);
 8558    } else {
 8559      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", y);
 8560    }
 8561  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 8562    if (!C_immediatep(y) && C_block_header(y) == C_CPLXNUM_TAG) {
 8563      C_word real_sum, imag_sum;
 8564      real_sum = C_s_a_i_plus(ptr, 2, C_u_i_cplxnum_real(x), C_u_i_cplxnum_real(y));
 8565      imag_sum = C_s_a_i_plus(ptr, 2, C_u_i_cplxnum_imag(x), C_u_i_cplxnum_imag(y));
 8566      if (C_truep(C_u_i_zerop2(imag_sum))) return real_sum;
 8567      else return C_cplxnum(ptr, real_sum, imag_sum);
 8568    } else {
 8569      C_word real_sum = C_s_a_i_plus(ptr, 2, C_u_i_cplxnum_real(x), y),
 8570             imag = C_u_i_cplxnum_imag(x);
 8571      if (C_truep(C_u_i_inexactp(real_sum)))
 8572        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8573      return C_cplxnum(ptr, real_sum, imag);
 8574    }
 8575  } else {
 8576    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "+", x);
 8577  }
 8578}
 8579
 8580C_regparm C_word
 8581C_s_a_u_i_integer_plus(C_word **ptr, C_word n, C_word x, C_word y)
 8582{
 8583  if ((x & y) & C_FIXNUM_BIT) {
 8584    return C_a_i_fixnum_plus(ptr, 2, x, y);
 8585  } else {
 8586    C_word ab[C_SIZEOF_FIX_BIGNUM * 2 + C_SIZEOF_BIGNUM_WRAPPER], *a = ab;
 8587    if (x & C_FIXNUM_BIT) x = C_a_u_i_fix_to_big(&a, x);
 8588    if (y & C_FIXNUM_BIT) y = C_a_u_i_fix_to_big(&a, y);
 8589
 8590    if (C_bignum_negativep(x)) {
 8591      if (C_bignum_negativep(y)) {
 8592        return bignum_plus_unsigned(ptr, x, y, C_SCHEME_TRUE);
 8593      } else {
 8594        return bignum_minus_unsigned(ptr, y, x);
 8595      }
 8596    } else {
 8597      if (C_bignum_negativep(y)) {
 8598        return bignum_minus_unsigned(ptr, x, y);
 8599      } else {
 8600        return bignum_plus_unsigned(ptr, x, y, C_SCHEME_FALSE);
 8601      }
 8602    }
 8603  }
 8604}
 8605
 8606void C_ccall C_plus(C_word c, C_word *av)
 8607{
 8608  /* C_word closure = av[ 0 ]; */
 8609  C_word k = av[ 1 ];
 8610  C_word next_val,
 8611    result = C_fix(0),
 8612    prev_result = result;
 8613  C_word ab[2][C_SIZEOF_CPLXNUM + C_SIZEOF_RATNUM*2 + C_SIZEOF_FIX_BIGNUM * 4], *a;
 8614
 8615  c -= 2;
 8616  av += 2;
 8617
 8618  while (c--) {
 8619    next_val = *(av++);
 8620    a = ab[c&1]; /* One may hold last iteration result, the other is unused */
 8621    result = C_s_a_i_plus(&a, 2, result, next_val);
 8622    result = move_buffer_object(&a, ab[(c+1)&1], result);
 8623    clear_buffer_object(ab[(c+1)&1], prev_result);
 8624    prev_result = result;
 8625  }
 8626
 8627  C_kontinue(k, result);
 8628}
 8629
 8630static C_word bignum_minus_unsigned(C_word **ptr, C_word x, C_word y)
 8631{
 8632  C_word res, size;
 8633  C_uword *scan_r, *end_r, *scan_y, *end_y, difference, digit;
 8634  int borrow = 0;
 8635
 8636  switch(bignum_cmp_unsigned(x, y)) {
 8637  case 0:	      /* x = y, return 0 */
 8638    return C_fix(0);
 8639  case -1:	      /* abs(x) < abs(y), return -(abs(y) - abs(x)) */
 8640    size = C_fix(C_bignum_size(y)); /* Maximum size of result is length of y. */
 8641    res = C_allocate_scratch_bignum(ptr, size, C_SCHEME_TRUE, C_SCHEME_FALSE);
 8642    size = y;
 8643    y = x;
 8644    x = size;
 8645    break;
 8646  case 1:	      /* abs(x) > abs(y), return abs(x) - abs(y) */
 8647  default:
 8648    size = C_fix(C_bignum_size(x)); /* Maximum size of result is length of x. */
 8649    res = C_allocate_scratch_bignum(ptr, size, C_SCHEME_FALSE, C_SCHEME_FALSE);
 8650    break;
 8651  }
 8652
 8653  scan_r = C_bignum_digits(res);
 8654  end_r = scan_r + C_bignum_size(res);
 8655  scan_y = C_bignum_digits(y);
 8656  end_y = scan_y + C_bignum_size(y);
 8657
 8658  bignum_digits_destructive_copy(res, x); /* See bignum_plus_unsigned */
 8659
 8660  /* Destructively subtract y's digits w/ borrow from and back into r. */
 8661  while (scan_y < end_y) {
 8662    digit = *scan_r;
 8663    if (borrow) {
 8664      difference = digit - *scan_y++ - 1;
 8665      borrow = difference >= digit;
 8666    } else {
 8667      difference = digit - *scan_y++;
 8668      borrow = difference > digit;
 8669    }
 8670    (*scan_r++) = difference;
 8671  }
 8672
 8673  /* The end of y, the smaller number.  Propagate borrow into the rest of x. */
 8674  while (borrow) {
 8675    digit = *scan_r;
 8676    difference = digit - borrow;
 8677    borrow = difference >= digit;
 8678    (*scan_r++) = difference;
 8679  }
 8680
 8681  assert(scan_r <= end_r);
 8682
 8683  return C_bignum_simplify(res);
 8684}
 8685
 8686/* Like C_s_a_i_plus, this needs at most 29 words */
 8687C_regparm C_word
 8688C_s_a_i_minus(C_word **ptr, C_word n, C_word x, C_word y)
 8689{
 8690  if (x & C_FIXNUM_BIT) {
 8691    if (y & C_FIXNUM_BIT) {
 8692      return C_a_i_fixnum_difference(ptr, 2, x, y);
 8693    } else if (C_immediatep(y)) {
 8694      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", y);
 8695    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8696      return C_flonum(ptr, (double)C_unfix(x) - C_flonum_magnitude(y));
 8697    } else if (C_truep(C_bignump(y))) {
 8698      return C_s_a_u_i_integer_minus(ptr, 2, x, y);
 8699    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8700      return integer_minus_rat(ptr, x, y);
 8701    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8702      C_word real_diff = C_s_a_i_minus(ptr, 2, x, C_u_i_cplxnum_real(y)),
 8703             imag = C_s_a_i_negate(ptr, 1, C_u_i_cplxnum_imag(y));
 8704      if (C_truep(C_u_i_inexactp(real_diff)))
 8705        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8706      return C_cplxnum(ptr, real_diff, imag);
 8707    } else {
 8708      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", y);
 8709    }
 8710  } else if (C_immediatep(x)) {
 8711    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", x);
 8712  } else if (C_block_header(x) == C_FLONUM_TAG) {
 8713    if (y & C_FIXNUM_BIT) {
 8714      return C_flonum(ptr, C_flonum_magnitude(x) - (double)C_unfix(y));
 8715    } else if (C_immediatep(y)) {
 8716      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", y);
 8717    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8718      return C_a_i_flonum_difference(ptr, 2, x, y);
 8719    } else if (C_truep(C_bignump(y))) {
 8720      return C_flonum(ptr, C_flonum_magnitude(x)-C_bignum_to_double(y));
 8721    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8722      return C_s_a_i_minus(ptr, 2, x, C_a_i_exact_to_inexact(ptr, 1, y));
 8723    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8724      C_word real_diff = C_s_a_i_minus(ptr, 2, x, C_u_i_cplxnum_real(y)),
 8725             imag = C_s_a_i_negate(ptr, 1, C_u_i_cplxnum_imag(y));
 8726      if (C_truep(C_u_i_inexactp(real_diff)))
 8727        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8728      return C_cplxnum(ptr, real_diff, imag);
 8729    } else {
 8730      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", y);
 8731    }
 8732  } else if (C_truep(C_bignump(x))) {
 8733    if (y & C_FIXNUM_BIT) {
 8734      return C_s_a_u_i_integer_minus(ptr, 2, x, y);
 8735    } else if (C_immediatep(y)) {
 8736      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", y);
 8737    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8738      return C_flonum(ptr, C_bignum_to_double(x)-C_flonum_magnitude(y));
 8739    } else if (C_truep(C_bignump(y))) {
 8740      return C_s_a_u_i_integer_minus(ptr, 2, x, y);
 8741    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8742      return integer_minus_rat(ptr, x, y);
 8743    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8744      C_word real_diff = C_s_a_i_minus(ptr, 2, x, C_u_i_cplxnum_real(y)),
 8745             imag = C_s_a_i_negate(ptr, 1, C_u_i_cplxnum_imag(y));
 8746      if (C_truep(C_u_i_inexactp(real_diff)))
 8747        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8748      return C_cplxnum(ptr, real_diff, imag);
 8749    } else {
 8750      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", y);
 8751    }
 8752  } else if (C_block_header(x) == C_RATNUM_TAG) {
 8753    if (y & C_FIXNUM_BIT) {
 8754      return rat_plusmin_integer(ptr, x, y, C_s_a_u_i_integer_minus);
 8755    } else if (C_immediatep(y)) {
 8756      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", y);
 8757    } else if (C_block_header(y) == C_FLONUM_TAG) {
 8758      return C_s_a_i_minus(ptr, 2, C_a_i_exact_to_inexact(ptr, 1, x), y);
 8759    } else if (C_truep(C_bignump(y))) {
 8760      return rat_plusmin_integer(ptr, x, y, C_s_a_u_i_integer_minus);
 8761    } else if (C_block_header(y) == C_RATNUM_TAG) {
 8762      return rat_plusmin_rat(ptr, x, y, C_s_a_u_i_integer_minus);
 8763    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 8764      C_word real_diff = C_s_a_i_minus(ptr, 2, x, C_u_i_cplxnum_real(y)),
 8765             imag = C_s_a_i_negate(ptr, 1, C_u_i_cplxnum_imag(y));
 8766      if (C_truep(C_u_i_inexactp(real_diff)))
 8767        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8768      return C_cplxnum(ptr, real_diff, imag);
 8769    } else {
 8770      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", y);
 8771    }
 8772  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 8773    if (!C_immediatep(y) && C_block_header(y) == C_CPLXNUM_TAG) {
 8774      C_word real_diff, imag_diff;
 8775      real_diff = C_s_a_i_minus(ptr,2,C_u_i_cplxnum_real(x),C_u_i_cplxnum_real(y));
 8776      imag_diff = C_s_a_i_minus(ptr,2,C_u_i_cplxnum_imag(x),C_u_i_cplxnum_imag(y));
 8777      if (C_truep(C_u_i_zerop2(imag_diff))) return real_diff;
 8778      else return C_cplxnum(ptr, real_diff, imag_diff);
 8779    } else {
 8780      C_word real_diff = C_s_a_i_minus(ptr, 2, C_u_i_cplxnum_real(x), y),
 8781             imag = C_u_i_cplxnum_imag(x);
 8782      if (C_truep(C_u_i_inexactp(real_diff)))
 8783        imag = C_a_i_exact_to_inexact(ptr, 1, imag);
 8784      return C_cplxnum(ptr, real_diff, imag);
 8785    }
 8786  } else {
 8787    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "-", x);
 8788  }
 8789}
 8790
 8791C_regparm C_word
 8792C_s_a_u_i_integer_minus(C_word **ptr, C_word n, C_word x, C_word y)
 8793{
 8794  if ((x & y) & C_FIXNUM_BIT) {
 8795    return C_a_i_fixnum_difference(ptr, 2, x, y);
 8796  } else {
 8797    C_word ab[C_SIZEOF_FIX_BIGNUM * 2 + C_SIZEOF_BIGNUM_WRAPPER], *a = ab;
 8798    if (x & C_FIXNUM_BIT) x = C_a_u_i_fix_to_big(&a, x);
 8799    if (y & C_FIXNUM_BIT) y = C_a_u_i_fix_to_big(&a, y);
 8800
 8801    if (C_bignum_negativep(x)) {
 8802      if (C_bignum_negativep(y)) {
 8803        return bignum_minus_unsigned(ptr, y, x);
 8804      } else {
 8805        return bignum_plus_unsigned(ptr, x, y, C_SCHEME_TRUE);
 8806      }
 8807    } else {
 8808      if (C_bignum_negativep(y)) {
 8809        return bignum_plus_unsigned(ptr, x, y, C_SCHEME_FALSE);
 8810      } else {
 8811        return bignum_minus_unsigned(ptr, x, y);
 8812      }
 8813    }
 8814  }
 8815}
 8816
 8817void C_ccall C_minus(C_word c, C_word *av)
 8818{
 8819  /* C_word closure = av[ 0 ]; */
 8820  C_word k = av[ 1 ];
 8821  C_word next_val, result, prev_result;
 8822  C_word ab[2][C_SIZEOF_CPLXNUM + C_SIZEOF_RATNUM*2 + C_SIZEOF_FIX_BIGNUM * 4], *a;
 8823
 8824  if (c < 3) {
 8825    C_bad_min_argc(c, 3);
 8826  } else if (c == 3) {
 8827    a = ab[0];
 8828    C_kontinue(k, C_s_a_i_negate(&a, 1, av[ 2 ]));
 8829  } else {
 8830    prev_result = result = av[ 2 ];
 8831    c -= 3;
 8832    av += 3;
 8833
 8834    while (c--) {
 8835      next_val = *(av++);
 8836      a = ab[c&1]; /* One may hold last iteration result, the other is unused */
 8837      result = C_s_a_i_minus(&a, 2, result, next_val);
 8838      result = move_buffer_object(&a, ab[(c+1)&1], result);
 8839      clear_buffer_object(ab[(c+1)&1], prev_result);
 8840      prev_result = result;
 8841    }
 8842
 8843    C_kontinue(k, result);
 8844  }
 8845}
 8846
 8847
 8848static C_regparm void
 8849integer_divrem(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r)
 8850{
 8851  if (!(y & C_FIXNUM_BIT)) { /* y is bignum. */
 8852    if (x & C_FIXNUM_BIT) {
 8853      /* abs(x) < abs(y), so it will always be [0, x] except for this case: */
 8854      if (x == C_fix(C_MOST_NEGATIVE_FIXNUM) &&
 8855          C_bignum_negated_fitsinfixnump(y)) {
 8856        if (q != NULL) *q = C_fix(-1);
 8857        if (r != NULL) *r = C_fix(0);
 8858      } else {
 8859        if (q != NULL) *q = C_fix(0);
 8860        if (r != NULL) *r = x;
 8861      }
 8862    } else {
 8863      bignum_divrem(ptr, x, y, q, r);
 8864    }
 8865  } else if (x & C_FIXNUM_BIT) { /* both x and y are fixnum. */
 8866    if (q != NULL) *q = C_a_i_fixnum_quotient_checked(ptr, 2, x, y);
 8867    if (r != NULL) *r = C_i_fixnum_remainder_checked(x, y);
 8868  } else { /* x is bignum, y is fixnum. */
 8869    C_word absy = (y & C_INT_SIGN_BIT) ? -C_unfix(y) : C_unfix(y);
 8870
 8871    if (y == C_fix(1)) {
 8872      if (q != NULL) *q = x;
 8873      if (r != NULL) *r = C_fix(0);
 8874    } else if (y == C_fix(-1)) {
 8875      if (q != NULL) *q = C_s_a_u_i_integer_negate(ptr, 1, x);
 8876      if (r != NULL) *r = C_fix(0);
 8877    } else if (C_fitsinbignumhalfdigitp(absy) ||
 8878               ((((C_uword)1 << (C_ilen(absy)-1)) == absy) &&
 8879                C_fitsinfixnump(absy))) {
 8880      assert(y != C_fix(0)); /* _must_ be checked by caller */
 8881      if (q != NULL) {
 8882        bignum_destructive_divide_unsigned_small(ptr, x, y, q, r);
 8883      } else { /* We assume r isn't NULL here (that makes no sense) */
 8884        C_word rem;
 8885	C_uword next_power = (C_uword)1 << (C_ilen(absy)-1);
 8886
 8887	if (next_power == absy) { /* Is absy a power of two? */
 8888          rem = *(C_bignum_digits(x)) & (next_power - 1);
 8889        } else { /* Too bad, we have to do some real work */
 8890          rem = bignum_remainder_unsigned_halfdigit(x, absy);
 8891	}
 8892        *r = C_bignum_negativep(x) ? C_fix(-rem) : C_fix(rem);
 8893      }
 8894    } else {			/* Just divide it as two bignums */
 8895      C_word ab[C_SIZEOF_FIX_BIGNUM], *a = ab;
 8896      bignum_divrem(ptr, x, C_a_u_i_fix_to_big(&a, y), q, r);
 8897      if (q != NULL) *q = move_buffer_object(ptr, ab, *q);
 8898      if (r != NULL) *r = move_buffer_object(ptr, ab, *r);
 8899    }
 8900  }
 8901}
 8902
 8903/* This _always_ needs two bignum wrappers in ptr! */
 8904static C_regparm void
 8905bignum_divrem(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r)
 8906{
 8907  C_word q_negp = C_mk_bool(C_bignum_negativep(y) != C_bignum_negativep(x)),
 8908         r_negp = C_mk_bool(C_bignum_negativep(x)), res, size;
 8909
 8910  switch(bignum_cmp_unsigned(x, y)) {
 8911  case 0:
 8912    if (q != NULL) *q = C_truep(q_negp) ? C_fix(-1) : C_fix(1);
 8913    if (r != NULL) *r = C_fix(0);
 8914    break;
 8915  case -1:
 8916    if (q != NULL) *q = C_fix(0);
 8917    if (r != NULL) *r = x;
 8918    break;
 8919  case 1:
 8920  default:
 8921    res = C_SCHEME_FALSE;
 8922    size = C_bignum_size(x) - C_bignum_size(y);
 8923    if (C_bignum_size(y) > C_BURNIKEL_ZIEGLER_THRESHOLD &&
 8924        size > C_BURNIKEL_ZIEGLER_THRESHOLD) {
 8925      res = bignum_divide_burnikel_ziegler(ptr, x, y, q, r);
 8926    }
 8927
 8928    if (!C_truep(res)) {
 8929      bignum_divide_unsigned(ptr, x, y, q, q_negp, r, r_negp);
 8930      if (q != NULL) *q = C_bignum_simplify(*q);
 8931      if (r != NULL) *r = C_bignum_simplify(*r);
 8932    }
 8933    break;
 8934  }
 8935}
 8936
 8937/* Burnikel-Ziegler recursive division: Split high number (x) in three
 8938 * or four parts and divide by the lowest number (y), split in two
 8939 * parts.  There are descriptions in [MpNT, 4.2], [MCA, 1.4.3] and the
 8940 * paper "Fast Recursive Division" by Christoph Burnikel & Joachim
 8941 * Ziegler is freely available.  There is also a description in Karl
 8942 * Hasselstrom's thesis "Fast Division of Integers".
 8943 *
 8944 * The complexity of this is supposedly O(r*s^{log(3)-1} + r*log(s)),
 8945 * where s is the length of x, and r is the length of y (in digits).
 8946 *
 8947 * TODO: See if it's worthwhile to implement "division without remainder"
 8948 * from the Burnikel-Ziegler paper.
 8949 */
 8950static C_regparm C_word
 8951bignum_divide_burnikel_ziegler(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r)
 8952{
 8953  C_word ab[C_SIZEOF_FIX_BIGNUM*9], *a = ab,
 8954         lab[2][C_SIZEOF_FIX_BIGNUM*10], *la,
 8955         q_negp = (C_bignum_negativep(y) ? C_mk_nbool(C_bignum_negativep(x)) :
 8956                   C_mk_bool(C_bignum_negativep(x))),
 8957         r_negp = C_mk_bool(C_bignum_negativep(x)), s, m, n, i, j, l, shift,
 8958         yhi, ylo, zi, zi_orig, newx, newy, quot, qi, ri;
 8959
 8960  /* Ran out of stack?  Fall back to non-recursive division */
 8961  C_stack_check1(return C_SCHEME_FALSE);
 8962
 8963  x = C_s_a_u_i_integer_abs(&a, 1, x);
 8964  y = C_s_a_u_i_integer_abs(&a, 1, y);
 8965
 8966  /* Define m as min{2^k|(2^k)*BURNIKEL_ZIEGLER_DIFF_THRESHOLD > s}
 8967   * This ensures we shift as little as possible (less pressure
 8968   * on the GC) while maintaining a power of two until we drop
 8969   * below the threshold, so we can always split N in half.
 8970   */
 8971  s = C_bignum_size(y);
 8972  m = 1 << C_ilen(s / C_BURNIKEL_ZIEGLER_THRESHOLD);
 8973  j = (s+m-1) / m;              /* j = s/m, rounded up */
 8974  n = j * m;
 8975
 8976  shift = (C_BIGNUM_DIGIT_LENGTH * n) - integer_length_abs(y);
 8977  newx = C_s_a_i_arithmetic_shift(&a, 2, x, C_fix(shift));
 8978  newy = C_s_a_i_arithmetic_shift(&a, 2, y, C_fix(shift));
 8979  if (shift != 0) {
 8980    clear_buffer_object(ab, x);
 8981    clear_buffer_object(ab, y);
 8982  }
 8983  x = newx;
 8984  y = newy;
 8985
 8986  /* l needs to be the smallest value so that a < base^{l*n}/2 */
 8987  l = (C_bignum_size(x) + n) / n;
 8988  if ((C_BIGNUM_DIGIT_LENGTH * l) == integer_length_abs(x)) l++;
 8989  l = nmax(l, 2);
 8990
 8991  yhi = bignum_extract_digits(&a, 3, y, C_fix(n >> 1), C_SCHEME_FALSE);
 8992  ylo = bignum_extract_digits(&a, 3, y, C_fix(0), C_fix(n >> 1));
 8993
 8994  s = (l - 2) * n * C_BIGNUM_DIGIT_LENGTH;
 8995  zi_orig = zi = C_s_a_i_arithmetic_shift(&a, 2, x, C_fix(-s));
 8996  quot = C_fix(0);
 8997
 8998  for(i = l - 2; i >= 0; --i) {
 8999    la = lab[i&1];
 9000
 9001    burnikel_ziegler_2n_div_1n(&la, zi, y, yhi, ylo, C_fix(n), &qi, &ri);
 9002
 9003    newx = C_s_a_i_arithmetic_shift(&la, 2, quot, C_fix(n*C_BIGNUM_DIGIT_LENGTH));
 9004    clear_buffer_object(lab, quot);
 9005    quot = C_s_a_u_i_integer_plus(&la, 2, newx, qi);
 9006    move_buffer_object(&la, lab[(i+1)&1], quot);
 9007    clear_buffer_object(lab, newx);
 9008    clear_buffer_object(lab, qi);
 9009
 9010    if (i > 0) {  /* Set z_{i-1} = [r{i}, x{i-1}] */
 9011      newx = bignum_extract_digits(&la, 3, x, C_fix(n * (i-1)), C_fix(n * i));
 9012      newy = C_s_a_i_arithmetic_shift(&la, 2, ri, C_fix(n*C_BIGNUM_DIGIT_LENGTH));
 9013      clear_buffer_object(lab, zi);
 9014      zi = C_s_a_u_i_integer_plus(&la, 2, newx, newy);
 9015      move_buffer_object(&la, lab[(i+1)&1], zi);
 9016      move_buffer_object(&la, lab[(i+1)&1], quot);
 9017      clear_buffer_object(lab, newx);
 9018      clear_buffer_object(lab, newy);
 9019      clear_buffer_object(lab, ri);
 9020    }
 9021  }
 9022  clear_buffer_object(ab, x);
 9023  clear_buffer_object(ab, y);
 9024  clear_buffer_object(ab, yhi);
 9025  clear_buffer_object(ab, ylo);
 9026  clear_buffer_object(ab, zi_orig);
 9027  clear_buffer_object(lab, zi);
 9028
 9029  if (q != NULL) {
 9030    if (C_truep(q_negp)) {
 9031      newx = C_s_a_u_i_integer_negate(&la, 1, quot);
 9032      clear_buffer_object(lab, quot);
 9033      quot = newx;
 9034    }
 9035    *q = move_buffer_object(ptr, lab, quot);
 9036  }
 9037  clear_buffer_object(lab, quot);
 9038
 9039  if (r != NULL) {
 9040    newx = C_s_a_i_arithmetic_shift(&la, 2, ri, C_fix(-shift));
 9041    if (C_truep(r_negp)) {
 9042      newy = C_s_a_u_i_integer_negate(ptr, 1, newx);
 9043      clear_buffer_object(lab, newx);
 9044      newx = newy;
 9045    }
 9046    *r = move_buffer_object(ptr, lab, newx);
 9047  }
 9048  clear_buffer_object(lab, ri);
 9049
 9050  return C_SCHEME_TRUE;
 9051}
 9052
 9053static C_regparm void
 9054burnikel_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)
 9055{
 9056  C_word kab[C_SIZEOF_FIX_BIGNUM*6 + C_SIZEOF_BIGNUM(2)], *ka = kab,
 9057         lab[2][C_SIZEOF_FIX_BIGNUM*4], *la,
 9058         size, tmp, less, qhat, rhat, r1, r1a3, i = 0;
 9059
 9060  size = C_unfix(n) * C_BIGNUM_DIGIT_LENGTH;
 9061  tmp = C_s_a_i_arithmetic_shift(&ka, 2, a12, C_fix(-size));
 9062  less = C_i_integer_lessp(tmp, b1); /* a1 < b1 ? */
 9063  clear_buffer_object(kab, tmp);
 9064
 9065  if (C_truep(less)) {
 9066    C_word atmpb[C_SIZEOF_FIX_BIGNUM*2], *atmp = atmpb, b11, b12, halfn;
 9067
 9068    halfn = C_fix(C_unfix(n) >> 1);
 9069    b11 = bignum_extract_digits(&atmp, 3, b1, halfn, C_SCHEME_FALSE);
 9070    b12 = bignum_extract_digits(&atmp, 3, b1, C_fix(0), halfn);
 9071
 9072    burnikel_ziegler_2n_div_1n(&ka, a12, b1, b11, b12, n, &qhat, &r1);
 9073    qhat = move_buffer_object(&ka, atmpb, qhat);
 9074    r1 = move_buffer_object(&ka, atmpb, r1);
 9075
 9076    clear_buffer_object(atmpb, b11);
 9077    clear_buffer_object(atmpb, b12);
 9078  } else {
 9079    C_word atmpb[C_SIZEOF_FIX_BIGNUM*5], *atmp = atmpb, tmp2;
 9080
 9081    tmp = C_s_a_i_arithmetic_shift(&atmp, 2, C_fix(1), C_fix(size));
 9082    qhat = C_s_a_u_i_integer_minus(&ka, 2, tmp, C_fix(1));  /* B^n - 1 */
 9083    qhat = move_buffer_object(&ka, atmpb, qhat);
 9084    clear_buffer_object(atmpb, tmp);
 9085
 9086    /* r1 = (a12 - b1*B^n) + b1 */
 9087    tmp = C_s_a_i_arithmetic_shift(&atmp, 2, b1, C_fix(size));
 9088    tmp2 = C_s_a_u_i_integer_minus(&atmp, 2, a12, tmp);
 9089    r1 = C_s_a_u_i_integer_plus(&ka, 2, tmp2, b1);
 9090    r1 = move_buffer_object(&ka, atmpb, r1);
 9091    clear_buffer_object(atmpb, tmp);
 9092    clear_buffer_object(atmpb, tmp2);
 9093  }
 9094
 9095  tmp = C_s_a_i_arithmetic_shift(&ka, 2, r1, C_fix(size));
 9096  clear_buffer_object(kab, r1);
 9097  r1a3 = C_s_a_u_i_integer_plus(&ka, 2, tmp, a3);
 9098  b2 = C_s_a_u_i_integer_times(&ka, 2, qhat, b2);
 9099
 9100  la = lab[0];
 9101  rhat = C_s_a_u_i_integer_minus(&la, 2, r1a3, b2);
 9102  rhat = move_buffer_object(&la, kab, rhat);
 9103  qhat = move_buffer_object(&la, kab, qhat);
 9104
 9105  clear_buffer_object(kab, tmp);
 9106  clear_buffer_object(kab, r1a3);
 9107  clear_buffer_object(kab, b2);
 9108
 9109  while(C_truep(C_i_negativep(rhat))) {
 9110    la = lab[(++i)&1];
 9111    /* rhat += b */
 9112    r1 = C_s_a_u_i_integer_plus(&la, 2, rhat, b);
 9113    tmp = move_buffer_object(&la, lab[(i-1)&1], r1);
 9114    clear_buffer_object(lab[(i-1)&1], r1);
 9115    clear_buffer_object(lab[(i-1)&1], rhat);
 9116    clear_buffer_object(kab, rhat);
 9117    rhat = tmp;
 9118
 9119    /* qhat -= 1 */
 9120    r1 = C_s_a_u_i_integer_minus(&la, 2, qhat, C_fix(1));
 9121    tmp = move_buffer_object(&la, lab[(i-1)&1], r1);
 9122    clear_buffer_object(lab[(i-1)&1], r1);
 9123    clear_buffer_object(lab[(i-1)&1], qhat);
 9124    clear_buffer_object(kab, qhat);
 9125    qhat = tmp;
 9126  }
 9127
 9128  if (q != NULL) *q = move_buffer_object(ptr, lab, qhat);
 9129  if (r != NULL) *r = move_buffer_object(ptr, lab, rhat);
 9130  clear_buffer_object(lab, qhat);
 9131  clear_buffer_object(lab, rhat);
 9132}
 9133
 9134static C_regparm void
 9135burnikel_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)
 9136{
 9137  C_word kab[2][C_SIZEOF_FIX_BIGNUM*7], *ka, a12, a3, a4,
 9138         q1 = C_fix(0), r1, q2 = C_fix(0), r2, *qp;
 9139  int stack_full = 0;
 9140
 9141  C_stack_check1(stack_full = 1);
 9142
 9143  n = C_unfix(n);
 9144  if (stack_full || (n & 1) || (n < C_BURNIKEL_ZIEGLER_THRESHOLD)) {
 9145    integer_divrem(ptr, a, b, q, r);
 9146  } else {
 9147    ka = kab[0];
 9148    a12 = bignum_extract_digits(&ka, 3, a, C_fix(n), C_SCHEME_FALSE);
 9149    a3 = bignum_extract_digits(&ka, 3, a, C_fix(n >> 1), C_fix(n));
 9150
 9151    qp = (q == NULL) ? NULL : &q1;
 9152    ka = kab[1];
 9153    burnikel_ziegler_3n_div_2n(&ka, a12, a3, b, b1, b2, C_fix(n >> 1), qp, &r1);
 9154    q1 = move_buffer_object(&ka, kab[0], q1);
 9155    r1 = move_buffer_object(&ka, kab[0], r1);
 9156    clear_buffer_object(kab[0], a12);
 9157    clear_buffer_object(kab[0], a3);
 9158
 9159    a4 = bignum_extract_digits(&ka, 3, a, C_fix(0), C_fix(n >> 1));
 9160
 9161    qp = (q == NULL) ? NULL : &q2;
 9162    ka = kab[0];
 9163    burnikel_ziegler_3n_div_2n(&ka, r1, a4, b, b1, b2, C_fix(n >> 1), qp, r);
 9164    if (r != NULL) *r = move_buffer_object(ptr, kab[0], *r);
 9165    clear_buffer_object(kab[1], r1);
 9166
 9167    if (q != NULL) {
 9168      C_word halfn_bits = (n >> 1) * C_BIGNUM_DIGIT_LENGTH;
 9169      r1 = C_s_a_i_arithmetic_shift(&ka, 2, q1, C_fix(halfn_bits));
 9170      *q = C_s_a_i_plus(ptr, 2, r1, q2); /* q = [q1, q2] */
 9171      *q = move_buffer_object(ptr, kab[0], *q);
 9172      clear_buffer_object(kab[0], r1);
 9173      clear_buffer_object(kab[1], q1);
 9174      clear_buffer_object(kab[0], q2);
 9175    }
 9176    clear_buffer_object(kab[1], a4);
 9177  }
 9178}
 9179
 9180
 9181static C_regparm C_word bignum_remainder_unsigned_halfdigit(C_word x, C_word y)
 9182{
 9183  C_uword *start = C_bignum_digits(x),
 9184          *scan = start + C_bignum_size(x),
 9185          rem = 0, two_digits;
 9186
 9187  assert((y > 1) && (C_fitsinbignumhalfdigitp(y)));
 9188  while (start < scan) {
 9189    two_digits = (*--scan);
 9190    rem = C_BIGNUM_DIGIT_COMBINE(rem, C_BIGNUM_DIGIT_HI_HALF(two_digits)) % y;
 9191    rem = C_BIGNUM_DIGIT_COMBINE(rem, C_BIGNUM_DIGIT_LO_HALF(two_digits)) % y;
 9192  }
 9193  return rem;
 9194}
 9195
 9196/* There doesn't seem to be a way to return two values from inline functions */
 9197void C_ccall C_quotient_and_remainder(C_word c, C_word *av)
 9198{
 9199  C_word ab[C_SIZEOF_FIX_BIGNUM*4+C_SIZEOF_FLONUM*2], *a = ab,
 9200    nx = C_SCHEME_FALSE, ny = C_SCHEME_FALSE,
 9201    q, r, k, x, y;
 9202
 9203  if (c != 4) C_bad_argc_2(c, 4, av[ 0 ]);
 9204
 9205  k = av[ 1 ];
 9206  x = av[ 2 ];
 9207  y = av[ 3 ];
 9208
 9209  if (!C_truep(C_i_integerp(x)))
 9210    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "quotient&remainder", x);
 9211  if (!C_truep(C_i_integerp(y)))
 9212    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "quotient&remainder", y);
 9213  if (C_truep(C_i_zerop(y))) C_div_by_zero_error("quotient&remainder");
 9214
 9215  if (C_truep(C_i_flonump(x))) {
 9216    if C_truep(C_i_flonump(y)) {
 9217      double dx = C_flonum_magnitude(x), dy = C_flonum_magnitude(y), tmp;
 9218
 9219      C_modf(dx / dy, &tmp);
 9220      q = C_flonum(&a, tmp);
 9221      r = C_flonum(&a, dx - tmp * dy);
 9222      /* reuse av */
 9223      av[ 0 ] = C_SCHEME_UNDEFINED;
 9224      /* av[ 1 ] = k; */ /* stays the same */
 9225      av[ 2 ] = q;
 9226      av[ 3 ] = r;
 9227      C_values(4, av);
 9228    }
 9229    x = nx = C_s_a_u_i_flo_to_int(&a, 1, x);
 9230  }
 9231  if (C_truep(C_i_flonump(y))) {
 9232    y = ny = C_s_a_u_i_flo_to_int(&a, 1, y);
 9233  }
 9234
 9235  integer_divrem(&a, x, y, &q, &r);
 9236
 9237  if (C_truep(nx) || C_truep(ny)) {
 9238    C_word newq, newr;
 9239    newq = C_a_i_exact_to_inexact(&a, 1, q);
 9240    newr = C_a_i_exact_to_inexact(&a, 1, r);
 9241    clear_buffer_object(ab, q);
 9242    clear_buffer_object(ab, r);
 9243    q = newq;
 9244    r = newr;
 9245
 9246    clear_buffer_object(ab, nx);
 9247    clear_buffer_object(ab, ny);
 9248  }
 9249  /* reuse av */
 9250  av[ 0 ] = C_SCHEME_UNDEFINED;
 9251  /* av[ 1 ] = k; */ /* stays the same */
 9252  av[ 2 ] = q;
 9253  av[ 3 ] = r;
 9254  C_values(4, av);
 9255}
 9256
 9257void C_ccall C_u_integer_quotient_and_remainder(C_word c, C_word *av)
 9258{
 9259  C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, q, r;
 9260
 9261  if (av[ 3 ] == C_fix(0)) C_div_by_zero_error("quotient&remainder");
 9262
 9263  integer_divrem(&a, av[ 2 ], av[ 3 ], &q, &r);
 9264
 9265  /* reuse av */
 9266  av[ 0 ] = C_SCHEME_UNDEFINED;
 9267  /* av[ 1 ] = k; */ /* stays the same */
 9268  av[ 2 ] = q;
 9269  av[ 3 ] = r;
 9270  C_values(4, av);
 9271}
 9272
 9273C_regparm C_word
 9274C_s_a_i_remainder(C_word **ptr, C_word n, C_word x, C_word y)
 9275{
 9276  C_word ab[C_SIZEOF_FIX_BIGNUM*4+C_SIZEOF_FLONUM*2], *a = ab, r,
 9277         nx = C_SCHEME_FALSE, ny = C_SCHEME_FALSE;
 9278
 9279  if (!C_truep(C_i_integerp(x)))
 9280    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "remainder", x);
 9281  if (!C_truep(C_i_integerp(y)))
 9282    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "remainder", y);
 9283  if (C_truep(C_i_zerop(y))) C_div_by_zero_error("remainder");
 9284
 9285  if (C_truep(C_i_flonump(x))) {
 9286    if C_truep(C_i_flonump(y)) {
 9287      double dx = C_flonum_magnitude(x), dy = C_flonum_magnitude(y), tmp;
 9288
 9289      C_modf(dx / dy, &tmp);
 9290      return C_flonum(ptr, dx - tmp * dy);
 9291    }
 9292    x = nx = C_s_a_u_i_flo_to_int(&a, 1, x);
 9293  }
 9294  if (C_truep(C_i_flonump(y))) {
 9295    y = ny = C_s_a_u_i_flo_to_int(&a, 1, y);
 9296  }
 9297
 9298  integer_divrem(&a, x, y, NULL, &r);
 9299
 9300  if (C_truep(nx) || C_truep(ny)) {
 9301    C_word newr = C_a_i_exact_to_inexact(ptr, 1, r);
 9302    clear_buffer_object(ab, r);
 9303    r = newr;
 9304
 9305    clear_buffer_object(ab, nx);
 9306    clear_buffer_object(ab, ny);
 9307  }
 9308  return move_buffer_object(ptr, ab, r);
 9309}
 9310
 9311C_regparm C_word
 9312C_s_a_u_i_integer_remainder(C_word **ptr, C_word n, C_word x, C_word y)
 9313{
 9314  C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, r;
 9315  if (y == C_fix(0)) C_div_by_zero_error("remainder");
 9316  integer_divrem(&a, x, y, NULL, &r);
 9317  return move_buffer_object(ptr, ab, r);
 9318}
 9319
 9320/* Modulo's sign follows y (whereas remainder's sign follows x) */
 9321C_regparm C_word
 9322C_s_a_i_modulo(C_word **ptr, C_word n, C_word x, C_word y)
 9323{
 9324  C_word ab[C_SIZEOF_FIX_BIGNUM], *a = ab, r,
 9325         nx = C_SCHEME_FALSE, ny = C_SCHEME_FALSE;
 9326
 9327  if (!C_truep(C_i_integerp(x)))
 9328    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "modulo", x);
 9329  if (!C_truep(C_i_integerp(y)))
 9330    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "modulo", y);
 9331  if (C_truep(C_i_zerop(y))) C_div_by_zero_error("modulo");
 9332
 9333  if (C_truep(C_i_flonump(x))) {
 9334    if C_truep(C_i_flonump(y)) {
 9335      double dx = C_flonum_magnitude(x), dy = C_flonum_magnitude(y), tmp;
 9336
 9337      C_modf(dx / dy, &tmp);
 9338      tmp = dx - tmp * dy;
 9339      if ((dx > 0.0) != (dy > 0.0) && tmp != 0.0) {
 9340        return C_flonum(ptr, tmp + dy);
 9341      } else {
 9342        return C_flonum(ptr, tmp);
 9343      }
 9344    }
 9345    x = nx = C_s_a_u_i_flo_to_int(&a, 1, x);
 9346  }
 9347  if (C_truep(C_i_flonump(y))) {
 9348    y = ny = C_s_a_u_i_flo_to_int(&a, 1, y);
 9349  }
 9350
 9351  integer_divrem(&a, x, y, NULL, &r);
 9352  if (C_i_positivep(y) != C_i_positivep(r) && r != C_fix(0)) {
 9353    C_word m = C_s_a_i_plus(ptr, 2, r, y);
 9354    m = move_buffer_object(ptr, ab, m);
 9355    clear_buffer_object(ab, r);
 9356    r = m;
 9357  }
 9358
 9359  if (C_truep(nx) || C_truep(ny)) {
 9360    C_word newr = C_a_i_exact_to_inexact(ptr, 1, r);
 9361    clear_buffer_object(ab, r);
 9362    r = newr;
 9363
 9364    clear_buffer_object(ab, nx);
 9365    clear_buffer_object(ab, ny);
 9366  }
 9367
 9368  return move_buffer_object(ptr, ab, r);
 9369}
 9370
 9371C_regparm C_word
 9372C_s_a_u_i_integer_modulo(C_word **ptr, C_word n, C_word x, C_word y)
 9373{
 9374  C_word ab[C_SIZEOF_FIX_BIGNUM], *a = ab, r;
 9375  if (y == C_fix(0)) C_div_by_zero_error("modulo");
 9376
 9377  integer_divrem(&a, x, y, NULL, &r);
 9378  if (C_i_positivep(y) != C_i_positivep(r) && r != C_fix(0)) {
 9379    C_word m = C_s_a_u_i_integer_plus(ptr, 2, r, y);
 9380    m = move_buffer_object(ptr, ab, m);
 9381    clear_buffer_object(ab, r);
 9382    r = m;
 9383  }
 9384  return move_buffer_object(ptr, ab, r);
 9385}
 9386
 9387C_regparm C_word
 9388C_s_a_i_quotient(C_word **ptr, C_word n, C_word x, C_word y)
 9389{
 9390  C_word ab[C_SIZEOF_FIX_BIGNUM*4+C_SIZEOF_FLONUM*2], *a = ab, q,
 9391         nx = C_SCHEME_FALSE, ny = C_SCHEME_FALSE;
 9392
 9393  if (!C_truep(C_i_integerp(x)))
 9394    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "quotient", x);
 9395  if (!C_truep(C_i_integerp(y)))
 9396    barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "quotient", y);
 9397  if (C_truep(C_i_zerop(y))) C_div_by_zero_error("quotient");
 9398
 9399  if (C_truep(C_i_flonump(x))) {
 9400    if C_truep(C_i_flonump(y)) {
 9401      double dx = C_flonum_magnitude(x), dy = C_flonum_magnitude(y), tmp;
 9402
 9403      C_modf(dx / dy, &tmp);
 9404      return C_flonum(ptr, tmp);
 9405    }
 9406    x = nx = C_s_a_u_i_flo_to_int(&a, 1, x);
 9407  }
 9408  if (C_truep(C_i_flonump(y))) {
 9409    y = ny = C_s_a_u_i_flo_to_int(&a, 1, y);
 9410  }
 9411
 9412  integer_divrem(&a, x, y, &q, NULL);
 9413
 9414  if (C_truep(nx) || C_truep(ny)) {
 9415    C_word newq = C_a_i_exact_to_inexact(ptr, 1, q);
 9416    clear_buffer_object(ab, q);
 9417    q = newq;
 9418
 9419    clear_buffer_object(ab, nx);
 9420    clear_buffer_object(ab, ny);
 9421  }
 9422  return move_buffer_object(ptr, ab, q);
 9423}
 9424
 9425C_regparm C_word
 9426C_s_a_u_i_integer_quotient(C_word **ptr, C_word n, C_word x, C_word y)
 9427{
 9428  C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, q;
 9429  if (y == C_fix(0)) C_div_by_zero_error("quotient");
 9430  integer_divrem(&a, x, y, &q, NULL);
 9431  return move_buffer_object(ptr, ab, q);
 9432}
 9433
 9434
 9435/* For help understanding this algorithm, see:
 9436   Knuth, Donald E., "The Art of Computer Programming",
 9437   volume 2, "Seminumerical Algorithms"
 9438   section 4.3.1, "Multiple-Precision Arithmetic".
 9439
 9440   [Yeah, that's a nice book but that particular section is not
 9441   helpful at all, which is also pointed out by P. Brinch Hansen's
 9442   "Multiple-Length Division Revisited: A Tour Of The Minefield".
 9443   That's a more down-to-earth step-by-step explanation of the
 9444   algorithm.  Add to this the C implementation in Hacker's Delight
 9445   (section 9-2, p141--142) and you may be able to grok this...
 9446   ...barely, if you're as math-challenged as I am -- sjamaan]
 9447
 9448   This assumes that numerator >= denominator!
 9449*/
 9450static void
 9451bignum_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)
 9452{
 9453  C_word quotient = C_SCHEME_UNDEFINED, remainder = C_SCHEME_UNDEFINED,
 9454         return_rem = C_mk_nbool(r == NULL), size;
 9455
 9456  if (q != NULL) {
 9457    size = C_fix(C_bignum_size(num) + 1 - C_bignum_size(denom));
 9458    quotient = C_allocate_scratch_bignum(ptr, size, q_negp, C_SCHEME_FALSE);
 9459  }
 9460
 9461  /* An object is always required to receive the remainder */
 9462  size = C_fix(C_bignum_size(num) + 1);
 9463  remainder = C_allocate_scratch_bignum(ptr, size, r_negp, C_SCHEME_FALSE);
 9464  bignum_destructive_divide_full(num, denom, quotient, remainder, return_rem);
 9465
 9466  /* Simplification must be done by the caller, for consistency */
 9467  if (q != NULL) *q = quotient;
 9468  if (r == NULL) {
 9469    C_mutate_scratch_slot(NULL, C_internal_bignum_vector(remainder));
 9470  } else {
 9471    *r = remainder;
 9472  }
 9473}
 9474
 9475/* Compare two numbers as ratnums.  Either may be rat-, fix- or bignums */
 9476static C_word rat_cmp(C_word x, C_word y)
 9477{
 9478  C_word ab[C_SIZEOF_FIX_BIGNUM*4], *a = ab, x1, x2, y1, y2,
 9479         s, t, ssize, tsize, result, negp;
 9480  C_uword *scan;
 9481
 9482  /* Check for 1 or 0; if x or y is this, the other must be the ratnum */
 9483  if (x == C_fix(0)) {	      /* Only the sign of y1 matters */
 9484    return basic_cmp(x, C_u_i_ratnum_num(y), "ratcmp", 0);
 9485  } else if (x == C_fix(1)) { /* x1*y1 <> x2*y2 --> y2 <> y1 | x1/x2 = 1/1 */
 9486    return basic_cmp(C_u_i_ratnum_denom(y), C_u_i_ratnum_num(y), "ratcmp", 0);
 9487  } else if (y == C_fix(0)) { /* Only the sign of x1 matters */
 9488    return basic_cmp(C_u_i_ratnum_num(x), y, "ratcmp", 0);
 9489  } else if (y == C_fix(1)) { /* x1*y1 <> x2*y2 --> x1 <> x2 | y1/y2 = 1/1 */
 9490    return basic_cmp(C_u_i_ratnum_num(x), C_u_i_ratnum_denom(x), "ratcmp", 0);
 9491  }
 9492
 9493  /* Extract components x=x1/x2 and y=y1/y2 */
 9494  if (x & C_FIXNUM_BIT || C_truep(C_bignump(x))) {
 9495    x1 = x;
 9496    x2 = C_fix(1);
 9497  } else {
 9498    x1 = C_u_i_ratnum_num(x);
 9499    x2 = C_u_i_ratnum_denom(x);
 9500  }
 9501
 9502  if (y & C_FIXNUM_BIT || C_truep(C_bignump(y))) {
 9503    y1 = y;
 9504    y2 = C_fix(1);
 9505  } else {
 9506    y1 = C_u_i_ratnum_num(y);
 9507    y2 = C_u_i_ratnum_denom(y);
 9508  }
 9509
 9510  /* We only want to deal with bignums (this is tricky enough) */
 9511  if (x1 & C_FIXNUM_BIT) x1 = C_a_u_i_fix_to_big(&a, x1);
 9512  if (x2 & C_FIXNUM_BIT) x2 = C_a_u_i_fix_to_big(&a, x2);
 9513  if (y1 & C_FIXNUM_BIT) y1 = C_a_u_i_fix_to_big(&a, y1);
 9514  if (y2 & C_FIXNUM_BIT) y2 = C_a_u_i_fix_to_big(&a, y2);
 9515
 9516  /* We multiply using schoolbook method, so this will be very slow in
 9517   * extreme cases.  This is a tradeoff we make so that comparisons
 9518   * are inlineable, which makes a big difference for the common case.
 9519   */
 9520  ssize = C_bignum_size(x1) + C_bignum_size(y2);
 9521  negp = C_mk_bool(C_bignum_negativep(x1));
 9522  s = allocate_tmp_bignum(C_fix(ssize), negp, C_SCHEME_TRUE);
 9523  bignum_digits_multiply(x1, y2, s); /* Swap args if x1 < y2? */
 9524
 9525  tsize = C_bignum_size(y1) + C_bignum_size(x2);
 9526  negp = C_mk_bool(C_bignum_negativep(y1));
 9527  t = allocate_tmp_bignum(C_fix(tsize), negp, C_SCHEME_TRUE);
 9528  bignum_digits_multiply(y1, x2, t); /* Swap args if y1 < x2? */
 9529
 9530  /* Shorten the numbers if needed */
 9531  for (scan = C_bignum_digits(s)+ssize-1; *scan == 0; scan--) ssize--;
 9532  C_bignum_mutate_size(s, ssize);
 9533  for (scan = C_bignum_digits(t)+tsize-1; *scan == 0; scan--) tsize--;
 9534  C_bignum_mutate_size(t, tsize);
 9535
 9536  result = C_i_bignum_cmp(s, t);
 9537
 9538  free_tmp_bignum(t);
 9539  free_tmp_bignum(s);
 9540  return result;
 9541}
 9542
 9543C_regparm double C_bignum_to_double(C_word bignum)
 9544{
 9545  double accumulator = 0;
 9546  C_uword *start = C_bignum_digits(bignum),
 9547          *scan = start + C_bignum_size(bignum);
 9548  while (start < scan) {
 9549    accumulator *= (C_uword)1 << C_BIGNUM_HALF_DIGIT_LENGTH;
 9550    accumulator *= (C_uword)1 << C_BIGNUM_HALF_DIGIT_LENGTH;
 9551    accumulator += (*--scan);
 9552  }
 9553  return(C_bignum_negativep(bignum) ? -accumulator : accumulator);
 9554}
 9555
 9556C_regparm C_word
 9557C_s_a_u_i_flo_to_int(C_word **ptr, C_word n, C_word x)
 9558{
 9559  int exponent;
 9560  double significand = frexp(C_flonum_magnitude(x), &exponent);
 9561
 9562  assert(C_truep(C_u_i_fpintegerp(x)));
 9563
 9564  if (exponent <= 0) {
 9565    return C_fix(0);
 9566  } else if (exponent == 1) { /* TODO: check significand * 2^exp fits fixnum? */
 9567    return significand < 0.0 ? C_fix(-1) : C_fix(1);
 9568  } else {
 9569    C_word size, negp = C_mk_bool(C_flonum_magnitude(x) < 0.0), result;
 9570    C_uword *start, *end;
 9571
 9572    size = C_fix(C_BIGNUM_BITS_TO_DIGITS(exponent));
 9573    result = C_allocate_scratch_bignum(ptr, size, negp, C_SCHEME_FALSE);
 9574
 9575    start = C_bignum_digits(result);
 9576    end = start + C_bignum_size(result);
 9577
 9578    fabs_frexp_to_digits(exponent, fabs(significand), start, end);
 9579    return C_bignum_simplify(result);
 9580  }
 9581}
 9582
 9583static void
 9584fabs_frexp_to_digits(C_uword exp, double sign, C_uword *start, C_uword *scan)
 9585{
 9586  C_uword digit, odd_bits = exp % C_BIGNUM_DIGIT_LENGTH;
 9587
 9588  assert(C_isfinite(sign));
 9589  assert(0.5 <= sign && sign < 1); /* Guaranteed by frexp() and fabs() */
 9590  assert((scan - start) == C_BIGNUM_BITS_TO_DIGITS(exp));
 9591
 9592  if (odd_bits > 0) { /* Handle most significant digit first */
 9593    sign *= (C_uword)1 << odd_bits;
 9594    digit = (C_uword)sign;
 9595    (*--scan) = digit;
 9596    sign -= (double)digit;
 9597  }
 9598
 9599  while (start < scan && sign > 0) {
 9600    sign *= pow(2.0, C_BIGNUM_DIGIT_LENGTH);
 9601    digit = (C_uword)sign;
 9602    (*--scan) = digit;
 9603    sign -= (double)digit;
 9604  }
 9605
 9606  /* Finish up by clearing any remaining, lower, digits */
 9607  while (start < scan)
 9608    (*--scan) = 0;
 9609}
 9610
 9611/* This is a bit weird: We have to compare flonums as bignums due to
 9612 * precision loss on 64-bit platforms.  For simplicity, we convert
 9613 * fixnums to bignums here.
 9614 */
 9615static C_word int_flo_cmp(C_word intnum, C_word flonum)
 9616{
 9617  C_word ab[C_SIZEOF_FIX_BIGNUM + C_SIZEOF_FLONUM], *a = ab, flo_int, res;
 9618  double i, f;
 9619
 9620  f = C_flonum_magnitude(flonum);
 9621
 9622  if (C_isnan(f)) {
 9623    return C_SCHEME_FALSE; /* "mu" */
 9624  } else if (C_isinf(f)) {
 9625    return C_fix((f > 0.0) ? -1 : 1); /* x is smaller if f is +inf.0 */
 9626  } else {
 9627    f = modf(f, &i);
 9628
 9629    flo_int = C_s_a_u_i_flo_to_int(&a, 1, C_flonum(&a, i));
 9630
 9631    res = basic_cmp(intnum, flo_int, "int_flo_cmp", 0);
 9632    clear_buffer_object(ab, flo_int);
 9633
 9634    if (res == C_fix(0)) /* Use fraction to break tie. If f > 0, x is smaller */
 9635      return C_fix((f > 0.0) ? -1 : ((f < 0.0) ? 1 : 0));
 9636    else
 9637      return res;
 9638  }
 9639}
 9640
 9641/* For convenience (ie, to reduce the degree of mindfuck) */
 9642static C_word flo_int_cmp(C_word flonum, C_word intnum)
 9643{
 9644  C_word res = int_flo_cmp(intnum, flonum);
 9645  switch(res) {
 9646  case C_fix(1): return C_fix(-1);
 9647  case C_fix(-1): return C_fix(1);
 9648  default: return res; /* Can be either C_fix(0) or C_SCHEME_FALSE(!) */
 9649  }
 9650}
 9651
 9652/* This code is a bit tedious, but it makes inline comparisons possible! */
 9653static C_word rat_flo_cmp(C_word ratnum, C_word flonum)
 9654{
 9655  C_word ab[C_SIZEOF_FIX_BIGNUM * 4 + C_SIZEOF_FLONUM], *a = ab,
 9656         num, denom, i_int, res, nscaled, iscaled, negp, shift_amount;
 9657  C_uword *scan;
 9658  double i, f;
 9659
 9660  f = C_flonum_magnitude(flonum);
 9661
 9662  if (C_isnan(f)) {
 9663    return C_SCHEME_FALSE; /* "mu" */
 9664  } else if (C_isinf(f)) {
 9665    return C_fix((f > 0.0) ? -1 : 1); /* x is smaller if f is +inf.0 */
 9666  } else {
 9667    /* Scale up the floating-point number to become a whole integer,
 9668     * and remember power of two (# of bits) to shift the numerator.
 9669     */
 9670    shift_amount = 0;
 9671
 9672    /* TODO: This doesn't work for denormalized flonums! */
 9673    while (modf(f, &i) != 0.0) {
 9674      f = ldexp(f, 1);
 9675      shift_amount++;
 9676    }
 9677
 9678    i = f; /* TODO: split i and f so it'll work for denormalized flonums */
 9679
 9680    num = C_u_i_ratnum_num(ratnum);
 9681    negp = C_i_negativep(num);
 9682
 9683    if (C_truep(negp) && i >= 0.0) { /* Save some time if signs differ */
 9684      return C_fix(-1);
 9685    } else if (!C_truep(negp) && i <= 0.0) { /* num is never 0 */
 9686      return C_fix(1);
 9687    } else {
 9688      denom = C_u_i_ratnum_denom(ratnum);
 9689      i_int = C_s_a_u_i_flo_to_int(&a, 1, C_flonum(&a, i));
 9690
 9691      /* Multiply the scaled flonum integer by the denominator, and
 9692       * shift the numerator so that they may be directly compared. */
 9693      iscaled = C_s_a_u_i_integer_times(&a, 2, i_int, denom);
 9694      nscaled = C_s_a_i_arithmetic_shift(&a, 2, num, C_fix(shift_amount));
 9695
 9696      /* Finally, we're ready to compare them! */
 9697      res = basic_cmp(nscaled, iscaled, "rat_flo_cmp", 0);
 9698      clear_buffer_object(ab, nscaled);
 9699      clear_buffer_object(ab, iscaled);
 9700      clear_buffer_object(ab, i_int);
 9701
 9702      return res;
 9703    }
 9704  }
 9705}
 9706
 9707static C_word flo_rat_cmp(C_word flonum, C_word ratnum)
 9708{
 9709  C_word res = rat_flo_cmp(ratnum, flonum);
 9710  switch(res) {
 9711  case C_fix(1): return C_fix(-1);
 9712  case C_fix(-1): return C_fix(1);
 9713  default: return res; /* Can be either C_fix(0) or C_SCHEME_FALSE(!) */
 9714  }
 9715}
 9716
 9717/* The primitive comparison operator.  eqp should be 1 if we're only
 9718 * interested in equality testing (can speed things up and in case of
 9719 * compnums, equality checking is the only available operation).  This
 9720 * may return #f, in case there is no answer (for NaNs) or as a quick
 9721 * and dirty non-zero answer when eqp is true.  Ugly but effective :)
 9722 */
 9723static C_word basic_cmp(C_word x, C_word y, char *loc, int eqp)
 9724{
 9725  if (x & C_FIXNUM_BIT) {
 9726    if (y & C_FIXNUM_BIT) {
 9727      return C_fix((x < y) ? -1 : ((x > y) ? 1 : 0));
 9728    } else if (C_immediatep(y)) {
 9729      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9730    } else if (C_block_header(y) == C_FLONUM_TAG) {
 9731      return int_flo_cmp(x, y);
 9732    } else if (C_truep(C_bignump(y))) {
 9733      C_word ab[C_SIZEOF_FIX_BIGNUM], *a = ab;
 9734      return C_i_bignum_cmp(C_a_u_i_fix_to_big(&a, x), y);
 9735    } else if (C_block_header(y) == C_RATNUM_TAG) {
 9736      if (eqp) return C_SCHEME_FALSE;
 9737      else return rat_cmp(x, y);
 9738    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 9739      if (eqp) return C_SCHEME_FALSE;
 9740      else barf(C_BAD_ARGUMENT_TYPE_COMPLEX_NO_ORDERING_ERROR, loc, y);
 9741    } else {
 9742      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9743    }
 9744  } else if (C_immediatep(x)) {
 9745    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, x);
 9746  } else if (C_block_header(x) == C_FLONUM_TAG) {
 9747    if (y & C_FIXNUM_BIT) {
 9748      return flo_int_cmp(x, y);
 9749    } else if (C_immediatep(y)) {
 9750      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9751    } else if (C_block_header(y) == C_FLONUM_TAG) {
 9752      double a = C_flonum_magnitude(x), b = C_flonum_magnitude(y);
 9753      if (C_isnan(a) || C_isnan(b)) return C_SCHEME_FALSE; /* "mu" */
 9754      else return C_fix((a < b) ? -1 : ((a > b) ? 1 : 0));
 9755    } else if (C_truep(C_bignump(y))) {
 9756      return flo_int_cmp(x, y);
 9757    } else if (C_block_header(y) == C_RATNUM_TAG) {
 9758      return flo_rat_cmp(x, y);
 9759    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 9760      if (eqp) return C_SCHEME_FALSE;
 9761      else barf(C_BAD_ARGUMENT_TYPE_COMPLEX_NO_ORDERING_ERROR, loc, y);
 9762    } else {
 9763      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9764    }
 9765  } else if (C_truep(C_bignump(x))) {
 9766    if (y & C_FIXNUM_BIT) {
 9767      C_word ab[C_SIZEOF_FIX_BIGNUM], *a = ab;
 9768      return C_i_bignum_cmp(x, C_a_u_i_fix_to_big(&a, y));
 9769    } else if (C_immediatep(y)) {
 9770      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9771    } else if (C_block_header(y) == C_FLONUM_TAG) {
 9772      return int_flo_cmp(x, y);
 9773    } else if (C_truep(C_bignump(y))) {
 9774      return C_i_bignum_cmp(x, y);
 9775    } else if (C_block_header(y) == C_RATNUM_TAG) {
 9776      if (eqp) return C_SCHEME_FALSE;
 9777      else return 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_block_header(x) == C_RATNUM_TAG) {
 9785    if (y & C_FIXNUM_BIT) {
 9786      if (eqp) return C_SCHEME_FALSE;
 9787      else return rat_cmp(x, 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 rat_flo_cmp(x, y);
 9792    } else if (C_truep(C_bignump(y))) {
 9793      if (eqp) return C_SCHEME_FALSE;
 9794      else return rat_cmp(x, y);
 9795    } else if (C_block_header(y) == C_RATNUM_TAG) {
 9796      if (eqp) {
 9797        return C_and(C_and(C_i_integer_equalp(C_u_i_ratnum_num(x),
 9798                                              C_u_i_ratnum_num(y)),
 9799                           C_i_integer_equalp(C_u_i_ratnum_denom(x),
 9800                                              C_u_i_ratnum_denom(y))),
 9801                     C_fix(0));
 9802      } else {
 9803        return rat_cmp(x, y);
 9804      }
 9805    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 9806      if (eqp) return C_SCHEME_FALSE;
 9807      else barf(C_BAD_ARGUMENT_TYPE_COMPLEX_NO_ORDERING_ERROR, loc, y);
 9808    } else {
 9809      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9810    }
 9811  } else if (C_block_header(x) == C_CPLXNUM_TAG) {
 9812    if (!eqp) {
 9813      barf(C_BAD_ARGUMENT_TYPE_COMPLEX_NO_ORDERING_ERROR, loc, x);
 9814    } else if (y & C_FIXNUM_BIT) {
 9815      return C_SCHEME_FALSE;
 9816    } else if (C_immediatep(y)) {
 9817      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9818    } else if (C_block_header(y) == C_FLONUM_TAG ||
 9819               C_truep(C_bignump(x)) ||
 9820               C_block_header(y) == C_RATNUM_TAG) {
 9821      return C_SCHEME_FALSE;
 9822    } else if (C_block_header(y) == C_CPLXNUM_TAG) {
 9823      return C_and(C_and(C_i_nequalp(C_u_i_cplxnum_real(x), C_u_i_cplxnum_real(y)),
 9824                         C_i_nequalp(C_u_i_cplxnum_imag(x), C_u_i_cplxnum_imag(y))),
 9825                   C_fix(0));
 9826    } else {
 9827      barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, y);
 9828    }
 9829  } else {
 9830    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, loc, x);
 9831  }
 9832}
 9833
 9834static int bignum_cmp_unsigned(C_word x, C_word y)
 9835{
 9836  C_word xlen = C_bignum_size(x), ylen = C_bignum_size(y);
 9837
 9838  if (xlen < ylen) {
 9839    return -1;
 9840  } else if (xlen > ylen) {
 9841    return 1;
 9842  } else if (x == y) {
 9843    return 0;
 9844  } else {
 9845    C_uword *startx = C_bignum_digits(x),
 9846            *scanx = startx + xlen,
 9847            *scany = C_bignum_digits(y) + ylen;
 9848
 9849    while (startx < scanx) {
 9850      C_uword xdigit = (*--scanx), ydigit = (*--scany);
 9851      if (xdigit < ydigit)
 9852        return -1;
 9853      if (xdigit > ydigit)
 9854        return 1;
 9855    }
 9856    return 0;
 9857  }
 9858}
 9859
 9860C_regparm C_word C_i_bignum_cmp(C_word x, C_word y)
 9861{
 9862  if (C_bignum_negativep(x)) {
 9863    if (C_bignum_negativep(y)) { /* Largest negative number is smallest */
 9864      return C_fix(bignum_cmp_unsigned(y, x));
 9865    } else {
 9866      return C_fix(-1);
 9867    }
 9868  } else {
 9869    if (C_bignum_negativep(y)) {
 9870      return C_fix(1);
 9871    } else {
 9872      return C_fix(bignum_cmp_unsigned(x, y));
 9873    }
 9874  }
 9875}
 9876
 9877void C_ccall C_nequalp(C_word c, C_word *av)
 9878{
 9879  /* C_word closure = av[ 0 ]; */
 9880  C_word k = av[ 1 ];
 9881  C_word x, y, result = C_SCHEME_TRUE;
 9882
 9883  c -= 2;
 9884  av += 2;
 9885  if (c == 0) C_kontinue(k, result);
 9886  x = *(av++);
 9887
 9888  if (c == 1 && !C_truep(C_i_numberp(x)))
 9889    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "=", x);
 9890
 9891  while(--c) {
 9892    y = *(av++);
 9893    result = C_i_nequalp(x, y);
 9894    if (result == C_SCHEME_FALSE) break;
 9895  }
 9896
 9897  C_kontinue(k, result);
 9898}
 9899
 9900C_regparm C_word C_i_nequalp(C_word x, C_word y)
 9901{
 9902   return C_mk_bool(basic_cmp(x, y, "=", 1) == C_fix(0));
 9903}
 9904
 9905C_regparm C_word C_i_integer_equalp(C_word x, C_word y)
 9906{
 9907  if (x & C_FIXNUM_BIT)
 9908    return C_mk_bool(x == y);
 9909  else if (y & C_FIXNUM_BIT)
 9910    return C_SCHEME_FALSE;
 9911  else
 9912    return C_mk_bool(C_i_bignum_cmp(x, y) == C_fix(0));
 9913}
 9914
 9915
 9916void C_ccall C_greaterp(C_word c, C_word *av)
 9917{
 9918  C_word x, y,
 9919    /* closure = av[ 0 ] */
 9920    k = av[ 1 ],
 9921    result = C_SCHEME_TRUE;
 9922
 9923  c -= 2;
 9924  av += 2;
 9925  if (c == 0) C_kontinue(k, result);
 9926
 9927  x = *(av++);
 9928
 9929  if (c == 1 && !C_truep(C_i_numberp(x)))
 9930    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, ">", x);
 9931
 9932  while(--c) {
 9933    y = *(av++);
 9934    result = C_i_greaterp(x, y);
 9935    if (result == C_SCHEME_FALSE) break;
 9936    x = y;
 9937  }
 9938
 9939  C_kontinue(k, result);
 9940}
 9941
 9942
 9943C_regparm C_word C_i_greaterp(C_word x, C_word y)
 9944{
 9945   return C_mk_bool(basic_cmp(x, y, ">", 0) == C_fix(1));
 9946}
 9947
 9948C_regparm C_word C_i_integer_greaterp(C_word x, C_word y)
 9949{
 9950  if (x & C_FIXNUM_BIT) {
 9951    if (y & C_FIXNUM_BIT) {
 9952      return C_mk_bool(C_unfix(x) > C_unfix(y));
 9953    } else {
 9954      return C_mk_bool(C_bignum_negativep(y));
 9955    }
 9956  } else if (y & C_FIXNUM_BIT) {
 9957    return C_mk_nbool(C_bignum_negativep(x));
 9958  } else {
 9959    return C_mk_bool(C_i_bignum_cmp(x, y) == C_fix(1));
 9960  }
 9961}
 9962
 9963void C_ccall C_lessp(C_word c, C_word *av)
 9964{
 9965  C_word x, y,
 9966    /* closure = av[ 0 ] */
 9967    k = av[ 1 ],
 9968    result = C_SCHEME_TRUE;
 9969
 9970  c -= 2;
 9971  av += 2;
 9972  if (c == 0) C_kontinue(k, result);
 9973
 9974  x = *(av++);
 9975
 9976  if (c == 1 && !C_truep(C_i_numberp(x)))
 9977    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "<", x);
 9978
 9979  while(--c) {
 9980    y = *(av++);
 9981    result = C_i_lessp(x, y);
 9982    if (result == C_SCHEME_FALSE) break;
 9983    x = y;
 9984  }
 9985
 9986  C_kontinue(k, result);
 9987}
 9988
 9989
 9990C_regparm C_word C_i_lessp(C_word x, C_word y)
 9991{
 9992   return C_mk_bool(basic_cmp(x, y, "<", 0) == C_fix(-1));
 9993}
 9994
 9995C_regparm C_word C_i_integer_lessp(C_word x, C_word y)
 9996{
 9997  if (x & C_FIXNUM_BIT) {
 9998    if (y & C_FIXNUM_BIT) {
 9999      return C_mk_bool(C_unfix(x) < C_unfix(y));
10000    } else {
10001      return C_mk_nbool(C_bignum_negativep(y));
10002    }
10003  } else if (y & C_FIXNUM_BIT) {
10004    return C_mk_bool(C_bignum_negativep(x));
10005  } else {
10006    return C_mk_bool(C_i_bignum_cmp(x, y) == C_fix(-1));
10007  }
10008}
10009
10010void C_ccall C_greater_or_equal_p(C_word c, C_word *av)
10011{
10012  C_word x, y,
10013    /* closure = av[ 0 ] */
10014    k = av[ 1 ],
10015    result = C_SCHEME_TRUE;
10016
10017  c -= 2;
10018  av += 2;
10019  if (c == 0) C_kontinue(k, result);
10020
10021  x = *(av++);
10022
10023  if (c == 1 && !C_truep(C_i_numberp(x)))
10024    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, ">=", x);
10025
10026  while(--c) {
10027    y = *(av++);
10028    result = C_i_greater_or_equalp(x, y);
10029    if (result == C_SCHEME_FALSE) break;
10030    x = y;
10031  }
10032
10033  C_kontinue(k, result);
10034}
10035
10036
10037C_regparm C_word C_i_greater_or_equalp(C_word x, C_word y)
10038{
10039   C_word res = basic_cmp(x, y, ">=", 0);
10040   return C_mk_bool(res == C_fix(0) || res == C_fix(1));
10041}
10042
10043C_regparm C_word C_i_integer_greater_or_equalp(C_word x, C_word y)
10044{
10045  if (x & C_FIXNUM_BIT) {
10046    if (y & C_FIXNUM_BIT) {
10047      return C_mk_bool(C_unfix(x) >= C_unfix(y));
10048    } else {
10049      return C_mk_bool(C_bignum_negativep(y));
10050    }
10051  } else if (y & C_FIXNUM_BIT) {
10052    return C_mk_nbool(C_bignum_negativep(x));
10053  } else {
10054    C_word res = C_i_bignum_cmp(x, y);
10055    return C_mk_bool(res == C_fix(0) || res == C_fix(1));
10056  }
10057}
10058
10059void C_ccall C_less_or_equal_p(C_word c, C_word *av)
10060{
10061  C_word x, y,
10062    /* closure = av[ 0 ] */
10063    k = av[ 1 ],
10064    result = C_SCHEME_TRUE;
10065
10066  c -= 2;
10067  av += 2;
10068  if (c == 0) C_kontinue(k, result);
10069
10070  x = *(av++);
10071
10072  if (c == 1 && !C_truep(C_i_numberp(x)))
10073    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "<=", x);
10074
10075  while(--c) {
10076    y = *(av++);
10077    result = C_i_less_or_equalp(x, y);
10078    if (result == C_SCHEME_FALSE) break;
10079    x = y;
10080  }
10081
10082  C_kontinue(k, result);
10083}
10084
10085
10086C_regparm C_word C_i_less_or_equalp(C_word x, C_word y)
10087{
10088   C_word res = basic_cmp(x, y, "<=", 0);
10089   return C_mk_bool(res == C_fix(0) || res == C_fix(-1));
10090}
10091
10092
10093C_regparm C_word C_i_integer_less_or_equalp(C_word x, C_word y)
10094{
10095  if (x & C_FIXNUM_BIT) {
10096    if (y & C_FIXNUM_BIT) {
10097      return C_mk_bool(C_unfix(x) <= C_unfix(y));
10098    } else {
10099      return C_mk_nbool(C_bignum_negativep(y));
10100    }
10101  } else if (y & C_FIXNUM_BIT) {
10102    return C_mk_bool(C_bignum_negativep(x));
10103  } else {
10104    C_word res = C_i_bignum_cmp(x, y);
10105    return C_mk_bool(res == C_fix(0) || res == C_fix(-1));
10106  }
10107}
10108
10109
10110void C_ccall C_gc(C_word c, C_word *av)
10111{
10112  C_word
10113    /* closure = av[ 0 ] */
10114    k = av[ 1 ];
10115  int f;
10116  C_word
10117    arg, *p,
10118    size = 0;
10119
10120  if(c == 3) {
10121    arg = av[ 2 ];
10122    f = C_truep(arg);
10123  }
10124  else if(c != 2) C_bad_min_argc(c, 2);
10125  else f = 1;
10126
10127  C_save(k);
10128  p = C_temporary_stack;
10129
10130  if(c == 3) {
10131    if((arg & C_FIXNUM_BIT) != 0) size = C_unfix(arg);
10132    else if(arg == C_SCHEME_END_OF_LIST) size = percentage(heap_size, C_heap_growth);
10133  }
10134
10135  if(size && !C_heap_size_is_fixed) {
10136    C_rereclaim2(size, 0);
10137    C_temporary_stack = C_temporary_stack_bottom;
10138    gc_2(0, p);
10139  }
10140  else if(f) C_fromspace_top = C_fromspace_limit;
10141
10142  C_reclaim((void *)gc_2, 1);
10143}
10144
10145
10146void C_ccall gc_2(C_word c, C_word *av)
10147{
10148  C_word k = av[ 0 ];
10149  C_kontinue(k, C_fix((C_uword)C_fromspace_limit - (C_uword)C_fromspace_top));
10150}
10151
10152
10153void C_ccall C_open_file_port(C_word c, C_word *av)
10154{
10155  C_word
10156    /* closure = av[ 0 ] */
10157    k = av[ 1 ],
10158    port = av[ 2 ],
10159    channel = av[ 3 ],
10160    mode = av[ 4 ];
10161  C_FILEPTR fp = (C_FILEPTR)NULL;
10162  C_char *fmode;
10163  C_word n, bv, fbv;
10164  C_char *buf;
10165  C_WCHAR *fbuf;
10166
10167  switch(channel) {
10168  case C_fix(0): fp = C_stdin; break;
10169  case C_fix(1): fp = C_stdout; break;
10170  case C_fix(2): fp = C_stderr; break;
10171  default:
10172    bv = C_block_item(channel, 0);
10173    buf = C_c_string(bv);
10174    fbv = C_block_item(mode, 0);
10175    fmode = C_c_string(fbv);
10176    if (C_header_size(C_block_item(channel, 0)) - 1 != strlen(buf))
10177      barf(C_ASCIIZ_REPRESENTATION_ERROR, "open", channel);
10178    if (C_header_size(C_block_item(mode, 0)) - 1 != strlen(fmode))
10179      barf(C_ASCIIZ_REPRESENTATION_ERROR, "open", mode);
10180    fbuf = C_OS_FILENAME(bv, 0);
10181    fp = C_fopen(fbuf, C_OS_FILENAME(fbv, 1));
10182  }
10183
10184  C_set_block_item(port, 0, (C_word)fp);
10185  C_kontinue(k, C_mk_bool(fp != NULL));
10186}
10187
10188
10189void C_ccall C_allocate_vector(C_word c, C_word *av)
10190{
10191  C_word
10192    /* closure = av[ 0 ] */
10193    k = av[ 1 ],
10194    size, init, bytes, n, *p;
10195
10196  if(c != 4) C_bad_argc(c, 4);
10197
10198  size = av[ 2 ];
10199  init = av[ 3 ];
10200  n = C_unfix(size);
10201
10202  if(n > C_HEADER_SIZE_MASK || n < 0)
10203    barf(C_OUT_OF_BOUNDS_ERROR, NULL, size, C_fix(C_HEADER_SIZE_MASK));
10204
10205  bytes = C_wordstobytes(n) + sizeof(C_word);
10206
10207  C_save(k);
10208  C_save(size);
10209  C_save(init);
10210  C_save(C_fix(bytes));
10211
10212  if(!C_demand(C_bytestowords(bytes))) {
10213    /* Allocate on heap: */
10214    if((C_uword)(C_fromspace_limit - C_fromspace_top) < (bytes + stack_size * 2))
10215      C_fromspace_top = C_fromspace_limit; /* trigger major GC */
10216
10217    C_save(C_SCHEME_TRUE);
10218    /* We explicitly pass 5 here, that's the number of things saved.
10219     * That's the arguments, plus one additional thing: the mode.
10220     */
10221    C_reclaim((void *)allocate_vector_2, 5);
10222  }
10223
10224  C_save(C_SCHEME_FALSE);
10225  p = C_temporary_stack;
10226  C_temporary_stack = C_temporary_stack_bottom;
10227  allocate_vector_2(0, p);
10228}
10229
10230
10231void C_ccall allocate_vector_2(C_word c, C_word *av)
10232{
10233  C_word
10234    mode = av[ 0 ],
10235    bytes = C_unfix(av[ 1 ]),
10236    init = av[ 2 ],
10237    size = C_unfix(av[ 3 ]),
10238    k = av[ 4 ],
10239    *v0, v;
10240
10241  if(C_truep(mode)) {
10242    while((C_uword)(C_fromspace_limit - C_fromspace_top) < (bytes + stack_size)) {
10243      if(C_heap_size_is_fixed)
10244	panic(C_text("out of memory - cannot allocate vector (heap resizing disabled)"));
10245
10246      C_save(init);
10247      C_save(k);
10248      C_rereclaim2(percentage(heap_size, C_heap_growth) + (C_uword)bytes, 0);
10249      k = C_restore;
10250      init = C_restore;
10251    }
10252
10253    v0 = (C_word *)C_align((C_word)C_fromspace_top);
10254    C_fromspace_top += C_align(bytes);
10255  }
10256  else v0 = C_alloc(C_bytestowords(bytes));
10257
10258  v = (C_word)v0;
10259  *(v0++) = C_VECTOR_TYPE | size;
10260  while(size--) *(v0++) = init;
10261  C_kontinue(k, v);
10262}
10263
10264void C_ccall C_allocate_bytevector(C_word c, C_word *av)
10265{
10266  C_word
10267    /* closure = av[ 0 ] */
10268    k = av[ 1 ],
10269    size, init, align8, bytes, str, n, *p;
10270
10271  if(c != 4) C_bad_argc(c, 4);
10272
10273  size = av[ 2 ];
10274  init = av[ 3 ];
10275  n = C_unfix(size);
10276
10277  if(n > C_HEADER_SIZE_MASK || n < 0)
10278    barf(C_OUT_OF_BOUNDS_ERROR, NULL, size, C_fix(C_HEADER_SIZE_MASK));
10279
10280  bytes = n + sizeof(C_word) * 2;
10281
10282  C_save(k);
10283  C_save(size);
10284  C_save(init);
10285  C_save(C_fix(bytes));
10286
10287  if(!C_demand(C_bytestowords(bytes))) {
10288    /* Allocate on heap: */
10289    if((C_uword)(C_fromspace_limit - C_fromspace_top) < (bytes + stack_size * 2))
10290      C_fromspace_top = C_fromspace_limit; /* trigger major GC */
10291
10292    C_save(C_SCHEME_TRUE);
10293    /* We explicitly pass 5 here, that's the number of things saved.
10294     * That's the arguments, plus one additional thing: the mode.
10295     */
10296    C_reclaim((void *)allocate_bytevector_2, 5);
10297  }
10298
10299  C_save(C_SCHEME_FALSE);
10300  p = C_temporary_stack;
10301  C_temporary_stack = C_temporary_stack_bottom;
10302  allocate_bytevector_2(0, p);
10303}
10304
10305
10306void C_ccall allocate_bytevector_2(C_word c, C_word *av)
10307{
10308  C_word
10309    mode = av[ 0 ],
10310    bytes = C_unfix(av[ 1 ]),
10311    init = av[ 2 ],
10312    size = C_unfix(av[ 3 ]),
10313    k = av[ 4 ],
10314    *v0, v;
10315  char buf[ 4 ];
10316
10317  if(C_truep(mode)) {
10318    while((C_uword)(C_fromspace_limit - C_fromspace_top) < (bytes + stack_size)) {
10319      if(C_heap_size_is_fixed)
10320	panic(C_text("out of memory - cannot allocate vector (heap resizing disabled)"));
10321
10322      C_save(init);
10323      C_save(k);
10324      C_rereclaim2(percentage(heap_size, C_heap_growth) + (C_uword)bytes, 0);
10325      k = C_restore;
10326      init = C_restore;
10327    }
10328
10329    v0 = (C_word *)C_align((C_word)C_fromspace_top);
10330    C_fromspace_top += C_align(bytes);
10331  }
10332  else v0 = C_alloc(C_bytestowords(bytes));
10333
10334#ifndef C_SIXTY_FOUR
10335  if(C_aligned8(v0)) ++v0;
10336#endif
10337
10338  v = (C_word)v0;
10339  *(v0++) = C_BYTEVECTOR_TYPE | size;
10340
10341  if(C_truep(init)) C_memset(v0, C_unfix(init), size);
10342
10343  C_kontinue(k, v);
10344}
10345
10346static C_word allocate_tmp_bignum(C_word size, C_word negp, C_word initp)
10347{
10348  C_word *mem = C_malloc(C_wordstobytes(C_SIZEOF_BIGNUM(C_unfix(size)))),
10349          bigvec = (C_word)(mem + C_SIZEOF_BIGNUM_WRAPPER);
10350  if (mem == NULL) abort();     /* TODO: panic */
10351
10352  C_block_header_init(bigvec, C_BYTEVECTOR_TYPE | C_wordstobytes(C_unfix(size)+1));
10353  C_set_block_item(bigvec, 0, C_truep(negp));
10354
10355  if (C_truep(initp)) {
10356    C_memset(((C_uword *)C_data_pointer(bigvec))+1,
10357             0, C_wordstobytes(C_unfix(size)));
10358  }
10359
10360  return C_a_i_bignum_wrapper(&mem, bigvec);
10361}
10362
10363C_regparm C_word
10364C_allocate_scratch_bignum(C_word **ptr, C_word size, C_word negp, C_word initp)
10365{
10366  C_word big, bigvec = C_scratch_alloc(C_SIZEOF_INTERNAL_BIGNUM_VECTOR(C_unfix(size)));
10367
10368  C_block_header_init(bigvec, C_BYTEVECTOR_TYPE | C_wordstobytes(C_unfix(size)+1));
10369  C_set_block_item(bigvec, 0, C_truep(negp));
10370
10371  if (C_truep(initp)) {
10372    C_memset(((C_uword *)C_data_pointer(bigvec))+1,
10373             0, C_wordstobytes(C_unfix(size)));
10374  }
10375
10376  big = C_a_i_bignum_wrapper(ptr, bigvec);
10377  C_mutate_scratch_slot(&C_internal_bignum_vector(big), bigvec);
10378  return big;
10379}
10380
10381/* Simplification: scan trailing zeroes, then return a fixnum if the
10382 * value fits, or trim the bignum's length.  If the bignum was stored
10383 * in scratch space, we mark it as reclaimable.  This means any
10384 * references to the original bignum are invalid after simplification!
10385 */
10386C_regparm C_word C_bignum_simplify(C_word big)
10387{
10388  C_uword *start = C_bignum_digits(big),
10389          *last_digit = start + C_bignum_size(big) - 1,
10390          *scan = last_digit, tmp;
10391  int length;
10392
10393  while (scan >= start && *scan == 0)
10394    scan--;
10395  length = scan - start + 1;
10396
10397  switch(length) {
10398  case 0:
10399    if (C_in_scratchspacep(C_internal_bignum_vector(big)))
10400      C_mutate_scratch_slot(NULL, C_internal_bignum_vector(big));
10401    return C_fix(0);
10402  case 1:
10403    tmp = *start;
10404    if (C_bignum_negativep(big) ?
10405        !(tmp & C_INT_SIGN_BIT) && C_fitsinfixnump(-(C_word)tmp) :
10406        C_ufitsinfixnump(tmp)) {
10407      if (C_in_scratchspacep(C_internal_bignum_vector(big)))
10408        C_mutate_scratch_slot(NULL, C_internal_bignum_vector(big));
10409      return C_bignum_negativep(big) ? C_fix(-(C_word)tmp) : C_fix(tmp);
10410    }
10411    /* FALLTHROUGH */
10412  default:
10413    if (scan < last_digit) C_bignum_mutate_size(big, length);
10414    return big;
10415  }
10416}
10417
10418static void bignum_digits_destructive_negate(C_word result)
10419{
10420  C_uword *scan, *end, digit, sum;
10421
10422  scan = C_bignum_digits(result);
10423  end = scan + C_bignum_size(result);
10424
10425  do {
10426    digit = ~*scan;
10427    sum = digit + 1;
10428    *scan++ = sum;
10429  } while (sum == 0 && scan < end);
10430
10431  for (; scan < end; scan++) {
10432    *scan = ~*scan;
10433  }
10434}
10435
10436static C_uword
10437bignum_digits_destructive_scale_up_with_carry(C_uword *start, C_uword *end, C_uword factor, C_uword carry)
10438{
10439  C_uword digit, p;
10440
10441  assert(C_fitsinbignumhalfdigitp(carry));
10442  assert(C_fitsinbignumhalfdigitp(factor));
10443
10444  /* See fixnum_times.  Substitute xlo = factor, xhi = 0, y = digit
10445   * and simplify the result to reduce variable usage.
10446   */
10447  while (start < end) {
10448    digit = (*start);
10449
10450    p = factor * C_BIGNUM_DIGIT_LO_HALF(digit) + carry;
10451    carry = C_BIGNUM_DIGIT_LO_HALF(p);
10452
10453    p = factor * C_BIGNUM_DIGIT_HI_HALF(digit) + C_BIGNUM_DIGIT_HI_HALF(p);
10454    (*start++) = C_BIGNUM_DIGIT_COMBINE(C_BIGNUM_DIGIT_LO_HALF(p), carry);
10455    carry = C_BIGNUM_DIGIT_HI_HALF(p);
10456  }
10457  return carry;
10458}
10459
10460static C_uword
10461bignum_digits_destructive_scale_down(C_uword *start, C_uword *end, C_uword denominator)
10462{
10463  C_uword digit, k = 0;
10464  C_uhword q_j_hi, q_j_lo;
10465
10466  /* Single digit divisor case from Hacker's Delight, Figure 9-1,
10467   * adapted to modify u[] in-place instead of writing to q[].
10468   */
10469  while (start < end) {
10470    digit = (*--end);
10471
10472    k = C_BIGNUM_DIGIT_COMBINE(k, C_BIGNUM_DIGIT_HI_HALF(digit)); /* j */
10473    q_j_hi = k / denominator;
10474    k -= q_j_hi * denominator;
10475
10476    k = C_BIGNUM_DIGIT_COMBINE(k, C_BIGNUM_DIGIT_LO_HALF(digit)); /* j-1 */
10477    q_j_lo = k / denominator;
10478    k -= q_j_lo * denominator;
10479
10480    *end = C_BIGNUM_DIGIT_COMBINE(q_j_hi, q_j_lo);
10481  }
10482  return k;
10483}
10484
10485static C_uword
10486bignum_digits_destructive_shift_right(C_uword *start, C_uword *end, int shift_right, int negp)
10487{
10488  int shift_left = C_BIGNUM_DIGIT_LENGTH - shift_right;
10489  C_uword digit, carry = negp ? ((~(C_uword)0) << shift_left) : 0;
10490
10491  assert(shift_right < C_BIGNUM_DIGIT_LENGTH);
10492
10493  while (start < end) {
10494    digit = *(--end);
10495    *end = (digit >> shift_right) | carry;
10496    carry = digit << shift_left;
10497  }
10498  return carry >> shift_left; /* The bits that were shifted out to the right */
10499}
10500
10501static C_uword
10502bignum_digits_destructive_shift_left(C_uword *start, C_uword *end, int shift_left)
10503{
10504  C_uword carry = 0, digit;
10505  int shift_right = C_BIGNUM_DIGIT_LENGTH - shift_left;
10506
10507  assert(shift_left < C_BIGNUM_DIGIT_LENGTH);
10508
10509  while (start < end) {
10510    digit = *start;
10511    (*start++) = (digit << shift_left) | carry;
10512    carry = digit >> shift_right;
10513  }
10514  return carry;	 /* This would end up as most significant digit if it fit */
10515}
10516
10517static C_regparm void
10518bignum_digits_multiply(C_word x, C_word y, C_word result)
10519{
10520  C_uword product,
10521          *xd = C_bignum_digits(x),
10522          *yd = C_bignum_digits(y),
10523          *rd = C_bignum_digits(result);
10524  C_uhword carry, yj;
10525  /* Lengths in halfwords */
10526  int i, j, length_x = C_bignum_size(x) * 2, length_y = C_bignum_size(y) * 2;
10527
10528  /* From Hacker's Delight, Figure 8-1 (top part) */
10529  for (j = 0; j < length_y; ++j) {
10530    yj = C_uhword_ref(yd, j);
10531    if (yj == 0) continue;
10532    carry = 0;
10533    for (i = 0; i < length_x; ++i) {
10534      product = (C_uword)C_uhword_ref(xd, i) * yj +
10535                (C_uword)C_uhword_ref(rd, i + j) + carry;
10536      C_uhword_set(rd, i + j, product);
10537      carry = C_BIGNUM_DIGIT_HI_HALF(product);
10538    }
10539    C_uhword_set(rd, j + length_x, carry);
10540  }
10541}
10542
10543
10544/* "small" is either a number that fits a halfdigit, or a power of two */
10545static C_regparm void
10546bignum_destructive_divide_unsigned_small(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r)
10547{
10548  C_word size, quotient, q_negp = C_mk_bool((y & C_INT_SIGN_BIT) ?
10549                                            !(C_bignum_negativep(x)) :
10550                                            C_bignum_negativep(x)),
10551         r_negp = C_mk_bool(C_bignum_negativep(x));
10552  C_uword *start, *end, remainder;
10553  int shift_amount;
10554
10555  size = C_fix(C_bignum_size(x));
10556  quotient = C_allocate_scratch_bignum(ptr, size, q_negp, C_SCHEME_FALSE);
10557  bignum_digits_destructive_copy(quotient, x);
10558
10559  start = C_bignum_digits(quotient);
10560  end = start + C_bignum_size(quotient);
10561
10562  y = (y & C_INT_SIGN_BIT) ? -C_unfix(y) : C_unfix(y);
10563
10564  shift_amount = C_ilen(y) - 1;
10565  if (((C_uword)1 << shift_amount) == y) { /* Power of two?  Shift! */
10566    remainder = bignum_digits_destructive_shift_right(start,end,shift_amount,0);
10567    assert(C_ufitsinfixnump(remainder));
10568  } else {
10569    remainder = bignum_digits_destructive_scale_down(start, end, y);
10570    assert(C_fitsinbignumhalfdigitp(remainder));
10571  }
10572
10573  if (r != NULL) *r = C_truep(r_negp) ? C_fix(-remainder) : C_fix(remainder);
10574  /* Calling this function only makes sense if quotient is needed */
10575  *q = C_bignum_simplify(quotient);
10576}
10577
10578static C_regparm void
10579bignum_destructive_divide_full(C_word numerator, C_word denominator, C_word quotient, C_word remainder, C_word return_remainder)
10580{
10581  C_word length = C_bignum_size(denominator);
10582  C_uword d1 = *(C_bignum_digits(denominator) + length - 1),
10583          *startr = C_bignum_digits(remainder),
10584          *endr = startr + C_bignum_size(remainder);
10585  int shift;
10586
10587  shift = C_BIGNUM_DIGIT_LENGTH - C_ilen(d1); /* nlz */
10588
10589  /* We have to work on halfdigits, so we shift out only the necessary
10590   * amount in order fill out that halfdigit (base is halved).
10591   * This trick is shamelessly stolen from Gauche :)
10592   * See below for part 2 of the trick.
10593   */
10594  if (shift >= C_BIGNUM_HALF_DIGIT_LENGTH)
10595    shift -= C_BIGNUM_HALF_DIGIT_LENGTH;
10596
10597  /* Code below won't always set high halfdigit of quotient, so do it here. */
10598  if (quotient != C_SCHEME_UNDEFINED)
10599    C_bignum_digits(quotient)[C_bignum_size(quotient)-1] = 0;
10600
10601  bignum_digits_destructive_copy(remainder, numerator);
10602  *(endr-1) = 0;    /* Ensure most significant digit is initialised */
10603  if (shift == 0) { /* Already normalized */
10604    bignum_destructive_divide_normalized(remainder, denominator, quotient);
10605  } else { /* Requires normalisation; allocate scratch denominator for this */
10606    C_uword *startnd;
10607    C_word ndenom;
10608
10609    bignum_digits_destructive_shift_left(startr, endr, shift);
10610
10611    ndenom = allocate_tmp_bignum(C_fix(length), C_SCHEME_FALSE, C_SCHEME_FALSE);
10612    startnd = C_bignum_digits(ndenom);
10613    bignum_digits_destructive_copy(ndenom, denominator);
10614    bignum_digits_destructive_shift_left(startnd, startnd+length, shift);
10615
10616    bignum_destructive_divide_normalized(remainder, ndenom, quotient);
10617    if (C_truep(return_remainder)) /* Otherwise, don't bother shifting back */
10618      bignum_digits_destructive_shift_right(startr, endr, shift, 0);
10619
10620    free_tmp_bignum(ndenom);
10621  }
10622}
10623
10624static C_regparm void
10625bignum_destructive_divide_normalized(C_word big_u, C_word big_v, C_word big_q)
10626{
10627  C_uword *v = C_bignum_digits(big_v),
10628          *u = C_bignum_digits(big_u),
10629          *q = big_q == C_SCHEME_UNDEFINED ? NULL : C_bignum_digits(big_q),
10630           p,               /* product of estimated quotient & "denominator" */
10631           hat, qhat, rhat, /* estimated quotient and remainder digit */
10632           vn_1, vn_2;      /* "cached" values v[n-1], v[n-2] */
10633  C_word t, k;              /* Two helpers: temp/final remainder and "borrow" */
10634  /* We use plain ints here, which theoretically may not be enough on
10635   * 64-bit for an insanely huge number, but it is a _lot_ faster.
10636   */
10637  int n = C_bignum_size(big_v) * 2,       /* in halfwords */
10638      m = (C_bignum_size(big_u) * 2) - 2; /* Correct for extra digit */
10639  int i, j;		   /* loop  vars */
10640
10641  /* Part 2 of Gauche's aforementioned trick: */
10642  if (C_uhword_ref(v, n-1) == 0) n--;
10643
10644  /* These won't change during the loop, but are used in every step. */
10645  vn_1 = C_uhword_ref(v, n-1);
10646  vn_2 = C_uhword_ref(v, n-2);
10647
10648  /* See also Hacker's Delight, Figure 9-1.  This is almost exactly that. */
10649  for (j = m - n; j >= 0; j--) {
10650    hat = C_BIGNUM_DIGIT_COMBINE(C_uhword_ref(u, j+n), C_uhword_ref(u, j+n-1));
10651    if (hat == 0) {
10652      if (q != NULL) C_uhword_set(q, j, 0);
10653      continue;
10654    }
10655    qhat = hat / vn_1;
10656    rhat = hat % vn_1;
10657
10658    /* Two whiles is faster than one big check with an OR.  Thanks, Gauche! */
10659    while(qhat >= ((C_uword)1 << C_BIGNUM_HALF_DIGIT_LENGTH)) { qhat--; rhat += vn_1; }
10660    while(qhat * vn_2 > C_BIGNUM_DIGIT_COMBINE(rhat, C_uhword_ref(u, j+n-2))
10661	  && rhat < ((C_uword)1 << C_BIGNUM_HALF_DIGIT_LENGTH)) {
10662      qhat--;
10663      rhat += vn_1;
10664    }
10665
10666    /* Multiply and subtract */
10667    k = 0;
10668    for (i = 0; i < n; i++) {
10669      p = qhat * C_uhword_ref(v, i);
10670      t = C_uhword_ref(u, i+j) - k - C_BIGNUM_DIGIT_LO_HALF(p);
10671      C_uhword_set(u, i+j, t);
10672      k = C_BIGNUM_DIGIT_HI_HALF(p) - (t >> C_BIGNUM_HALF_DIGIT_LENGTH);
10673    }
10674    t = C_uhword_ref(u,j+n) - k;
10675    C_uhword_set(u, j+n, t);
10676
10677    if (t < 0) {		/* Subtracted too much? */
10678      qhat--;
10679      k = 0;
10680      for (i = 0; i < n; i++) {
10681        t = (C_uword)C_uhword_ref(u, i+j) + C_uhword_ref(v, i) + k;
10682        C_uhword_set(u, i+j, t);
10683	k = t >> C_BIGNUM_HALF_DIGIT_LENGTH;
10684      }
10685      C_uhword_set(u, j+n, (C_uhword_ref(u, j+n) + k));
10686    }
10687    if (q != NULL) C_uhword_set(q, j, qhat);
10688  } /* end j */
10689}
10690
10691
10692/* XXX this should be an inline_allocate routine */
10693void C_ccall C_string_to_symbol(C_word c, C_word *av)
10694{
10695  C_word
10696    /* closure = av[ 0 ] */
10697    k = av[ 1 ];
10698  int len, key;
10699  C_word s, *a = C_alloc(C_SIZEOF_SYMBOL + C_SIZEOF_PAIR), b;
10700  C_char *name;
10701
10702  b = av[ 2 ];
10703  len = C_header_size(b) - 1;
10704  name = C_c_string(b);
10705
10706  key = hash_string(len, name, symbol_table->size, symbol_table->rand);
10707  if(!C_truep(s = lookup(key, len, name, symbol_table)))
10708    s = add_symbol(&a, key, b, symbol_table);
10709
10710  C_kontinue(k, s);
10711}
10712
10713/* XXX this should be an inline_allocate routine */
10714void C_ccall C_string_to_keyword(C_word c, C_word *av)
10715{
10716  C_word
10717    /* closure = av[ 0 ] */
10718    k = av[ 1 ];
10719  int len, key;
10720  C_word s, *a = C_alloc(C_SIZEOF_SYMBOL + C_SIZEOF_PAIR), b;
10721  C_char *name;
10722
10723  b = av[ 2 ];
10724  len = C_header_size(b) - 1;
10725  name = C_c_string(b);
10726  key = hash_string(len, name, keyword_table->size, keyword_table->rand);
10727
10728  if(!C_truep(s = lookup(key, len, name, keyword_table))) {
10729    s = add_symbol(&a, key, b, keyword_table);
10730    C_set_block_item(s, 0, s); /* Keywords evaluate to themselves */
10731    C_set_block_item(s, 2, C_SCHEME_FALSE); /* Keywords have no plists */
10732  }
10733  C_kontinue(k, s);
10734}
10735
10736/* This will usually return a flonum, but it may also return a cplxnum
10737 * consisting of two flonums, making for a total of 11 words.
10738 */
10739C_regparm C_word
10740C_a_i_exact_to_inexact(C_word **ptr, int c, C_word n)
10741{
10742  if (n & C_FIXNUM_BIT) {
10743    return C_flonum(ptr, (double)C_unfix(n));
10744  } else if (C_immediatep(n)) {
10745    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "exact->inexact", n);
10746  } else if (C_block_header(n) == C_FLONUM_TAG) {
10747    return n;
10748  } else if (C_truep(C_bignump(n))) {
10749    return C_a_u_i_big_to_flo(ptr, c, n);
10750  } else if (C_block_header(n) == C_CPLXNUM_TAG) {
10751    return C_cplxnum(ptr, C_a_i_exact_to_inexact(ptr, 1, C_u_i_cplxnum_real(n)),
10752                     C_a_i_exact_to_inexact(ptr, 1, C_u_i_cplxnum_imag(n)));
10753  /* The horribly painful case: ratnums */
10754  } else if (C_block_header(n) == C_RATNUM_TAG) {
10755    /* This tries to keep the numbers within representable ranges and
10756     * tries to drop as few significant digits as possible by bringing
10757     * the two numbers to within the same powers of two.  See
10758     * algorithms M & N in Knuth, 4.2.1.
10759     */
10760     C_word num = C_u_i_ratnum_num(n), denom = C_u_i_ratnum_denom(n),
10761             /* e = approx. distance between the numbers in powers of 2.
10762              * ie, 2^e-1 < n/d < 2^e+1 (e is the *un*biased value of
10763              * e_w in M2.  TODO: What if b!=2 (ie, flonum-radix isn't 2)?
10764              */
10765             e = integer_length_abs(num) - integer_length_abs(denom),
10766             ab[C_SIZEOF_FIX_BIGNUM*5+C_SIZEOF_FLONUM], *a = ab, tmp, q, r, len,
10767             shift_amount, negp = C_i_integer_negativep(num);
10768     C_uword *d;
10769     double res, fraction;
10770
10771     /* Align by shifting the smaller to the size of the larger */
10772     if (e < 0)      num = C_s_a_i_arithmetic_shift(&a, 2, num, C_fix(-e));
10773     else if (e > 0) denom = C_s_a_i_arithmetic_shift(&a, 2, denom, C_fix(e));
10774
10775     /* Here, 1/2 <= n/d < 2 [N3] */
10776     if (C_truep(C_i_integer_lessp(num, denom))) { /* n/d < 1? */
10777       tmp = C_s_a_i_arithmetic_shift(&a, 2, num, C_fix(1));
10778       clear_buffer_object(ab, num); /* "knows" shift creates fresh numbers */
10779       num = tmp;
10780       e--;
10781     }
10782
10783     /* Here, 1 <= n/d < 2 (normalized) [N5] */
10784     shift_amount = nmin(DBL_MANT_DIG-1, e - (DBL_MIN_EXP - DBL_MANT_DIG));
10785
10786     tmp = C_s_a_i_arithmetic_shift(&a, 2, num, C_fix(shift_amount));
10787     clear_buffer_object(ab, num); /* "knows" shift creates fresh numbers */
10788     num = tmp;
10789
10790     /* Now, calculate round(num/denom).  We start with a quotient&remainder */
10791     integer_divrem(&a, num, denom, &q, &r);
10792
10793     /* We multiply the remainder by two to simulate adding 1/2 for
10794      * round.  However, we don't do it if num = denom (q=1,r=0) */
10795     if (!((q == C_fix(1) || q == C_fix(-1)) && r == C_fix(0))) {
10796       tmp = C_s_a_i_arithmetic_shift(&a, 2, r, C_fix(1));
10797       clear_buffer_object(ab, r); /* "knows" shift creates fresh numbers */
10798       r = tmp;
10799     }
10800
10801     /* Now q is the quotient, but to "round" result we need to
10802      * adjust.  This follows the semantics of the "round" procedure:
10803      * Round away from zero on positive numbers (ignoring sign).  In
10804      * case of exactly halfway, we round up if odd.
10805      */
10806     tmp = C_a_i_exact_to_inexact(&a, 1, q);
10807     fraction = fabs(C_flonum_magnitude(tmp));
10808     switch (basic_cmp(r, denom, "", 0)) {
10809     case C_fix(0):
10810       if (C_truep(C_i_oddp(q))) fraction += 1.0;
10811       break;
10812     case C_fix(1):
10813       fraction += 1.0;
10814       break;
10815     default: /* if r <= denom, we're done */ break;
10816     }
10817
10818     clear_buffer_object(ab, num);
10819     clear_buffer_object(ab, denom);
10820     clear_buffer_object(ab, q);
10821     clear_buffer_object(ab, r);
10822
10823     shift_amount = nmin(DBL_MANT_DIG-1, e - (DBL_MIN_EXP - DBL_MANT_DIG));
10824     res = ldexp(fraction, e - shift_amount);
10825     return C_flonum(ptr, C_truep(negp) ? -res : res);
10826  } else {
10827    barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, "exact->inexact", n);
10828  }
10829}
10830
10831
10832/* this is different from C_a_i_flonum_round, for R5RS compatibility */
10833C_regparm C_word C_a_i_flonum_round_proper(C_word **ptr, int c, C_word n)
10834{
10835  double fn, i, f, i2, r;
10836
10837  fn = C_flonum_magnitude(n);
10838  if(fn < 0.0) {
10839    f = modf(-fn, &i);
10840    if(f < 0.5 || (f == 0.5 && modf(i * 0.5, &i2) == 0.0))
10841      r = -i;
10842    else
10843      r = -(i + 1.0);
10844  }
10845  else if(fn == 0.0/* || fn == -0.0*/)
10846    r = fn;
10847  else {
10848    f = modf(fn, &i);
10849    if(f < 0.5 || (f == 0.5 && modf(i * 0.5, &i2) == 0.0))
10850      r = i;
10851    else
10852      r = i + 1.0;
10853  }
10854
10855  return C_flonum(ptr, r);
10856}
10857
10858C_regparm C_word
10859C_a_i_flonum_gcd(C_word **p, C_word n, C_word x, C_word y)
10860{
10861   double xub, yub, r;
10862
10863   if (!C_truep(C_u_i_fpintegerp(x)))
10864     barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "gcd", x);
10865   if (!C_truep(C_u_i_fpintegerp(y)))
10866     barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "gcd", y);
10867
10868   xub = C_flonum_magnitude(x);
10869   yub = C_flonum_magnitude(y);
10870
10871   if (xub < 0.0) xub = -xub;
10872   if (yub < 0.0) yub = -yub;
10873
10874   while(yub != 0.0) {
10875     r = fmod(xub, yub);
10876     xub = yub;
10877     yub = r;
10878   }
10879   return C_flonum(p, xub);
10880}
10881
10882/* This is Lehmer's GCD algorithm with Jebelean's quotient test, as
10883 * it is presented in the paper "An Analysis of Lehmer’s Euclidean
10884 * GCD Algorithm", by J. Sorenson.  Fuck the ACM and their goddamn
10885 * paywall; you can currently find the paper here:
10886 * http://www.csie.nuk.edu.tw/~cychen/gcd/An%20analysis%20of%20Lehmer%27s%20Euclidean%20GCD%20algorithm.pdf
10887 * If that URI fails, it's also explained in [MpNT, 5.2]
10888 *
10889 * The basic idea is to avoid divisions which yield only small
10890 * quotients, in which the remainder won't reduce the numbers by
10891 * much.  This can be detected by dividing only the leading k bits.
10892 * In our case, k = C_WORD_SIZE - 2.
10893 */
10894inline static void lehmer_gcd(C_word **ptr, C_word u, C_word v, C_word *x, C_word *y)
10895{
10896  int i_even = 1, done = 0;
10897  C_word shift_amount = integer_length_abs(u) - (C_WORD_SIZE - 2),
10898         ab[C_SIZEOF_BIGNUM(2)*2+C_SIZEOF_FIX_BIGNUM*2], *a = ab,
10899         uhat, vhat, qhat, xnext, ynext,
10900         xprev = 1, yprev = 0, xcurr = 0, ycurr = 1;
10901
10902  uhat = C_s_a_i_arithmetic_shift(&a, 2, u, C_fix(-shift_amount));
10903  vhat = C_s_a_i_arithmetic_shift(&a, 2, v, C_fix(-shift_amount));
10904  assert(uhat & C_FIXNUM_BIT); uhat = C_unfix(uhat);
10905  assert(vhat & C_FIXNUM_BIT); vhat = C_unfix(vhat);
10906
10907  do {
10908    qhat = uhat / vhat;         /* Estimated quotient for this step */
10909    xnext = xprev - qhat * xcurr;
10910    ynext = yprev - qhat * ycurr;
10911
10912    /* Euclidean GCD swap on uhat and vhat (shift_amount is not needed): */
10913    shift_amount = vhat;
10914    vhat = uhat - qhat * vhat;
10915    uhat = shift_amount;
10916
10917    i_even = !i_even;
10918    if (i_even)
10919      done = (vhat < -xnext) || ((uhat - vhat) < (ynext - ycurr));
10920    else
10921      done = (vhat < -ynext) || ((uhat - vhat) < (xnext - xcurr));
10922
10923    if (!done) {
10924      xprev = xcurr; yprev = ycurr;
10925      xcurr = xnext; ycurr = ynext;
10926    }
10927  } while (!done);
10928
10929  /* x = xprev * u + yprev * v */
10930  uhat = C_s_a_u_i_integer_times(&a, 2, C_fix(xprev), u);
10931  vhat = C_s_a_u_i_integer_times(&a, 2, C_fix(yprev), v);
10932  *x = C_s_a_u_i_integer_plus(ptr, 2, uhat, vhat);
10933  *x = move_buffer_object(ptr, ab, *x);
10934  clear_buffer_object(ab, uhat);
10935  clear_buffer_object(ab, vhat);
10936
10937  /* y = xcurr * u + ycurr * v */
10938  uhat = C_s_a_u_i_integer_times(&a, 2, C_fix(xcurr), u);
10939  vhat = C_s_a_u_i_integer_times(&a, 2, C_fix(ycurr), v);
10940  *y = C_s_a_u_i_integer_plus(ptr, 2, uhat, vhat);
10941  *y = move_buffer_object(ptr, ab, *y);
10942  clear_buffer_object(ab, uhat);
10943  clear_buffer_object(ab, vhat);
10944}
10945
10946/* Because this must be inlineable (due to + and - using this for
10947 * ratnums), we can't use burnikel-ziegler division here, until we
10948 * have a C implementation that doesn't consume stack.  However,
10949 * we *can* use Lehmer's GCD.
10950 */
10951C_regparm C_word
10952C_s_a_u_i_integer_gcd(C_word **ptr, C_word n, C_word x, C_word y)
10953{
10954   C_word ab[2][C_SIZEOF_BIGNUM(2) * 2], *a, newx, newy, size, i = 0;
10955
10956   if (x & C_FIXNUM_BIT && y & C_FIXNUM_BIT) return C_i_fixnum_gcd(x, y);
10957
10958   a = ab[i++];
10959   x = C_s_a_u_i_integer_abs(&a, 1, x);
10960   y = C_s_a_u_i_integer_abs(&a, 1, y);
10961
10962   if (!C_truep(C_i_integer_greaterp(x, y))) {
10963     newx = y; y = x; x = newx; /* Ensure loop invariant: abs(x) >= abs(y) */
10964   }
10965
10966   while(y != C_fix(0)) {
10967     assert(integer_length_abs(x) >= integer_length_abs(y));
10968     /* x and y are stored in the same buffer, as well as a result */
10969     a = ab[i++];
10970     if (i == 2) i = 0;
10971
10972     if (x & C_FIXNUM_BIT) return C_i_fixnum_gcd(x, y);
10973
10974     /* First, see if we should run a Lehmer step */
10975     if ((integer_length_abs(x) - integer_length_abs(y)) < C_HALF_WORD_SIZE) {
10976       lehmer_gcd(&a, x, y, &newx, &newy);
10977       newx = move_buffer_object(&a, ab[i], newx);
10978       newy = move_buffer_object(&a, ab[i], newy);
10979       clear_buffer_object(ab[i], x);
10980       clear_buffer_object(ab[i], y);
10981       x = newx;
10982       y = newy;
10983       a = ab[i++]; /* Ensure x and y get cleared correctly below */
10984       if (i == 2) i = 0;
10985     }
10986
10987     newy = C_s_a_u_i_integer_remainder(&a, 2, x, y);
10988     newy = move_buffer_object(&a, ab[i], newy);
10989     newx = move_buffer_object(&a, ab[i], y);
10990     clear_buffer_object(ab[i], x);
10991     clear_buffer_object(ab[i], y);
10992     x = newx;
10993     y = newy;
10994   }
10995
10996   newx = C_s_a_u_i_integer_abs(ptr, 1, x);
10997   newx = move_buffer_object(ptr, ab, newx);
10998   clear_buffer_object(ab, x);
10999   clear_buffer_object(ab, y);
11000   return newx;
11001}
11002
11003
11004C_regparm C_word
11005C_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)
11006{
11007  if (start == end) {
11008    return C_SCHEME_FALSE;
11009  } else {
11010    size_t nbits;
11011    char *s = C_c_string(C_block_item(str, 0));
11012    C_word result, size;
11013    end = C_unfix(end);
11014    start = C_unfix(start);
11015    radix = C_unfix(radix);
11016
11017    assert((radix > 1) && C_fitsinbignumhalfdigitp(radix));
11018
11019    nbits = (end - start) * C_ilen(radix - 1);
11020    size = C_BIGNUM_BITS_TO_DIGITS(nbits);
11021    if (size == 1) {
11022      result = C_bignum1(ptr, C_truep(negp), 0);
11023    } else if (size == 2) {
11024      result = C_bignum2(ptr, C_truep(negp), 0, 0);
11025    } else {
11026      size = C_fix(size);
11027      result = C_allocate_scratch_bignum(ptr, size, negp, C_SCHEME_FALSE);
11028    }
11029
11030    return str_to_bignum(result, s + start, s + end, radix);
11031  }
11032}
11033
11034inline static int hex_char_to_digit(int ch)
11035{
11036  if (ch == (int)'#') return 0; /* Hash characters in numbers are mapped to 0 */
11037  else if (ch >= (int)'a') return ch - (int)'a' + 10; /* lower hex */
11038  else if (ch >= (int)'A') return ch - (int)'A' + 10; /* upper hex */
11039  else return ch - (int)'0'; /* decimal (OR INVALID; handled elsewhere) */
11040}
11041
11042/* Write from digit character stream to bignum.  Bignum does not need
11043 * to be initialised.  Returns the bignum, or a fixnum.  Assumes the
11044 * string contains only digits that fit within radix (checked by
11045 * string->number).
11046 */
11047static C_regparm C_word
11048str_to_bignum(C_word bignum, char *str, char *str_end, int radix)
11049{
11050  int radix_shift, str_digit;
11051  C_uword *digits = C_bignum_digits(bignum),
11052          *end_digits = digits + C_bignum_size(bignum), big_digit = 0;
11053
11054  /* Below, we try to save up as much as possible in big_digit, and
11055   * only when it exceeds what we would be able to multiply easily, we
11056   * scale up the bignum and add what we saved up.
11057   */
11058  radix_shift = C_ilen(radix) - 1;
11059  if (((C_uword)1 << radix_shift) == radix) { /* Power of two? */
11060    int n = 0; /* Number of bits read so far into current big digit */
11061
11062    /* Read from least to most significant digit to avoid shifting or scaling */
11063    while (str_end > str) {
11064      str_digit = hex_char_to_digit((int)*--str_end);
11065
11066      big_digit |= (C_uword)str_digit << n;
11067      n += radix_shift;
11068
11069      if (n >= C_BIGNUM_DIGIT_LENGTH) {
11070	n -= C_BIGNUM_DIGIT_LENGTH;
11071	*digits++ = big_digit;
11072	big_digit = str_digit >> (radix_shift - n);
11073      }
11074    }
11075    assert(n < C_BIGNUM_DIGIT_LENGTH);
11076    /* If radix isn't an exact divisor of digit length, write final digit */
11077    if (n > 0) *digits++ = big_digit;
11078    assert(digits == end_digits);
11079  } else {			  /* Not a power of two */
11080    C_uword *last_digit = digits, factor;  /* bignum starts as zero */
11081
11082    do {
11083      factor = radix;
11084      while (str < str_end && C_fitsinbignumhalfdigitp(factor)) {
11085        str_digit = hex_char_to_digit((int)*str++);
11086	factor *= radix;
11087	big_digit = radix * big_digit + str_digit;
11088      }
11089
11090      big_digit = bignum_digits_destructive_scale_up_with_carry(
11091                   digits, last_digit, factor / radix, big_digit);
11092
11093      if (big_digit) {
11094	(*last_digit++) = big_digit; /* Move end */
11095        big_digit = 0;
11096      }
11097    } while (str < str_end);
11098
11099    /* Set remaining digits to zero so bignum_simplify can do its work */
11100    assert(last_digit <= end_digits);
11101    while (last_digit < end_digits) *last_digit++ = 0;
11102  }
11103
11104  return C_bignum_simplify(bignum);
11105}
11106
11107
11108static C_regparm double decode_flonum_literal(C_char *str)
11109{
11110  C_char *eptr;
11111  double flo;
11112  int len = C_strlen(str);
11113
11114  /* We only need to be able to parse what C_flonum_to_string() emits,
11115   * so we avoid too much error checking.
11116   */
11117  if (len == 6) { /* Only perform comparisons when necessary */
11118    if (!C_strcmp(str, "-inf.0")) return -1.0 / 0.0;
11119    if (!C_strcmp(str, "+inf.0")) return 1.0 / 0.0;
11120    if (!C_strcmp(str, "+nan.0")) return 0.0 / 0.0;
11121  }
11122
11123  errno = 0;
11124  flo = C_strtod(str, &eptr);
11125
11126  if((flo == HUGE_VAL && errno != 0) ||
11127     (flo == -HUGE_VAL && errno != 0) ||
11128     (*eptr != '\0' && C_strcmp(eptr, ".0") != 0)) {
11129    panic(C_text("could not decode flonum literal"));
11130  }
11131
11132  return flo;
11133}
11134
11135
11136static char *to_n_nary(C_uword num, C_uword base, int negp, int as_flonum)
11137{
11138  static char *digits = "0123456789abcdef";
11139  char *p;
11140  C_uword shift = C_ilen(base) - 1;
11141  int mask = (1 << shift) - 1;
11142  if (as_flonum) {
11143    buffer[68] = '\0';
11144    buffer[67] = '0';
11145    buffer[66] = '.';
11146  } else {
11147    buffer[66] = '\0';
11148  }
11149  p = buffer + 66;
11150  if (mask == base - 1) {
11151    do {
11152      *(--p) = digits [ num & mask ];
11153      num >>= shift;
11154    } while (num);
11155  } else {
11156    do {
11157      *(--p) = digits [ num % base ];
11158      num /= base;
11159    } while (num);
11160  }
11161  if (negp) *(--p) = '-';
11162  return p;
11163}
11164
11165
11166void C_ccall C_number_to_string(C_word c, C_word *av)
11167{
11168  C_word radix, num;
11169
11170  if(c == 3) {
11171    radix = C_fix(10);
11172  } else if(c == 4) {
11173    radix = av[ 3 ];
11174    if(!(radix & C_FIXNUM_BIT))
11175      barf(C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR, "number->string", radix);
11176  } else {
11177    C_bad_argc(c, 3);
11178  }
11179
11180  num = av[ 2 ];
11181
11182  if(num & C_FIXNUM_BIT) {
11183    C_fixnum_to_string(c, av); /* reuse av */
11184  } else if (C_immediatep(num)) {
11185    barf(C_BAD_ARGUMENT_TYPE_ERROR, "number->string", num);
11186  } else if(C_block_header(num) == C_FLONUM_TAG) {
11187    C_flonum_to_string(c, av); /* reuse av */
11188  } else if (C_truep(C_bignump(num))) {
11189    C_integer_to_string(c, av); /* reuse av */
11190  } else {
11191    C_word k = av[ 1 ];
11192    try_extended_number("##sys#extended-number->string", 3, k, num, radix);
11193  }
11194}
11195
11196void C_ccall C_fixnum_to_string(C_word c, C_word *av)
11197{
11198  C_char *p;
11199  C_word *a,
11200    /* self = av[ 0 ] */
11201    k = av[ 1 ],
11202    num = av[ 2 ],
11203    radix = ((c == 3) ? 10 : C_unfix(av[ 3 ])),
11204    neg = ((num & C_INT_SIGN_BIT) ? 1 : 0);
11205
11206  if (radix < 2 || radix > 16) {
11207    barf(C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR, "number->string", C_fix(radix));
11208  }
11209
11210  num = neg ? -C_unfix(num) : C_unfix(num);
11211  p = to_n_nary(num, radix, neg, 0);
11212
11213  num = C_strlen(p);
11214  a = C_alloc(C_SIZEOF_STRING(num));
11215  C_kontinue(k, C_string(&a, num, p));
11216}
11217
11218void C_ccall C_flonum_to_string(C_word c, C_word *av)
11219{
11220  C_char *p;
11221  double f, fa, m;
11222  C_word *a,
11223    /* self = av[ 0 ] */
11224    k = av[ 1 ],
11225    num = av[ 2 ],
11226    radix = ((c == 3) ? 10 : C_unfix(av[ 3 ]));
11227
11228  f = C_flonum_magnitude(num);
11229  fa = fabs(f);
11230
11231  /* XXX TODO: Should inexacts be printable in other bases than 10?
11232   * Perhaps output a string starting with #i?
11233   * Right now something like (number->string 1e40 16) results in
11234   * a string that can't be read back using string->number.
11235   */
11236  if((radix < 2) || (radix > 16)){
11237    barf(C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR, "number->string", C_fix(radix));
11238  }
11239
11240  if(f == 0.0 || (C_modf(f, &m) == 0.0 && log2(fa) < C_WORD_SIZE)) { /* Use fast int code */
11241    if(signbit(f)) {
11242      p = to_n_nary((C_uword)-f, radix, 1, 1);
11243    } else {
11244      p = to_n_nary((C_uword)f, radix, 0, 1);
11245    }
11246  } else if(C_isnan(f)) {
11247    p = "+nan.0";
11248  } else if(C_isinf(f)) {
11249    p = f > 0 ? "+inf.0" : "-inf.0";
11250  } else { /* Doesn't fit an unsigned int and not "special"; use system libc */
11251    C_snprintf(buffer, STRING_BUFFER_SIZE, C_text("%.*g"),
11252               /* XXX: flonum_print_precision */
11253               (int)C_unfix(C_get_print_precision()), f);
11254    buffer[STRING_BUFFER_SIZE-1] = '\0';
11255
11256    if((p = C_strpbrk(buffer, C_text(".eE"))) == NULL) {
11257      /* Already checked for these, so shouldn't happen */
11258      assert(*buffer != 'i'); /* "inf" */
11259      assert(*buffer != 'n'); /* "nan" */
11260      /* Ensure integral flonums w/o expt are always terminated by .0 */
11261#if defined(HAVE_STRLCAT) || !defined(C_strcat)
11262      C_strlcat(buffer, C_text(".0"), sizeof(buffer));
11263#else
11264      C_strcat(buffer, C_text(".0"));
11265#endif
11266    }
11267    p = buffer;
11268  }
11269
11270  radix = C_strlen(p);
11271  a = C_alloc(C_SIZEOF_STRING(radix));
11272  radix = C_string(&a, radix, p);
11273  C_kontinue(k, radix);
11274}
11275
11276void C_ccall C_integer_to_string(C_word c, C_word *av)
11277{
11278  C_word
11279    /* self = av[ 0 ] */
11280    k = av[ 1 ],
11281    num = av[ 2 ],
11282    radix = ((c == 3) ? 10 : C_unfix(av[ 3 ]));
11283
11284  if (num & C_FIXNUM_BIT) {
11285    C_fixnum_to_string(4, av); /* reuse av */
11286  } else {
11287    int len, radix_shift;
11288    size_t nbits;
11289
11290    if ((radix < 2) || (radix > 16)) {
11291      barf(C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR, "number->string", C_fix(radix));
11292    }
11293
11294    /* Approximation of the number of radix digits we'll need.  We try
11295     * to be as precise as possible to avoid memmove overhead at the end
11296     * of the non-powers of two part of the conversion procedure, which
11297     * we may need to do because we write strings back-to-front, and
11298     * pointers must be aligned (even for byte blocks).
11299     */
11300    len = C_bignum_size(num)-1;
11301
11302    nbits  = (size_t)len * C_BIGNUM_DIGIT_LENGTH;
11303    nbits += C_ilen(C_bignum_digits(num)[len]);
11304
11305    len = C_ilen(radix)-1;
11306    len = (nbits + len - 1) / len;
11307    len += C_bignum_negativep(num) ? 1 : 0; /* Add space for negative sign */
11308
11309    radix_shift = C_ilen(radix) - 1;
11310    if (len > C_RECURSIVE_TO_STRING_THRESHOLD &&
11311        /* The power of two fast path is much faster than recursion */
11312        ((C_uword)1 << radix_shift) != radix) {
11313      try_extended_number("##sys#integer->string/recursive",
11314                          4, k, num, C_fix(radix), C_fix(len));
11315    } else {
11316      C_word kab[C_SIZEOF_CLOSURE(4)], *ka = kab, kav[4];
11317
11318      kav[ 0 ] = (C_word)NULL;   /* No "self" closure */
11319      kav[ 1 ] = C_closure(&ka, 4, (C_word)bignum_to_str_2,
11320                           k, num, C_fix(radix));
11321      kav[ 2 ] = C_fix(len + 1);
11322      kav[ 3 ] = C_SCHEME_FALSE; /* No initialization */
11323      C_allocate_bytevector(4, kav);
11324    }
11325  }
11326}
11327
11328static void bignum_to_str_2(C_word c, C_word *av)
11329{
11330  static char *characters = "0123456789abcdef";
11331  C_word
11332    self = av[ 0 ],
11333    string = av[ 1 ],
11334    k = C_block_item(self, 1),
11335    bignum = C_block_item(self, 2),
11336    radix = C_unfix(C_block_item(self, 3));
11337  char
11338    *buf = C_c_string(string),
11339    *index = buf + C_header_size(string) - 2;
11340  int radix_shift,
11341    negp = (C_bignum_negativep(bignum) ? 1 : 0);
11342  C_word us[ 5 ], *a = us;
11343
11344  *(index + 1) = '\0';
11345  radix_shift = C_ilen(radix) - 1;
11346  if (((C_uword)1 << radix_shift) == radix) { /* Power of two? */
11347    int radix_mask = radix - 1, big_digit_len = 0, radix_digit;
11348    C_uword *scan, *end, big_digit = 0;
11349
11350    scan = C_bignum_digits(bignum);
11351    end = scan + C_bignum_size(bignum);
11352
11353    while (scan < end) {
11354      /* If radix isn't an exact divisor of digit length, handle overlap */
11355      if (big_digit_len == 0) {
11356        big_digit = *scan++;
11357        big_digit_len = C_BIGNUM_DIGIT_LENGTH;
11358      } else {
11359        assert(index >= buf);
11360	radix_digit = big_digit;
11361        big_digit = *scan++;
11362	radix_digit |= ((unsigned int)big_digit << big_digit_len) & radix_mask;
11363        *index-- = characters[radix_digit];
11364	big_digit >>= (radix_shift - big_digit_len);
11365        big_digit_len = C_BIGNUM_DIGIT_LENGTH - (radix_shift - big_digit_len);
11366      }
11367
11368      while(big_digit_len >= radix_shift && index >= buf) {
11369	radix_digit = big_digit & radix_mask;
11370        *index-- = characters[radix_digit];
11371	big_digit >>= radix_shift;
11372	big_digit_len -= radix_shift;
11373      }
11374    }
11375
11376    assert(big_digit < radix);
11377
11378    /* Final digit (like overlap at start of while loop) */
11379    if (big_digit) *index-- = characters[big_digit];
11380
11381    if (negp) {
11382      /* Loop above might've overwritten sign position with a zero */
11383      if (*(index+1) == '0') *(index+1) = '-';
11384      else *index-- = '-';
11385    }
11386
11387    /* Length calculation is always precise for radix powers of two. */
11388    assert(index == buf-1);
11389  } else {
11390    C_uword base, *start, *scan, big_digit;
11391    C_word working_copy;
11392    int steps, i;
11393
11394    working_copy = allocate_tmp_bignum(C_fix(C_bignum_size(bignum)),
11395                                       C_mk_bool(negp), C_SCHEME_FALSE);
11396    bignum_digits_destructive_copy(working_copy, bignum);
11397
11398    start = C_bignum_digits(working_copy);
11399
11400    scan = start + C_bignum_size(bignum);
11401    /* Calculate the largest power of radix that fits a halfdigit:
11402     * steps = log10(2^halfdigit_bits), base = 10^steps
11403     */
11404    for(steps = 0, base = radix; C_fitsinbignumhalfdigitp(base); base *= radix)
11405      steps++;
11406
11407    base /= radix; /* Back down: we overshot in the loop */
11408
11409    while (scan > start) {
11410      big_digit = bignum_digits_destructive_scale_down(start, scan, base);
11411
11412      if (*(scan-1) == 0) scan--; /* Adjust if we exhausted the highest digit */
11413
11414      for(i = 0; i < steps && index >= buf; ++i) {
11415	C_word tmp = big_digit / radix;
11416        *index-- = characters[big_digit - (tmp*radix)]; /* big_digit % radix */
11417        big_digit = tmp;
11418      }
11419    }
11420    assert(index >= buf-1);
11421    free_tmp_bignum(working_copy);
11422
11423    /* Move index onto first nonzero digit.  We're writing a bignum
11424       here: it can't consist of only zeroes. */
11425    while(*++index == '0');
11426
11427    if (negp) *--index = '-';
11428
11429    /* Shorten with distance between start and index. */
11430    if (buf != index) {
11431      i = C_header_size(string) - (index - buf);
11432      C_memmove(buf, index, i); /* Move start of number to beginning. */
11433      buf[ i ] = '\0'; /* terminating 0 */
11434      C_block_header(string) = C_BYTEVECTOR_TYPE | i; /* Mutate strlength. */
11435    }
11436  }
11437
11438  C_kontinue(k, C_a_ustring(&a, 0, string, C_fix(C_header_size(string) - 1)));
11439}
11440
11441
11442/* XXX replace with inline routine */
11443void C_ccall C_make_structure(C_word c, C_word *av)
11444{
11445  C_word
11446    /* closure = av[ 0 ] */
11447    k = av[ 1 ],
11448    type = av[ 2 ],
11449    size = c - 3,
11450    *s, s0;
11451
11452  if(!C_demand(size + 2))
11453    C_save_and_reclaim((void *)C_make_structure, c, av);
11454
11455  s = C_alloc(C_SIZEOF_STRUCTURE(size + 1)),
11456  s0 = (C_word)s;
11457  *(s++) = C_STRUCTURE_TYPE | (size + 1);
11458  *(s++) = type;
11459  av += 3;
11460
11461  while(size--)
11462    *(s++) = *(av++);
11463
11464  C_kontinue(k, s0);
11465}
11466
11467
11468/* XXX replace with inline routine */
11469void C_ccall C_make_symbol(C_word c, C_word *av)
11470{
11471  C_word
11472    /* closure = av[ 0 ] */
11473    k = av[ 1 ],
11474    name = av[ 2 ],
11475    ab[ C_SIZEOF_SYMBOL ],
11476    *a = ab,
11477    s0 = (C_word)a;
11478
11479  *(a++) = C_SYMBOL_TYPE | (C_SIZEOF_SYMBOL - 1);
11480  *(a++) = C_SCHEME_UNBOUND;
11481  *(a++) = name;
11482  *a = C_SCHEME_END_OF_LIST;
11483  C_kontinue(k, s0);
11484}
11485
11486
11487/* XXX replace with inline routine */
11488void C_ccall C_make_pointer(C_word c, C_word *av)
11489{
11490  C_word
11491    /* closure = av[ 0 ] */
11492    k = av[ 1 ],
11493    ab[ 2 ],
11494    *a = ab,
11495    p;
11496
11497  p = C_mpointer(&a, NULL);
11498  C_kontinue(k, p);
11499}
11500
11501
11502/* XXX replace with inline routine */
11503void C_ccall C_make_tagged_pointer(C_word c, C_word *av)
11504{
11505  C_word
11506    /* closure = av[ 0 ] */
11507    k = av[ 1 ],
11508    tag = av[ 2 ],
11509    ab[ 3 ],
11510    *a = ab,
11511    p;
11512
11513  p = C_taggedmpointer(&a, tag, NULL);
11514  C_kontinue(k, p);
11515}
11516
11517
11518void C_ccall C_ensure_heap_reserve(C_word c, C_word *av)
11519{
11520  C_word
11521    /* closure = av[ 0 ] */
11522    k = av[ 1 ],
11523    n = av[ 2 ],
11524    *p;
11525
11526  C_save(k);
11527
11528  if(!C_demand(C_bytestowords(C_unfix(n))))
11529    C_reclaim((void *)generic_trampoline, 1);
11530
11531  p = C_temporary_stack;
11532  C_temporary_stack = C_temporary_stack_bottom;
11533  generic_trampoline(0, p);
11534}
11535
11536
11537void C_ccall generic_trampoline(C_word c, C_word *av)
11538{
11539  C_word k = av[ 0 ];
11540
11541  C_kontinue(k, C_SCHEME_UNDEFINED);
11542}
11543
11544
11545void C_ccall C_return_to_host(C_word c, C_word *av)
11546{
11547  C_word
11548    /* closure = av[ 0 ] */
11549    k = av[ 1 ];
11550
11551  return_to_host = 1;
11552  C_save(k);
11553  C_reclaim((void *)generic_trampoline, 1);
11554}
11555
11556
11557void C_ccall C_get_symbol_table_info(C_word c, C_word *av)
11558{
11559  C_word
11560    /* closure = av[ 0 ] */
11561    k = av[ 1 ];
11562  double d1, d2;
11563  int n = 0, total;
11564  C_SYMBOL_TABLE *stp;
11565  C_word
11566    x, y,
11567    ab[ WORDS_PER_FLONUM * 2 + C_SIZEOF_VECTOR(4) ],
11568    *a = ab;
11569
11570  for(stp = symbol_table_list; stp != NULL; stp = stp->next)
11571    ++n;
11572
11573  d1 = compute_symbol_table_load(&d2, &total);
11574  x = C_flonum(&a, d1);		/* load */
11575  y = C_flonum(&a, d2);		/* avg bucket length */
11576  C_kontinue(k, C_vector(&a, 4, x, y, C_fix(total), C_fix(n)));
11577}
11578
11579
11580void C_ccall C_get_memory_info(C_word c, C_word *av)
11581{
11582  C_word
11583    /* closure = av[ 0 ] */
11584    k = av[ 1 ],
11585    ab[ C_SIZEOF_VECTOR(2) ],
11586    *a = ab;
11587
11588  C_kontinue(k, C_vector(&a, 2, C_fix(heap_size), C_fix(stack_size)));
11589}
11590
11591
11592void C_ccall C_context_switch(C_word c, C_word *av)
11593{
11594  C_word
11595    /* closure = av[ 0 ] */
11596    state = av[ 2 ],
11597    n = C_header_size(state) - 1,
11598    adrs = C_block_item(state, 0),
11599    *av2;
11600  C_proc tp = (C_proc)C_block_item(adrs,0);
11601
11602  /* Copy argvector because it may be mutated in-place.  The state
11603   * vector should not be re-invoked(?), but it can be kept alive
11604   * during GC, so the mutated argvector/state slots may turn stale.
11605   */
11606  av2 = C_alloc(n);
11607  C_memcpy(av2, (C_word *)state + 2, n * sizeof(C_word));
11608  tp(n, av2);
11609}
11610
11611
11612void C_ccall C_peek_signed_integer(C_word c, C_word *av)
11613{
11614  C_word
11615    /* closure = av[ 0 ] */
11616    k = av[ 1 ],
11617    v = av[ 2 ],
11618    index = av[ 3 ],
11619    x = C_block_item(v, C_unfix(index)),
11620    ab[C_SIZEOF_BIGNUM(1)], *a = ab;
11621
11622  C_uword num = ((C_word *)C_data_pointer(v))[ C_unfix(index) ];
11623
11624  C_kontinue(k, C_int_to_num(&a, num));
11625}
11626
11627
11628void C_ccall C_peek_unsigned_integer(C_word c, C_word *av)
11629{
11630  C_word
11631    /* closure = av[ 0 ] */
11632    k = av[ 1 ],
11633    v = av[ 2 ],
11634    index = av[ 3 ],
11635    x = C_block_item(v, C_unfix(index)),
11636    ab[C_SIZEOF_BIGNUM(1)], *a = ab;
11637
11638  C_uword num = ((C_word *)C_data_pointer(v))[ C_unfix(index) ];
11639
11640  C_kontinue(k, C_unsigned_int_to_num(&a, num));
11641}
11642
11643void C_ccall C_peek_int64(C_word c, C_word *av)
11644{
11645  C_word
11646    /* closure = av[ 0 ] */
11647    k = av[ 1 ],
11648    v = av[ 2 ],
11649    index = av[ 3 ],
11650    x = C_block_item(v, C_unfix(index)),
11651    ab[C_SIZEOF_BIGNUM(2)], *a = ab;
11652
11653  C_s64 num = ((C_s64 *)C_data_pointer(v))[ C_unfix(index) ];
11654
11655  C_kontinue(k, C_int64_to_num(&a, num));
11656}
11657
11658
11659void C_ccall C_peek_uint64(C_word c, C_word *av)
11660{
11661  C_word
11662    /* closure = av[ 0 ] */
11663    k = av[ 1 ],
11664    v = av[ 2 ],
11665    index = av[ 3 ],
11666    x = C_block_item(v, C_unfix(index)),
11667    ab[C_SIZEOF_BIGNUM(2)], *a = ab;
11668
11669  C_u64 num = ((C_u64 *)C_data_pointer(v))[ C_unfix(index) ];
11670
11671  C_kontinue(k, C_uint64_to_num(&a, num));
11672}
11673
11674
11675void C_ccall C_decode_seconds(C_word c, C_word *av)
11676{
11677  C_word
11678    /* closure = av[ 0 ] */
11679    k = av[ 1 ],
11680    secs = av[ 2 ],
11681    mode = av[ 3 ];
11682  time_t tsecs;
11683  struct tm *tmt;
11684  C_word
11685    ab[ C_SIZEOF_VECTOR(10) ],
11686    *a = ab,
11687    info;
11688
11689  tsecs = (time_t)C_num_to_int64(secs);
11690
11691  if(mode == C_SCHEME_FALSE) tmt = C_localtime(&tsecs);
11692  else tmt = C_gmtime(&tsecs);
11693
11694  if(tmt  == NULL)
11695    C_kontinue(k, C_SCHEME_FALSE);
11696
11697  info = C_vector(&a, 10, C_fix(tmt->tm_sec), C_fix(tmt->tm_min), C_fix(tmt->tm_hour),
11698		  C_fix(tmt->tm_mday), C_fix(tmt->tm_mon), C_fix(tmt->tm_year),
11699		  C_fix(tmt->tm_wday), C_fix(tmt->tm_yday),
11700		  tmt->tm_isdst > 0 ? C_SCHEME_TRUE : C_SCHEME_FALSE,
11701#ifdef C_GNU_ENV
11702                  /* negative for west of UTC, but we want positive */
11703		  C_fix(-tmt->tm_gmtoff)
11704#elif defined(__CYGWIN__) || defined(__MINGW32__) || defined(_WIN32) || defined(__WINNT__)
11705                  C_fix(mode == C_SCHEME_FALSE ? _timezone : 0) /* does not account for DST */
11706#else
11707                  C_fix(mode == C_SCHEME_FALSE ? timezone : 0)  /* does not account for DST */
11708#endif
11709		  );
11710  C_kontinue(k, info);
11711}
11712
11713
11714void C_ccall C_machine_byte_order(C_word c, C_word *av)
11715{
11716  C_word
11717    /* closure = av[ 0 ] */
11718    k = av[ 1 ];
11719  char *str;
11720  C_word *a, s;
11721
11722  if(c != 2) C_bad_argc(c, 2);
11723
11724#if defined(C_MACHINE_BYTE_ORDER)
11725  str = C_MACHINE_BYTE_ORDER;
11726#else
11727  C_cblock
11728    static C_word one_two_three = 123;
11729    str = (*((C_char *)&one_two_three) != 123) ? "big-endian" : "little-endian";
11730  C_cblockend;
11731#endif
11732
11733  a = C_alloc(C_SIZEOF_STRING(strlen(str)));
11734  s = C_string2(&a, str);
11735
11736  C_kontinue(k, s);
11737}
11738
11739
11740void C_ccall C_machine_type(C_word c, C_word *av)
11741{
11742  C_word
11743    /* closure = av[ 0 ] */
11744    k = av[ 1 ],
11745    *a, s;
11746
11747  if(c != 2) C_bad_argc(c, 2);
11748
11749  a = C_alloc(C_SIZEOF_STRING(C_strlen(C_MACHINE_TYPE)));
11750  s = C_string2(&a, C_MACHINE_TYPE);
11751
11752  C_kontinue(k, s);
11753}
11754
11755
11756void C_ccall C_software_type(C_word c, C_word *av)
11757{
11758  C_word
11759    /* closure = av[ 0 ] */
11760    k = av[ 1 ],
11761    *a, s;
11762
11763  if(c != 2) C_bad_argc(c, 2);
11764
11765  a = C_alloc(C_SIZEOF_STRING(C_strlen(C_SOFTWARE_TYPE)));
11766  s = C_string2(&a, C_SOFTWARE_TYPE);
11767
11768 C_kontinue(k, s);
11769}
11770
11771
11772void C_ccall C_build_platform(C_word c, C_word *av)
11773{
11774  C_word
11775    /* closure = av[ 0 ] */
11776    k = av[ 1 ],
11777    *a, s;
11778
11779  if(c != 2) C_bad_argc(c, 2);
11780
11781  a = C_alloc(C_SIZEOF_STRING(C_strlen(C_BUILD_PLATFORM)));
11782  s = C_string2(&a, C_BUILD_PLATFORM);
11783
11784 C_kontinue(k, s);
11785}
11786
11787
11788void C_ccall C_software_version(C_word c, C_word *av)
11789{
11790  C_word
11791    /* closure = av[ 0 ] */
11792    k = av[ 1 ],
11793    *a, s;
11794
11795  if(c != 2) C_bad_argc(c, 2);
11796
11797  a = C_alloc(C_SIZEOF_STRING(C_strlen(C_SOFTWARE_VERSION)));
11798  s = C_string2(&a, C_SOFTWARE_VERSION);
11799
11800 C_kontinue(k, s);
11801}
11802
11803
11804/* Register finalizer: */
11805
11806void C_ccall C_register_finalizer(C_word c, C_word *av)
11807{
11808  C_word
11809    /* closure = av[ 0 ]) */
11810    k = av[ 1 ],
11811    x = av[ 2 ],
11812    proc = av[ 3 ];
11813
11814  if(C_immediatep(x) ||
11815     (!C_in_stackp(x) && !C_in_heapp(x) && !C_in_scratchspacep(x)))
11816    C_kontinue(k, x); /* not GCable */
11817
11818  C_do_register_finalizer(x, proc);
11819  C_kontinue(k, x);
11820}
11821
11822
11823/*XXX could this be made static? is it used in eggs somewhere?
11824  if not, declare as fcall/regparm (and static, remove from chicken.h)
11825 */
11826void C_ccall C_do_register_finalizer(C_word x, C_word proc)
11827{
11828  C_word *ptr;
11829  int n, i;
11830  FINALIZER_NODE *flist;
11831
11832  if(finalizer_free_list == NULL) {
11833    if((flist = (FINALIZER_NODE *)C_malloc(sizeof(FINALIZER_NODE))) == NULL)
11834      panic(C_text("out of memory - cannot allocate finalizer node"));
11835
11836    ++allocated_finalizer_count;
11837  }
11838  else {
11839    flist = finalizer_free_list;
11840    finalizer_free_list = flist->next;
11841  }
11842
11843  if(finalizer_list != NULL) finalizer_list->previous = flist;
11844
11845  flist->previous = NULL;
11846  flist->next = finalizer_list;
11847  finalizer_list = flist;
11848
11849  if(C_in_stackp(x)) C_mutate_slot(&flist->item, x);
11850  else flist->item = x;
11851
11852  if(C_in_stackp(proc)) C_mutate_slot(&flist->finalizer, proc);
11853  else flist->finalizer = proc;
11854
11855  ++live_finalizer_count;
11856}
11857
11858
11859/*XXX same here */
11860int C_do_unregister_finalizer(C_word x)
11861{
11862  int n;
11863  FINALIZER_NODE *flist;
11864
11865  for(flist = finalizer_list; flist != NULL; flist = flist->next) {
11866    if(flist->item == x) {
11867      if(flist->previous == NULL) finalizer_list = flist->next;
11868      else flist->previous->next = flist->next;
11869
11870      return 1;
11871    }
11872  }
11873
11874  return 0;
11875}
11876
11877
11878/* Dynamic loading of shared objects: */
11879
11880void C_ccall C_set_dlopen_flags(C_word c, C_word *av)
11881{
11882  C_word
11883    /* closure = av[ 0 ] */
11884    k = av[ 1 ],
11885    now = av[ 2 ],
11886    global = av[ 3 ];
11887
11888#if !defined(NO_DLOAD2) && defined(HAVE_DLFCN_H)
11889  dlopen_flags = (C_truep(now) ? RTLD_NOW : RTLD_LAZY) | (C_truep(global) ? RTLD_GLOBAL : RTLD_LOCAL);
11890#endif
11891  C_kontinue(k, C_SCHEME_UNDEFINED);
11892}
11893
11894
11895void C_ccall C_dload(C_word c, C_word *av)
11896{
11897  C_word
11898    /* closure = av[ 0 ] */
11899    k = av[ 1 ],
11900    name = av[ 2 ],
11901    entry = av[ 3 ];
11902
11903#if !defined(NO_DLOAD2) && (defined(HAVE_DLFCN_H) || defined(HAVE_DL_H) || (defined(HAVE_LOADLIBRARY) && defined(HAVE_GETPROCADDRESS)))
11904  /* Force minor GC: otherwise the lf may contain pointers to stack-data
11905     (stack allocated interned symbols, for example) */
11906  C_save_and_reclaim_args((void *)dload_2, 3, k, name, entry);
11907#endif
11908
11909  C_kontinue(k, C_SCHEME_FALSE);
11910}
11911
11912
11913#ifdef DLOAD_2_DEFINED
11914# undef DLOAD_2_DEFINED
11915#endif
11916
11917#if !defined(NO_DLOAD2) && defined(HAVE_DL_H) && !defined(DLOAD_2_DEFINED)
11918# ifdef __hpux__
11919#  define DLOAD_2_DEFINED
11920void C_ccall dload_2(C_word c, C_word *av0)
11921{
11922  void *handle, *p;
11923  C_word
11924    entry = av0[ 0 ],
11925    name = av0[ 1 ],
11926    k = av0[ 2 ],,
11927    av[ 2 ];
11928  C_char *mname = C_c_string(name);
11929
11930  /*
11931   * C_fprintf(C_stderr,
11932   *   "shl_loading %s : %s\n",
11933   *   (char *) C_c_string(name),
11934   *   (char *) C_c_string(entry));
11935   */
11936
11937  if ((handle = (void *) shl_load(mname,
11938				  BIND_IMMEDIATE | DYNAMIC_PATH,
11939				  0L)) != NULL) {
11940    shl_t shl_handle = (shl_t) handle;
11941
11942    /*** This version does not check for C_dynamic_and_unsafe. Fix it. */
11943    if (shl_findsym(&shl_handle, (char *) C_c_string(entry), TYPE_PROCEDURE, &p) == 0) {
11944      current_module_name = C_strdup(mname);
11945      current_module_handle = handle;
11946
11947      if(debug_mode) {
11948	C_dbg(C_text("debug"), C_text("loading compiled library %s (" UWORD_FORMAT_STRING ")\n"),
11949	      current_module_name, (C_uword)current_module_handle);
11950      }
11951
11952      av[ 0 ] = C_SCHEME_UNDEFINED;
11953      av[ 1 ] = k;
11954      ((C_proc)p)(2, av);       /* doesn't return */
11955    } else {
11956      C_dlerror = (char *) C_strerror(errno);
11957      shl_unload(shl_handle);
11958    }
11959  } else {
11960    C_dlerror = (char *) C_strerror(errno);
11961  }
11962
11963  C_kontinue(k, C_SCHEME_FALSE);
11964}
11965# endif
11966#endif
11967
11968
11969#if !defined(NO_DLOAD2) && defined(HAVE_DLFCN_H) && !defined(DLOAD_2_DEFINED)
11970# ifndef __hpux__
11971#  define DLOAD_2_DEFINED
11972void C_ccall dload_2(C_word c, C_word *av0)
11973{
11974  void *handle, *p, *p2;
11975  C_word
11976    entry = av0[ 0 ],
11977    name = av0[ 1 ],
11978    k = av0[ 2 ],
11979    av[ 2 ];
11980  C_char *topname = (C_char *)C_c_string(entry);
11981  C_char *mname = (C_char *)C_c_string(name);
11982  C_char *tmp;
11983  int tmp_len = 0;
11984
11985  if((handle = C_dlopen(mname, dlopen_flags)) != NULL) {
11986    if((p = C_dlsym(handle, topname)) == NULL) {
11987      tmp_len = C_strlen(topname) + 2;
11988      tmp = (C_char *)C_malloc(tmp_len);
11989
11990      if(tmp == NULL)
11991	panic(C_text("out of memory - cannot allocate toplevel name string"));
11992
11993      C_strlcpy(tmp, C_text("_"), tmp_len);
11994      C_strlcat(tmp, topname, tmp_len);
11995      p = C_dlsym(handle, tmp);
11996      C_free(tmp);
11997    }
11998
11999    if(p != NULL) {
12000      current_module_name = C_strdup(mname);
12001      current_module_handle = handle;
12002
12003      if(debug_mode) {
12004	C_dbg(C_text("debug"), C_text("loading compiled library %s (" UWORD_FORMAT_STRING ")\n"),
12005	      current_module_name, (C_uword)current_module_handle);
12006      }
12007
12008      av[ 0 ] = C_SCHEME_UNDEFINED;
12009      av[ 1 ] = k;
12010      ((C_proc)p)(2, av); /* doesn't return */
12011    }
12012
12013    C_dlclose(handle);
12014  }
12015
12016  C_dlerror = (char *)dlerror();
12017  C_kontinue(k, C_SCHEME_FALSE);
12018}
12019# endif
12020#endif
12021
12022
12023#if !defined(NO_DLOAD2) && (defined(HAVE_LOADLIBRARY) && defined(HAVE_GETPROCADDRESS)) && !defined(DLOAD_2_DEFINED)
12024# define DLOAD_2_DEFINED
12025void C_ccall dload_2(C_word c, C_word *av0)
12026{
12027  HINSTANCE handle;
12028  FARPROC p = NULL, p2;
12029  C_word
12030    entry = av0[ 0 ],
12031    name = av0[ 1 ],
12032    k = av0[ 2 ],
12033    av[ 2 ];
12034  C_char *topname = (C_char *)C_c_string(entry);
12035  C_char *mname = (C_char *)C_c_string(name);
12036
12037  /* cannot use LoadLibrary on non-DLLs, so we use extension checking */
12038  if (C_strlen(mname) >= 5) {
12039    C_char *n = mname;
12040    int l = C_strlen(mname);
12041    if (C_strncmp(".dll", n+l-4, 4) &&
12042        C_strncmp(".DLL", n+l-4, 4) &&
12043        C_strncmp(".so", n+l-3, 3) &&
12044	C_strncmp(".SO", n+l-3, 3))
12045      C_kontinue(k, C_SCHEME_FALSE);
12046  }
12047
12048  if((handle = LoadLibrary(mname)) != NULL) {
12049    if ((p = GetProcAddress(handle, topname)) != NULL) {
12050      current_module_name = C_strdup(mname);
12051      current_module_handle = handle;
12052
12053      if(debug_mode) {
12054	C_dbg(C_text("debug"), C_text("loading compiled library %s (" UWORD_FORMAT_STRING ")\n"),
12055	      current_module_name, (C_uword)current_module_handle);
12056      }
12057
12058      av[ 0 ] = C_SCHEME_UNDEFINED;
12059      av[ 1 ] = k;
12060      ((C_proc)p)(2, av);       /* doesn't return */
12061    }
12062    else FreeLibrary(handle);
12063  }
12064
12065  C_dlerror = (char *) C_strerror(errno);
12066  C_kontinue(k, C_SCHEME_FALSE);
12067}
12068#endif
12069
12070
12071void C_ccall C_become(C_word c, C_word *av)
12072{
12073  C_word
12074    /* closure = av[ 0 ] */
12075    k = av[ 1 ],
12076    table = av[ 2 ],
12077    tp, x, old, neu, i, *p;
12078
12079  i = forwarding_table_size;
12080  p = forwarding_table;
12081
12082  for(tp = table; tp != C_SCHEME_END_OF_LIST; tp = C_u_i_cdr(tp)) {
12083    x = C_u_i_car(tp);
12084    old = C_u_i_car(x);
12085    neu = C_u_i_cdr(x);
12086
12087    if(i == 0) {
12088      if((forwarding_table = (C_word *)realloc(forwarding_table, (forwarding_table_size + 1) * 4 * sizeof(C_word))) == NULL)
12089	panic(C_text("out of memory - cannot re-allocate forwarding table"));
12090
12091      i = forwarding_table_size;
12092      p = forwarding_table + forwarding_table_size * 2;
12093      forwarding_table_size *= 2;
12094    }
12095
12096    *(p++) = old;
12097    *(p++) = neu;
12098    --i;
12099  }
12100
12101  *p = 0;
12102  C_fromspace_top = C_fromspace_limit;
12103  C_save_and_reclaim_args((void *)become_2, 1, k);
12104}
12105
12106
12107void C_ccall become_2(C_word c, C_word *av)
12108{
12109  C_word k = av[ 0 ];
12110
12111  *forwarding_table = 0;
12112  C_kontinue(k, C_SCHEME_UNDEFINED);
12113}
12114
12115
12116C_regparm C_word
12117C_a_i_cpu_time(C_word **a, int c, C_word buf)
12118{
12119  C_word u, s = C_fix(0);
12120
12121#if defined(C_NONUNIX) || defined(__CYGWIN__)
12122  if(CLOCKS_PER_SEC == 1000) u = clock();
12123  else u = C_uint64_to_num(a, ((C_u64)clock() / CLOCKS_PER_SEC) * 1000);
12124#else
12125  struct rusage ru;
12126
12127  if(C_getrusage(RUSAGE_SELF, &ru) == -1) u = 0;
12128  else {
12129    u = C_uint64_to_num(a, (C_u64)ru.ru_utime.tv_sec * 1000 + ru.ru_utime.tv_usec / 1000);
12130    s = C_uint64_to_num(a, (C_u64)ru.ru_stime.tv_sec * 1000 + ru.ru_stime.tv_usec / 1000);
12131  }
12132#endif
12133
12134  /* buf must not be in nursery */
12135  C_set_block_item(buf, 0, u);
12136  C_set_block_item(buf, 1, s);
12137  return buf;
12138}
12139
12140
12141C_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)
12142{
12143  C_word *loc = *a;
12144  int offset, i, in = C_unfix(index);
12145  *a = loc + C_SIZEOF_LOCATIVE;
12146
12147  loc[ 0 ] = C_LOCATIVE_TAG;
12148
12149  switch(C_unfix(type)) {
12150  case C_SLOT_LOCATIVE: in *= sizeof(C_word); break;
12151  case C_U16_LOCATIVE:
12152  case C_S16_LOCATIVE: in *= 2; break;
12153  case C_U32_LOCATIVE:
12154  case C_F32_LOCATIVE:
12155  case C_S32_LOCATIVE: in *= 4; break;
12156  case C_U64_LOCATIVE:
12157  case C_S64_LOCATIVE:
12158  case C_F64_LOCATIVE: in *= 8; break;
12159  }
12160
12161  offset = in + sizeof(C_header);
12162  loc[ 1 ] = object + offset;
12163  loc[ 2 ] = C_fix(offset);
12164  loc[ 3 ] = type;
12165  loc[ 4 ] = C_truep(weak) ? C_SCHEME_FALSE : object;
12166
12167  return (C_word)loc;
12168}
12169
12170C_regparm C_word C_a_i_locative_ref(C_word **a, int c, C_word loc)
12171{
12172  C_word *ptr;
12173
12174  if(C_immediatep(loc) || C_block_header(loc) != C_LOCATIVE_TAG)
12175    barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-ref", loc);
12176
12177  ptr = (C_word *)C_block_item(loc, 0);
12178
12179  if(ptr == NULL) barf(C_LOST_LOCATIVE_ERROR, "locative-ref", loc);
12180
12181  switch(C_unfix(C_block_item(loc, 2))) {
12182  case C_SLOT_LOCATIVE: return *ptr;
12183  case C_CHAR_LOCATIVE: return C_utf_decode_ptr((C_char *)ptr);
12184  case C_U8_LOCATIVE: return C_fix(*((unsigned char *)ptr));
12185  case C_S8_LOCATIVE: return C_fix(*((char *)ptr));
12186  case C_U16_LOCATIVE: return C_fix(*((unsigned short *)ptr));
12187  case C_S16_LOCATIVE: return C_fix(*((short *)ptr));
12188  case C_U32_LOCATIVE: return C_unsigned_int_to_num(a, *((C_u32 *)ptr));
12189  case C_S32_LOCATIVE: return C_int_to_num(a, *((C_s32 *)ptr));
12190  case C_U64_LOCATIVE: return C_uint64_to_num(a, *((C_u64 *)ptr));
12191  case C_S64_LOCATIVE: return C_int64_to_num(a, *((C_s64 *)ptr));
12192  case C_F32_LOCATIVE: return C_flonum(a, *((float *)ptr));
12193  case C_F64_LOCATIVE: return C_flonum(a, *((double *)ptr));
12194  default: panic(C_text("bad locative type"));
12195  }
12196}
12197
12198C_regparm C_word C_i_locative_set(C_word loc, C_word x)
12199{
12200  C_word *ptr, val;
12201
12202  if(C_immediatep(loc) || C_block_header(loc) != C_LOCATIVE_TAG)
12203    barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", loc);
12204
12205  ptr = (C_word *)C_block_item(loc, 0);
12206
12207  if(ptr == NULL)
12208    barf(C_LOST_LOCATIVE_ERROR, "locative-set!", loc);
12209
12210  switch(C_unfix(C_block_item(loc, 2))) {
12211  case C_SLOT_LOCATIVE: C_mutate(ptr, x); break;
12212
12213  case C_CHAR_LOCATIVE:
12214    if((x & C_IMMEDIATE_TYPE_BITS) != C_CHARACTER_BITS)
12215      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12216
12217    /* does not check for exceeded buffer length! */
12218    C_utf_encode((C_char *)ptr, C_character_code(x));
12219    break;
12220
12221  case C_U8_LOCATIVE:
12222    if((x & C_FIXNUM_BIT) == 0)
12223      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12224
12225    *((unsigned char *)ptr) = C_unfix(x);
12226    break;
12227
12228  case C_S8_LOCATIVE:
12229    if((x & C_FIXNUM_BIT) == 0)
12230      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12231
12232    *((char *)ptr) = C_unfix(x);
12233    break;
12234
12235  case C_U16_LOCATIVE:
12236    if((x & C_FIXNUM_BIT) == 0)
12237      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12238
12239    *((unsigned short *)ptr) = C_unfix(x);
12240    break;
12241
12242  case C_S16_LOCATIVE:
12243    if((x & C_FIXNUM_BIT) == 0)
12244      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12245
12246    *((short *)ptr) = C_unfix(x);
12247    break;
12248
12249  case C_U32_LOCATIVE:
12250    if(!C_truep(C_i_exact_integerp(x)))
12251      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12252
12253    *((C_u32 *)ptr) = C_num_to_unsigned_int(x);
12254    break;
12255
12256  case C_S32_LOCATIVE:
12257    if(!C_truep(C_i_exact_integerp(x)))
12258      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12259
12260    *((C_s32 *)ptr) = C_num_to_int(x);
12261    break;
12262
12263  case C_U64_LOCATIVE:
12264    if(!C_truep(C_i_exact_integerp(x)))
12265      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12266
12267    *((C_u64 *)ptr) = C_num_to_uint64(x);
12268    break;
12269
12270  case C_S64_LOCATIVE:
12271    if(!C_truep(C_i_exact_integerp(x)))
12272      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12273
12274    *((C_s64 *)ptr) = C_num_to_int64(x);
12275    break;
12276
12277  case C_F32_LOCATIVE:
12278    if(C_immediatep(x) || C_block_header(x) != C_FLONUM_TAG)
12279      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12280
12281    *((float *)ptr) = C_flonum_magnitude(x);
12282    break;
12283
12284  case C_F64_LOCATIVE:
12285    if(C_immediatep(x) || C_block_header(x) != C_FLONUM_TAG)
12286      barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-set!", x);
12287
12288    *((double *)ptr) = C_flonum_magnitude(x);
12289    break;
12290
12291  default: panic(C_text("bad locative type"));
12292  }
12293
12294  return C_SCHEME_UNDEFINED;
12295}
12296
12297
12298C_regparm C_word C_i_locative_to_object(C_word loc)
12299{
12300  C_word *ptr;
12301
12302  if(C_immediatep(loc) || C_block_header(loc) != C_LOCATIVE_TAG)
12303    barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative->object", loc);
12304
12305  ptr = (C_word *)C_block_item(loc, 0);
12306
12307  if(ptr == NULL) return C_SCHEME_FALSE;
12308  else return (C_word)ptr - C_unfix(C_block_item(loc, 1));
12309}
12310
12311
12312C_regparm C_word C_i_locative_index(C_word loc)
12313{
12314  int bytes;
12315
12316  if(C_immediatep(loc) || C_block_header(loc) != C_LOCATIVE_TAG)
12317    barf(C_BAD_ARGUMENT_TYPE_ERROR, "locative-index", loc);
12318
12319  bytes = C_unfix(C_block_item(loc, 1)) - sizeof(C_header);
12320
12321  switch(C_unfix(C_block_item(loc, 2))) {
12322  case C_SLOT_LOCATIVE: return C_fix(bytes/sizeof(C_word)); break;
12323
12324  case C_CHAR_LOCATIVE:
12325    { C_word x = C_i_locative_to_object(loc);
12326      if(x == C_SCHEME_FALSE)
12327        barf(C_LOST_LOCATIVE_ERROR, "locative-index", loc);
12328      return C_fix(C_utf_char_position(x, bytes)); }
12329
12330  case C_U8_LOCATIVE:
12331  case C_S8_LOCATIVE: return C_fix(bytes); break;
12332
12333  case C_U16_LOCATIVE:
12334  case C_S16_LOCATIVE: return C_fix(bytes/2); break;
12335
12336  case C_U32_LOCATIVE:
12337  case C_S32_LOCATIVE:
12338  case C_F32_LOCATIVE: return C_fix(bytes/4); break;
12339
12340  case C_U64_LOCATIVE:
12341  case C_S64_LOCATIVE:
12342  case C_F64_LOCATIVE: return C_fix(bytes/8); break;
12343
12344  default: panic(C_text("bad locative type"));
12345  }
12346}
12347
12348
12349/* GC protection of user-variables: */
12350
12351C_regparm void C_gc_protect(C_word **addr, int n)
12352{
12353  int k;
12354
12355  if(collectibles_top + n >= collectibles_limit) {
12356    k = collectibles_limit - collectibles;
12357    collectibles = (C_word **)C_realloc(collectibles, sizeof(C_word *) * k * 2);
12358
12359    if(collectibles == NULL)
12360      panic(C_text("out of memory - cannot allocate GC protection vector"));
12361
12362    collectibles_top = collectibles + k;
12363    collectibles_limit = collectibles + k * 2;
12364  }
12365
12366  C_memcpy(collectibles_top, addr, n * sizeof(C_word *));
12367  collectibles_top += n;
12368}
12369
12370
12371C_regparm void C_gc_unprotect(int n)
12372{
12373  collectibles_top -= n;
12374}
12375
12376
12377/* Map procedure-ptr to id or id to ptr: */
12378
12379C_char *C_lookup_procedure_id(void *ptr)
12380{
12381  LF_LIST *lfl;
12382  C_PTABLE_ENTRY *pt;
12383
12384  for(lfl = lf_list; lfl != NULL; lfl = lfl->next) {
12385    pt = lfl->ptable;
12386
12387    if(pt != NULL) {
12388      while(pt->id != NULL) {
12389	if(pt->ptr == ptr) return pt->id;
12390	else ++pt;
12391      }
12392    }
12393  }
12394
12395  return NULL;
12396}
12397
12398
12399void *C_lookup_procedure_ptr(C_char *id)
12400{
12401  LF_LIST *lfl;
12402  C_PTABLE_ENTRY *pt;
12403
12404  for(lfl = lf_list; lfl != NULL; lfl = lfl->next) {
12405    pt = lfl->ptable;
12406
12407    if(pt != NULL) {
12408      while(pt->id != NULL) {
12409	if(!C_strcmp(id, pt->id)) return pt->ptr;
12410	else ++pt;
12411      }
12412    }
12413  }
12414
12415  return NULL;
12416}
12417
12418
12419void C_ccall C_copy_closure(C_word c, C_word *av)
12420{
12421  C_word
12422    /* closure = av[ 0 ] */
12423    k = av[ 1 ],
12424    proc = av[ 2 ],
12425    *p;
12426  int n = C_header_size(proc);
12427
12428  if(!C_demand(n + 1))
12429    C_save_and_reclaim_args((void *)copy_closure_2, 2, proc, k);
12430  else {
12431    C_save(proc);
12432    C_save(k);
12433    p = C_temporary_stack;
12434    C_temporary_stack = C_temporary_stack_bottom;
12435    copy_closure_2(0, p);
12436  }
12437}
12438
12439
12440static void C_ccall copy_closure_2(C_word c, C_word *av)
12441{
12442  C_word
12443    k = av[ 0 ],
12444    proc = av[ 1 ];
12445  int cells = C_header_size(proc);
12446  C_word
12447    *ptr = C_alloc(C_SIZEOF_CLOSURE(cells)),
12448    *p = ptr;
12449
12450  *(p++) = C_CLOSURE_TYPE | cells;
12451  /* this is only allowed because the storage is freshly allocated: */
12452  C_memcpy_slots(p, C_data_pointer(proc), cells);
12453  C_kontinue(k, (C_word)ptr);
12454}
12455
12456
12457/* Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn */
12458
12459void C_ccall C_call_with_cthulhu(C_word c, C_word *av)
12460{
12461  C_word
12462    proc = av[ 2 ],
12463    *a = C_alloc(C_SIZEOF_CLOSURE(1)),
12464    av2[ 2 ];
12465
12466  av2[ 0 ] = proc;
12467  av2[ 1 ] = C_closure(&a, 1, (C_word)termination_continuation); /* k */
12468  C_do_apply(2, av2);
12469}
12470
12471
12472/* fixnum arithmetic with overflow detection (from "Hacker's Delight" by Hank Warren)
12473   These routines return #f if the operation failed due to overflow.
12474 */
12475
12476C_regparm C_word C_i_o_fixnum_plus(C_word n1, C_word n2)
12477{
12478  C_word x1, x2, s;
12479
12480  if((n1 & C_FIXNUM_BIT) == 0 || (n2 & C_FIXNUM_BIT) == 0) return C_SCHEME_FALSE;
12481
12482  x1 = C_unfix(n1);
12483  x2 = C_unfix(n2);
12484  s = x1 + x2;
12485
12486#ifdef C_SIXTY_FOUR
12487  if((((s ^ x1) & (s ^ x2)) >> 62) != 0) return C_SCHEME_FALSE;
12488#else
12489  if((((s ^ x1) & (s ^ x2)) >> 30) != 0) return C_SCHEME_FALSE;
12490#endif
12491  else return C_fix(s);
12492}
12493
12494
12495C_regparm C_word C_i_o_fixnum_difference(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_times(C_word n1, C_word n2)
12515{
12516  C_word x1, x2;
12517  C_uword x1u, x2u;
12518#ifdef C_SIXTY_FOUR
12519# ifdef C_LLP
12520  C_uword c = 1ULL<<63ULL;
12521# else
12522  C_uword c = 1UL<<63UL;
12523# endif
12524#else
12525  C_uword c = 1UL<<31UL;
12526#endif
12527
12528  if((n1 & C_FIXNUM_BIT) == 0 || (n2 & C_FIXNUM_BIT) == 0) return C_SCHEME_FALSE;
12529
12530  if((n1 & C_INT_SIGN_BIT) == (n2 & C_INT_SIGN_BIT)) --c;
12531
12532  x1 = C_unfix(n1);
12533  x2 = C_unfix(n2);
12534  x1u = x1 < 0 ? -x1 : x1;
12535  x2u = x2 < 0 ? -x2 : x2;
12536
12537  if(x2u != 0 && x1u > (c / x2u)) return C_SCHEME_FALSE;
12538
12539  x1 = x1 * x2;
12540
12541  if(C_fitsinfixnump(x1)) return C_fix(x1);
12542  else return C_SCHEME_FALSE;
12543}
12544
12545
12546C_regparm C_word C_i_o_fixnum_quotient(C_word n1, C_word n2)
12547{
12548  C_word x1, x2;
12549
12550  if((n1 & C_FIXNUM_BIT) == 0 || (n2 & C_FIXNUM_BIT) == 0) return C_SCHEME_FALSE;
12551
12552  x1 = C_unfix(n1);
12553  x2 = C_unfix(n2);
12554
12555  if(x2 == 0)
12556    barf(C_DIVISION_BY_ZERO_ERROR, "fx/?");
12557
12558#ifdef C_SIXTY_FOUR
12559  if(x1 == 0x8000000000000000L && x2 == -1) return C_SCHEME_FALSE;
12560#else
12561  if(x1 == 0x80000000L && x2 == -1) return C_SCHEME_FALSE;
12562#endif
12563
12564  x1 = x1 / x2;
12565
12566  if(C_fitsinfixnump(x1)) return C_fix(x1);
12567  else return C_SCHEME_FALSE;
12568}
12569
12570
12571C_regparm C_word C_i_o_fixnum_and(C_word n1, C_word n2)
12572{
12573  C_uword x1, x2, r;
12574
12575  if((n1 & C_FIXNUM_BIT) == 0 || (n2 & C_FIXNUM_BIT) == 0) return C_SCHEME_FALSE;
12576
12577  x1 = C_unfix(n1);
12578  x2 = C_unfix(n2);
12579  r = x1 & x2;
12580
12581  if(((r & C_INT_SIGN_BIT) >> 1) != (r & C_INT_TOP_BIT)) return C_SCHEME_FALSE;
12582  else return C_fix(r);
12583}
12584
12585
12586C_regparm C_word C_i_o_fixnum_ior(C_word n1, C_word n2)
12587{
12588  C_uword x1, x2, r;
12589
12590  if((n1 & C_FIXNUM_BIT) == 0 || (n2 & C_FIXNUM_BIT) == 0) return C_SCHEME_FALSE;
12591
12592  x1 = C_unfix(n1);
12593  x2 = C_unfix(n2);
12594  r = x1 | x2;
12595
12596  if(((r & C_INT_SIGN_BIT) >> 1) != (r & C_INT_TOP_BIT)) return C_SCHEME_FALSE;
12597  else return C_fix(r);
12598}
12599
12600
12601C_regparm C_word C_i_o_fixnum_xor(C_word n1, C_word n2)
12602{
12603  C_uword x1, x2, r;
12604
12605  if((n1 & C_FIXNUM_BIT) == 0 || (n2 & C_FIXNUM_BIT) == 0) return C_SCHEME_FALSE;
12606
12607  x1 = C_unfix(n1);
12608  x2 = C_unfix(n2);
12609  r = x1 ^ x2;
12610
12611  if(((r & C_INT_SIGN_BIT) >> 1) != (r & C_INT_TOP_BIT)) return C_SCHEME_FALSE;
12612  else return C_fix(r);
12613}
12614
12615
12616/* decoding of literals in compressed format */
12617
12618static C_regparm C_uword decode_size(C_char **str)
12619{
12620  C_uchar **ustr = (C_uchar **)str;
12621  C_uword size = (*((*ustr)++) & 0xff) << 16; /* always big endian */
12622
12623  size |= (*((*ustr)++) & 0xff) << 8;
12624  size |= (*((*ustr)++) & 0xff);
12625  return size;
12626}
12627
12628
12629static C_regparm C_word decode_literal2(C_word **ptr, C_char **str,
12630						C_word *dest)
12631{
12632  C_ulong bits = *((*str)++) & 0xff;
12633  C_word *data, *dptr, val;
12634  C_uword size;
12635
12636  /* vvv this can be taken out at a later stage (once it works reliably) vvv */
12637  if(bits != 0xfe)
12638    panic(C_text("invalid encoded literal format"));
12639
12640  bits = *((*str)++) & 0xff;
12641  /* ^^^ */
12642
12643#ifdef C_SIXTY_FOUR
12644  bits <<= 24 + 32;
12645#else
12646  bits <<= 24;
12647#endif
12648
12649  if(bits == C_HEADER_BITS_MASK) {		/* special/immediate */
12650    switch(0xff & *((*str)++)) {
12651    case C_BOOLEAN_BITS:
12652      return C_mk_bool(*((*str)++));
12653
12654    case C_CHARACTER_BITS:
12655      return C_make_character(decode_size(str));
12656
12657    case C_SCHEME_END_OF_LIST:
12658    case C_SCHEME_UNDEFINED:
12659    case C_SCHEME_END_OF_FILE:
12660    case C_SCHEME_BROKEN_WEAK_PTR:
12661      return (C_word)(*(*str - 1));
12662
12663    case C_FIXNUM_BIT:
12664      val = (C_uword)(signed char)*((*str)++) << 24; /* always big endian */
12665      val |= ((C_uword)*((*str)++) & 0xff) << 16;
12666      val |= ((C_uword)*((*str)++) & 0xff) << 8;
12667      val |= ((C_uword)*((*str)++) & 0xff);
12668      return C_fix(val);
12669
12670/* XXX Handle legacy bignum encoding */
12671#ifdef C_SIXTY_FOUR
12672    case ((C_STRING_TYPE | C_GC_FORWARDING_BIT) >> (24 + 32)) & 0xff:
12673#else
12674    case ((C_STRING_TYPE | C_GC_FORWARDING_BIT) >> 24) & 0xff:
12675#endif
12676      bits = (C_STRING_TYPE | C_GC_FORWARDING_BIT);
12677      break;
12678/* XXX */
12679
12680#ifdef C_SIXTY_FOUR
12681    case ((C_BYTEVECTOR_TYPE | C_GC_FORWARDING_BIT) >> (24 + 32)) & 0xff:
12682#else
12683    case ((C_BYTEVECTOR_TYPE | C_GC_FORWARDING_BIT) >> 24) & 0xff:
12684#endif
12685      bits = (C_BYTEVECTOR_TYPE | C_GC_FORWARDING_BIT);
12686      break;
12687
12688    default:
12689      panic(C_text("invalid encoded special literal"));
12690    }
12691  }
12692
12693#ifndef C_SIXTY_FOUR
12694  if((bits & C_8ALIGN_BIT) != 0) {
12695    /* Align _data_ on 8-byte boundary: */
12696    if(C_aligned8(*ptr)) ++(*ptr);
12697  }
12698#endif
12699
12700  val = (C_word)(*ptr);
12701
12702  if((bits & C_SPECIALBLOCK_BIT) != 0)
12703    panic(C_text("literals with special bit cannot be decoded"));
12704
12705  if(bits == C_FLONUM_TYPE) {
12706    val = C_flonum(ptr, decode_flonum_literal(*str));
12707    while(*((*str)++) != '\0');      /* skip terminating '\0' */
12708    return val;
12709  }
12710
12711  size = decode_size(str);
12712
12713  switch(bits) {
12714  /* This cannot be encoded as a bytevector due to endianness differences */
12715
12716  /* XXX legacy bignum encoding: */
12717  case (C_STRING_TYPE | C_BYTEBLOCK_BIT | C_GC_FORWARDING_BIT): /* This represents "exact int" */
12718  /* XXX */
12719  case (C_BYTEVECTOR_TYPE | C_GC_FORWARDING_BIT): /* This represents "exact int" */
12720    /* bignums are also allocated statically */
12721    val = C_static_bignum(ptr, size, *str);
12722    *str += size;
12723    break;
12724
12725  /* XXX legacy encoding: */
12726  case (C_STRING_TYPE | C_BYTEBLOCK_BIT):
12727    /* strings are always allocated statically */
12728    val = C_static_string(ptr, size, *str);
12729    *str += size;
12730    break;
12731  /* XXX */
12732
12733  case C_STRING_TYPE:
12734    /* strings are always allocated statically */
12735    val = C_static_string(ptr, size - 1, *str);
12736    *str += size;
12737    break;
12738
12739  case C_BYTEVECTOR_TYPE:
12740    /* ... as are bytevectors */
12741    val = C_static_bytevector(ptr, size, *str);
12742    *str += size;
12743    break;
12744
12745  case C_SYMBOL_TYPE:
12746    if(dest == NULL)
12747      panic(C_text("invalid literal symbol destination"));
12748
12749    if (**str == '\1') {
12750      val = C_h_intern(dest, size, ++*str);
12751    } else if (**str == '\2') {
12752      val = C_h_intern_kw(dest, size, ++*str);
12753    } else {
12754      C_snprintf(buffer, sizeof(buffer), C_text("Unknown symbol subtype: %d"), (int)**str);
12755      panic(buffer);
12756    }
12757    *str += size;
12758    break;
12759
12760  case C_LAMBDA_INFO_TYPE:
12761    /* lambda infos are always allocated statically */
12762    val = C_static_lambda_info(ptr, size, *str);
12763    *str += size;
12764    break;
12765
12766  default:
12767    *((*ptr)++) = C_make_header(bits, size);
12768    data = *ptr;
12769
12770    if((bits & C_BYTEBLOCK_BIT) != 0) {
12771      C_memcpy(data, *str, size);
12772      size = C_align(size);
12773      *str += size;
12774      *ptr = (C_word *)C_align((C_word)(*ptr) + size);
12775    }
12776    else {
12777      C_word *dptr = *ptr;
12778      *ptr += size;
12779
12780      while(size--) {
12781	*dptr = decode_literal2(ptr, str, dptr);
12782	++dptr;
12783      }
12784    }
12785  }
12786
12787  return val;
12788}
12789
12790
12791C_regparm C_word
12792C_decode_literal(C_word **ptr, C_char *str)
12793{
12794  return decode_literal2(ptr, &str, NULL);
12795}
12796
12797
12798void
12799C_use_private_repository(C_char *path)
12800{
12801  private_repository = path;
12802}
12803
12804
12805C_char *
12806C_private_repository_path()
12807{
12808  return private_repository;
12809}
12810
12811C_char *
12812C_executable_pathname() {
12813#ifdef SEARCH_EXE_PATH
12814  return C_main_exe == NULL ? NULL : C_strdup(C_main_exe);
12815#else
12816  return C_resolve_executable_pathname(NULL);
12817#endif
12818}
12819
12820C_char *
12821C_executable_dirname() {
12822  int len;
12823  C_char *path;
12824
12825  if((path = C_executable_pathname()) == NULL)
12826    return NULL;
12827
12828#if defined(_WIN32) && !defined(__CYGWIN__)
12829  for(len = C_strlen(path); len >= 0 && path[len] != '\\'; len--);
12830#else
12831  for(len = C_strlen(path); len >= 0 && path[len] != '/'; len--);
12832#endif
12833
12834  path[len] = '\0';
12835  return path;
12836}
12837
12838C_char *
12839C_resolve_executable_pathname(C_char *fname)
12840{
12841  int n;
12842  C_WCHAR *buffer = (C_WCHAR *) C_malloc(C_MAX_PATH);
12843
12844  if(buffer == NULL) return NULL;
12845
12846#if defined(__linux__) || defined(__sun)
12847  C_char linkname[64]; /* /proc/<pid>/exe */
12848  pid_t pid = C_getpid();
12849
12850# ifdef __linux__
12851  C_snprintf(linkname, sizeof(linkname), "/proc/%i/exe", pid);
12852# else
12853  C_snprintf(linkname, sizeof(linkname), "/proc/%i/path/a.out", pid); /* SunOS / Solaris */
12854# endif
12855
12856  n = C_readlink(linkname, buffer, C_MAX_PATH);
12857  if(n < 0 || n >= C_MAX_PATH)
12858    goto error;
12859
12860  buffer[n] = '\0';
12861  return buffer;
12862#elif defined(_WIN32) && !defined(__CYGWIN__)
12863  n = GetModuleFileNameW(NULL, buffer, C_MAX_PATH);
12864  if(n == 0 || n >= C_MAX_PATH)
12865    goto error;
12866
12867  C_char *buf2 = C_strdup(C_utf8(buffer));
12868  C_free(buffer);
12869  return buf2;
12870#elif defined(C_MACOSX)
12871  C_char buf[C_MAX_PATH];
12872  C_u32 size = C_MAX_PATH;
12873
12874  if(_NSGetExecutablePath(buf, &size) != 0)
12875    goto error;
12876
12877  if(C_realpath(buf, buffer) == NULL)
12878    goto error;
12879
12880  return buffer;
12881#elif defined(__HAIKU__)
12882{
12883  image_info info;
12884  int32 cookie = 0;
12885
12886  while (get_next_image_info(0, &cookie, &info) == B_OK) {
12887    if (info.type == B_APP_IMAGE) {
12888      C_strlcpy(buffer, info.name, C_MAX_PATH);
12889      return buffer;
12890    }
12891  }
12892}
12893#elif defined(SEARCH_EXE_PATH)
12894  int len;
12895  C_char *path, buf[C_MAX_PATH];
12896
12897  /* no name given (execve) */
12898  if(fname == NULL)
12899    goto error;
12900
12901  /* absolute pathname */
12902  if(fname[0] == '/') {
12903    if(C_realpath(fname, buffer) == NULL)
12904      goto error;
12905    else
12906      return buffer;
12907  }
12908
12909  /* current directory */
12910  if(C_strchr(fname, '/') != NULL) {
12911    if(C_getcwd(buffer, C_MAX_PATH) == NULL)
12912      goto error;
12913
12914    n = C_snprintf(buf, C_MAX_PATH, "%s/%s", buffer, fname);
12915    if(n < 0 || n >= C_MAX_PATH)
12916      goto error;
12917
12918    if(C_access(buf, X_OK) == 0) {
12919      if(C_realpath(buf, buffer) == NULL)
12920        goto error;
12921      else
12922        return buffer;
12923    }
12924  }
12925
12926  /* walk PATH */
12927  if((path = getenv("PATH")) == NULL)
12928    goto error;
12929
12930  do {
12931    /* check PATH entry length */
12932    len = C_strcspn(path, ":");
12933    if(len == 0 || len >= C_MAX_PATH)
12934      continue;
12935
12936    /* "<path>/<fname>" to buf */
12937    C_strncpy(buf, path, len);
12938    n = C_snprintf(buf + len, C_MAX_PATH - len, "/%s", fname);
12939    if(n < 0 || n + len >= C_MAX_PATH)
12940      continue;
12941
12942    if(C_access(buf, X_OK) != 0)
12943      continue;
12944
12945    /* fname found, resolve links */
12946    if(C_realpath(buf, buffer) != NULL)
12947      return buffer;
12948
12949  /* seek next entry, skip colon */
12950  } while (path += len, *path++);
12951#else
12952# error "Please either define SEARCH_EXE_PATH in Makefile.<platform> or implement C_resolve_executable_pathname for your platform!"
12953#endif
12954
12955error:
12956  C_free(buffer);
12957  return NULL;
12958}
12959
12960C_regparm C_word
12961C_i_getprop(C_word sym, C_word prop, C_word def)
12962{
12963  C_word pl = C_symbol_plist(sym);
12964
12965  while(pl != C_SCHEME_END_OF_LIST) {
12966    if(C_block_item(pl, 0) == prop)
12967      return C_u_i_car(C_u_i_cdr(pl));
12968    else pl = C_u_i_cdr(C_u_i_cdr(pl));
12969  }
12970
12971  return def;
12972}
12973
12974
12975C_regparm C_word
12976C_putprop(C_word **ptr, C_word sym, C_word prop, C_word val)
12977{
12978  C_word pl = C_symbol_plist(sym);
12979
12980  /* Newly added plist?  Ensure the symbol stays! */
12981  if (pl == C_SCHEME_END_OF_LIST) C_i_persist_symbol(sym);
12982
12983  while(pl != C_SCHEME_END_OF_LIST) {
12984    if(C_block_item(pl, 0) == prop) {
12985      C_mutate(&C_u_i_car(C_u_i_cdr(pl)), val);
12986      return val;
12987    }
12988    else pl = C_u_i_cdr(C_u_i_cdr(pl));
12989  }
12990
12991  pl = C_a_pair(ptr, val, C_symbol_plist(sym));
12992  pl = C_a_pair(ptr, prop, pl);
12993  C_mutate_slot(&C_symbol_plist(sym), pl);
12994  return val;
12995}
12996
12997
12998C_regparm C_word
12999C_i_get_keyword(C_word kw, C_word args, C_word def)
13000{
13001  while(!C_immediatep(args)) {
13002    if(C_header_type(args) == C_PAIR_TYPE) {
13003      if(kw == C_u_i_car(args)) {
13004	args = C_u_i_cdr(args);
13005
13006	if(C_immediatep(args) || C_header_type(args) != C_PAIR_TYPE)
13007	  return def;
13008	else return C_u_i_car(args);
13009      }
13010      else {
13011	args = C_u_i_cdr(args);
13012
13013	if(C_immediatep(args) || C_header_type(args) != C_PAIR_TYPE)
13014	  return def;
13015	else args = C_u_i_cdr(args);
13016      }
13017    }
13018  }
13019
13020  return def;
13021}
13022
13023C_word C_i_dump_statistical_profile()
13024{
13025  PROFILE_BUCKET *b, *b2, **bp;
13026  FILE *fp;
13027  C_char *k1, *k2 = NULL;
13028  int n;
13029  double ms;
13030
13031  assert(profiling);
13032  assert(profile_table != NULL);
13033
13034  set_profile_timer(0);
13035
13036  profiling = 0; /* In case a SIGPROF is delivered late */
13037  bp = profile_table;
13038
13039  C_snprintf(buffer, STRING_BUFFER_SIZE, C_text("PROFILE.%d"), C_getpid());
13040
13041  if(debug_mode)
13042    C_dbg(C_text("debug"), C_text("dumping statistical profile to `%s'...\n"), buffer);
13043  fp = fopen(buffer, "w");
13044  if (fp == NULL)
13045    panic(C_text("could not write profile!"));
13046
13047  C_fputs(C_text("statistical\n"), fp);
13048  for(n = 0; n < PROFILE_TABLE_SIZE; ++n) {
13049    for(b = bp[ n ]; b != NULL; b = b2) {
13050      b2 = b->next;
13051
13052      k1 = b->key;
13053      C_fputs(C_text("(|"), fp);
13054      /* Dump raw C string as if it were a symbol */
13055      while((k2 = C_strpbrk(k1, C_text("\\|"))) != NULL) {
13056        C_fwrite(k1, 1, k2-k1, fp);
13057        C_fputc('\\', fp);
13058        C_fputc(*k2, fp);
13059        k1 = k2+1;
13060      }
13061      C_fputs(k1, fp);
13062      ms = (double)b->sample_count * (double)profile_frequency / 1000.0;
13063      C_fprintf(fp, C_text("| " UWORD_COUNT_FORMAT_STRING " %lf)\n"),
13064                b->call_count, ms);
13065      C_free(b);
13066    }
13067  }
13068
13069  C_fclose(fp);
13070  C_free(profile_table);
13071  profile_table = NULL;
13072
13073  return C_SCHEME_UNDEFINED;
13074}
13075
13076void C_ccall C_dump_heap_state(C_word c, C_word *av)
13077{
13078  C_word
13079    /* closure = av[ 0 ] */
13080    k = av[ 1 ];
13081
13082  /* make sure heap is compacted */
13083  C_save(k);
13084  C_fromspace_top = C_fromspace_limit; /* force major GC */
13085  C_reclaim((void *)dump_heap_state_2, 1);
13086}
13087
13088
13089static C_ulong
13090hdump_hash(C_word key)
13091{
13092  return (C_ulong)key % HDUMP_TABLE_SIZE;
13093}
13094
13095
13096static void
13097hdump_count(C_word key, int n, int t)
13098{
13099  HDUMP_BUCKET **bp = hdump_table + hdump_hash(key);
13100  HDUMP_BUCKET *b = *bp;
13101
13102  while(b != NULL) {
13103    if(b->key == key) {
13104      b->count += n;
13105      b->total += t;
13106      return;
13107    }
13108    else b = b->next;
13109  }
13110
13111  b = (HDUMP_BUCKET *)C_malloc(sizeof(HDUMP_BUCKET));
13112
13113  if(b == 0)
13114    panic(C_text("out of memory - can not allocate heap-dump table-bucket"));
13115
13116  b->next = *bp;
13117  b->key = key;
13118  *bp = b;
13119  b->count = n;
13120  b->total = t;
13121}
13122
13123
13124static void C_ccall dump_heap_state_2(C_word c, C_word *av)
13125{
13126  C_word k = av[ 0 ];
13127  HDUMP_BUCKET *b, *b2, **bp;
13128  int n, bytes;
13129  C_byte *scan;
13130  C_SCHEME_BLOCK *sbp;
13131  C_header h;
13132  C_word x, key, *p;
13133  int imm = 0, blk = 0;
13134
13135  hdump_table = (HDUMP_BUCKET **)C_malloc(HDUMP_TABLE_SIZE * sizeof(HDUMP_BUCKET *));
13136
13137  if(hdump_table == NULL)
13138    panic(C_text("out of memory - can not allocate heap-dump table"));
13139
13140  C_memset(hdump_table, 0, sizeof(HDUMP_BUCKET *) * HDUMP_TABLE_SIZE);
13141
13142  scan = fromspace_start;
13143
13144  while(scan < C_fromspace_top) {
13145    ++blk;
13146    sbp = (C_SCHEME_BLOCK *)scan;
13147
13148    if(*((C_word *)sbp) == ALIGNMENT_HOLE_MARKER)
13149      sbp = (C_SCHEME_BLOCK *)((C_word *)sbp + 1);
13150
13151    n = C_header_size(sbp);
13152    h = sbp->header;
13153    bytes = (h & C_BYTEBLOCK_BIT) ? n : n * sizeof(C_word);
13154    key = (C_word)(h & C_HEADER_BITS_MASK);
13155    p = sbp->data;
13156
13157    if(key == C_STRUCTURE_TYPE) key = *p;
13158
13159    hdump_count(key, 1, bytes);
13160
13161    if(n > 0 && (h & C_BYTEBLOCK_BIT) == 0) {
13162      if((h & C_SPECIALBLOCK_BIT) != 0) {
13163	--n;
13164	++p;
13165      }
13166
13167      while(n--) {
13168	x = *(p++);
13169
13170	if(C_immediatep(x)) {
13171	  ++imm;
13172
13173	  if((x & C_FIXNUM_BIT) != 0) key = C_fix(1);
13174	  else {
13175	    switch(x & C_IMMEDIATE_TYPE_BITS) {
13176	    case C_BOOLEAN_BITS: key = C_SCHEME_TRUE; break;
13177	    case C_CHARACTER_BITS: key = C_make_character('A'); break;
13178	    default: key = x;
13179	    }
13180	  }
13181
13182	  hdump_count(key, 1, 0);
13183	}
13184      }
13185    }
13186
13187    scan = (C_byte *)sbp + C_align(bytes) + sizeof(C_word);
13188  }
13189
13190  bp = hdump_table;
13191  /* HACK */
13192#define C_WEAK_PAIR_TYPE (C_PAIR_TYPE | C_SPECIALBLOCK_BIT)
13193
13194  for(n = 0; n < HDUMP_TABLE_SIZE; ++n) {
13195    for(b = bp[ n ]; b != NULL; b = b2) {
13196      b2 = b->next;
13197
13198      switch(b->key) {
13199      case C_fix(1): C_fprintf(C_stderr,                 C_text("fixnum         ")); break;
13200      case C_SCHEME_TRUE: C_fprintf(C_stderr,            C_text("boolean        ")); break;
13201      case C_SCHEME_END_OF_LIST: C_fprintf(C_stderr,     C_text("null           ")); break;
13202      case C_SCHEME_UNDEFINED  : C_fprintf(C_stderr,     C_text("void           ")); break;
13203      case C_SCHEME_BROKEN_WEAK_PTR: C_fprintf(C_stderr, C_text("broken weak ptr")); break;
13204      case C_make_character('A'): C_fprintf(C_stderr,    C_text("character      ")); break;
13205      case C_SCHEME_END_OF_FILE: C_fprintf(C_stderr,     C_text("eof            ")); break;
13206      case C_SCHEME_UNBOUND: C_fprintf(C_stderr,         C_text("unbound        ")); break;
13207      case C_SYMBOL_TYPE: C_fprintf(C_stderr,            C_text("symbol         ")); break;
13208      case C_STRING_TYPE: C_fprintf(C_stderr,            C_text("string         ")); break;
13209      case C_PAIR_TYPE: C_fprintf(C_stderr,              C_text("pair           ")); break;
13210      case C_CLOSURE_TYPE: C_fprintf(C_stderr,           C_text("closure        ")); break;
13211      case C_FLONUM_TYPE: C_fprintf(C_stderr,            C_text("flonum         ")); break;
13212      case C_PORT_TYPE: C_fprintf(C_stderr,              C_text("port           ")); break;
13213      case C_POINTER_TYPE: C_fprintf(C_stderr,           C_text("pointer        ")); break;
13214      case C_LOCATIVE_TYPE: C_fprintf(C_stderr,          C_text("locative       ")); break;
13215      case C_TAGGED_POINTER_TYPE: C_fprintf(C_stderr,    C_text("tagged pointer ")); break;
13216      case C_LAMBDA_INFO_TYPE: C_fprintf(C_stderr,       C_text("lambda info    ")); break;
13217      case C_WEAK_PAIR_TYPE: C_fprintf(C_stderr,         C_text("weak pair      ")); break;
13218      case C_VECTOR_TYPE: C_fprintf(C_stderr,            C_text("vector         ")); break;
13219      case C_BYTEVECTOR_TYPE: C_fprintf(C_stderr,        C_text("bytevector     ")); break;
13220      case C_BIGNUM_TYPE: C_fprintf(C_stderr,            C_text("bignum         ")); break;
13221      case C_CPLXNUM_TYPE: C_fprintf(C_stderr,           C_text("cplxnum        ")); break;
13222      case C_RATNUM_TYPE: C_fprintf(C_stderr,            C_text("ratnum         ")); break;
13223	/* XXX this is sort of funny: */
13224      case C_BYTEBLOCK_BIT: C_fprintf(C_stderr,        C_text("bytevector           ")); break;
13225      default:
13226	x = b->key;
13227
13228	if(!C_immediatep(x) && C_header_bits(x) == C_SYMBOL_TYPE) {
13229	  x = C_block_item(x, 1);
13230	  C_fprintf(C_stderr, C_text("`%.*s'"), (int)C_header_size(x), C_c_string(x));
13231	}
13232	else C_fprintf(C_stderr, C_text("unknown key " UWORD_FORMAT_STRING), (C_uword)b->key);
13233      }
13234
13235      C_fprintf(C_stderr, C_text("\t%d"), b->count);
13236
13237      if(b->total > 0)
13238	C_fprintf(C_stderr, C_text("\t%d bytes"), b->total);
13239
13240      C_fputc('\n', C_stderr);
13241      C_free(b);
13242    }
13243  }
13244
13245  C_fprintf(C_stderr, C_text("\ntotal number of blocks: %d, immediates: %d\n"),
13246	    blk, imm);
13247  C_free(hdump_table);
13248  C_kontinue(k, C_SCHEME_UNDEFINED);
13249}
13250
13251
13252static void C_ccall filter_heap_objects_2(C_word c, C_word *av)
13253{
13254  void *func = C_pointer_address(av[ 0 ]);
13255  C_word
13256    userarg = av[ 1 ],
13257    vector = av[ 2 ],
13258    k = av[ 3 ];
13259  int n, bytes;
13260  C_byte *scan;
13261  C_SCHEME_BLOCK *sbp;
13262  C_header h;
13263  C_word *p;
13264  int vecsize = C_header_size(vector);
13265  typedef int (*filterfunc)(C_word x, C_word userarg);
13266  filterfunc ff = (filterfunc)func;
13267  int vcount = 0;
13268
13269  scan = fromspace_start;
13270
13271  while(scan < C_fromspace_top) {
13272    sbp = (C_SCHEME_BLOCK *)scan;
13273
13274    if(*((C_word *)sbp) == ALIGNMENT_HOLE_MARKER)
13275      sbp = (C_SCHEME_BLOCK *)((C_word *)sbp + 1);
13276
13277    n = C_header_size(sbp);
13278    h = sbp->header;
13279    bytes = (h & C_BYTEBLOCK_BIT) ? n : n * sizeof(C_word);
13280    p = sbp->data;
13281
13282    if(ff((C_word)sbp, userarg)) {
13283      if(vcount < vecsize) {
13284	C_set_block_item(vector, vcount, (C_word)sbp);
13285	++vcount;
13286      }
13287      else {
13288	C_kontinue(k, C_fix(-1));
13289      }
13290    }
13291
13292    scan = (C_byte *)sbp + C_align(bytes) + sizeof(C_word);
13293  }
13294
13295  C_kontinue(k, C_fix(vcount));
13296}
13297
13298
13299void C_ccall C_filter_heap_objects(C_word c, C_word *av)
13300{
13301  C_word
13302    /* closure = av[ 0 ] */
13303    k = av[ 1 ],
13304    func = av[ 2 ],
13305    vector = av[ 3 ],
13306    userarg = av[ 4 ];
13307
13308  /* make sure heap is compacted */
13309  C_save(k);
13310  C_save(vector);
13311  C_save(userarg);
13312  C_save(func);
13313  C_fromspace_top = C_fromspace_limit; /* force major GC */
13314  C_reclaim((void *)filter_heap_objects_2, 4);
13315}
13316
13317C_regparm C_word C_i_process_sleep(C_word n)
13318{
13319#if defined(_WIN32) && !defined(__CYGWIN__)
13320  Sleep(C_unfix(n) * 1000);
13321  return C_fix(0);
13322#else
13323  return C_fix(sleep(C_unfix(n)));
13324#endif
13325}
13326
13327C_regparm C_word
13328C_i_file_exists_p(C_word name, C_word file, C_word dir)
13329{
13330#if defined(_WIN32) && !defined(__CYGWIN__)
13331  struct _stat64i32 buf;
13332#else
13333  struct stat buf;
13334#endif
13335  int res;
13336
13337  res = C_stat(C_OS_FILENAME(name, 0), &buf);
13338
13339  if(res != 0) {
13340    switch(errno) {
13341    case ENOENT: return C_SCHEME_FALSE;
13342    case EOVERFLOW: return C_truep(dir) ? C_SCHEME_FALSE : C_SCHEME_TRUE;
13343    case ENOTDIR: return C_SCHEME_FALSE;
13344    default: return C_fix(res);
13345    }
13346  }
13347
13348  switch(buf.st_mode & S_IFMT) {
13349  case S_IFDIR: return C_truep(file) ? C_SCHEME_FALSE : C_SCHEME_TRUE;
13350  default: return C_truep(dir) ? C_SCHEME_FALSE : C_SCHEME_TRUE;
13351  }
13352}
13353
13354
13355C_regparm C_word
13356C_i_pending_interrupt(C_word dummy)
13357{
13358  if(pending_interrupts_count > 0) {
13359    handling_interrupts = 1; /* Lock out further forced GCs until we're done */
13360    return C_fix(pending_interrupts[ --pending_interrupts_count ]);
13361  } else {
13362    handling_interrupts = 0; /* OK, can go on */
13363    return C_SCHEME_FALSE;
13364  }
13365}
13366
13367
13368/* random numbers, mostly lifted from
13369  https://github.com/jedisct1/libsodium/blob/master/src/libsodium/randombytes/sysrandom/randombytes_sysrandom.c
13370*/
13371
13372#ifdef __linux__
13373# include <sys/syscall.h>
13374#endif
13375
13376
13377#if !defined(_WIN32)
13378static C_word random_urandom(C_word buf, int count)
13379{
13380  static int fd = -1;
13381  int off = 0, r;
13382
13383  if(fd == -1) {
13384    fd = open("/dev/urandom", O_RDONLY);
13385
13386    if(fd == -1) return C_SCHEME_FALSE;
13387  }
13388
13389  while(count > 0) {
13390    r = read(fd, C_data_pointer(buf) + off, count);
13391
13392    if(r == -1) {
13393      if(errno != EINTR && errno != EAGAIN) return C_SCHEME_FALSE;
13394      else r = 0;
13395    }
13396
13397    count -= r;
13398    off += r;
13399   }
13400
13401  return C_SCHEME_TRUE;
13402}
13403#endif
13404
13405
13406C_word C_random_bytes(C_word buf, C_word size)
13407{
13408  int count = C_unfix(size);
13409  int r = 0;
13410  int off = 0;
13411
13412#if defined(__OpenBSD__) || defined(__FreeBSD__)
13413  arc4random_buf(C_data_pointer(buf), count);
13414#elif defined(SYS_getrandom) && defined(__NR_getrandom)
13415  static int use_urandom = 0;
13416
13417  if(use_urandom) return random_urandom(buf, count);
13418
13419  while(count > 0) {
13420    /* GRND_NONBLOCK = 0x0001 */
13421    r = syscall(SYS_getrandom, C_data_pointer(buf) + off, count, 1);
13422
13423    if(r == -1) {
13424      if(errno == ENOSYS) {
13425        use_urandom = 1;
13426        return random_urandom(buf, count);
13427      }
13428      else if(errno != EINTR) return C_SCHEME_FALSE;
13429      else r = 0;
13430    }
13431
13432    count -= r;
13433    off += r;
13434  }
13435#elif defined(_WIN32) && !defined(__CYGWIN__)
13436  typedef BOOLEAN (*func)(PVOID, ULONG);
13437  static func RtlGenRandom = NULL;
13438
13439  if(RtlGenRandom == NULL) {
13440     HMODULE mod = LoadLibrary("advapi32.dll");
13441
13442     if(mod == NULL) return C_SCHEME_FALSE;
13443
13444     if((RtlGenRandom = (func)GetProcAddress(mod, "SystemFunction036")) == NULL)
13445       return C_SCHEME_FALSE;
13446  }
13447
13448  if(!RtlGenRandom((PVOID)C_data_pointer(buf), (LONG)count))
13449    return C_SCHEME_FALSE;
13450#else
13451  return random_urandom(buf, count);
13452#endif
13453
13454  return C_SCHEME_TRUE;
13455}
13456
13457
13458/* WELL512 pseudo random number generator, see also:
13459   https://en.wikipedia.org/wiki/Well_equidistributed_long-period_linear
13460   http://lomont.org/Math/Papers/2008/Lomont_PRNG_2008.pdf
13461*/
13462
13463static C_uword random_word(void)
13464{
13465  C_uword a, b, c, d, r;
13466  a  = random_state[random_state_index];
13467  c  = random_state[(random_state_index+13)&15];
13468  b  = a^c^(a<<16)^(c<<15);
13469  c  = random_state[(random_state_index+9)&15];
13470  c ^= (c>>11);
13471  a  = random_state[random_state_index] = b^c;
13472  d  = a^((a<<5)&0xDA442D24UL);
13473  random_state_index = (random_state_index + 15)&15;
13474  a  = random_state[random_state_index];
13475  random_state[random_state_index] = a^b^d^(a<<2)^(b<<18)^(c<<28);
13476  r = random_state[random_state_index];
13477  return r;
13478}
13479
13480
13481static C_uword random_uniform(C_uword bound)
13482{
13483  C_uword r, min;
13484
13485  if (bound < 2) return 0;
13486
13487  min = (1U + ~bound) % bound; /* = 2**<wordsize> mod bound */
13488
13489  do r = random_word(); while (r < min);
13490
13491  /* r is now clamped to a set whose size mod upper_bound == 0
13492   * the worst case (2**<wordsize-1>+1) requires ~ 2 attempts */
13493
13494  return r % bound;
13495}
13496
13497
13498C_regparm C_word C_random_fixnum(C_word n)
13499{
13500  C_word nf;
13501
13502  if (!(n & C_FIXNUM_BIT))
13503    barf(C_BAD_ARGUMENT_TYPE_NO_FIXNUM_ERROR, "pseudo-random-integer", n);
13504
13505  nf = C_unfix(n);
13506
13507  if(nf < 0)
13508    barf(C_OUT_OF_BOUNDS_ERROR, "pseudo-random-integer", n, C_fix(0));
13509
13510  return C_fix(random_uniform(nf));
13511}
13512
13513
13514C_regparm C_word
13515C_s_a_u_i_random_int(C_word **ptr, C_word n, C_word rn)
13516{
13517  C_uword *start, *end;
13518
13519  if(C_bignum_negativep(rn))
13520    barf(C_OUT_OF_BOUNDS_ERROR, "pseudo-random-integer", rn, C_fix(0));
13521
13522  int len = integer_length_abs(rn);
13523  C_word size = C_fix(C_BIGNUM_BITS_TO_DIGITS(len));
13524  C_word result = C_allocate_scratch_bignum(ptr, size, C_SCHEME_FALSE, C_SCHEME_FALSE);
13525  C_uword *p;
13526  C_uword highest_word = C_bignum_digits(rn)[C_bignum_size(rn)-1];
13527  start = C_bignum_digits(result);
13528  end = start + C_bignum_size(result);
13529
13530  for(p = start; p < (end - 1); ++p) {
13531    *p = random_word();
13532    len -= sizeof(C_uword);
13533  }
13534
13535  *p = random_uniform(highest_word);
13536  return C_bignum_simplify(result);
13537}
13538
13539/*
13540 * C_a_i_random_real: Generate a stream of bits uniformly at random and
13541 * interpret it as the fractional part of the binary expansion of a
13542 * number in [0, 1], 0.00001010011111010100...; then round it.
13543 * More information on https://mumble.net/~campbell/2014/04/28/uniform-random-float
13544 */
13545
13546static inline C_u64 random64() {
13547#ifdef C_SIXTY_FOUR
13548    return random_word();
13549#else
13550    C_u64 v = 0;
13551    v |= ((C_u64) random_word()) << 32;
13552    v |= (C_u64) random_word();
13553    return v;
13554#endif
13555}
13556
13557#if defined(__GNUC__) && !defined(__TINYC__)
13558# define	clz64	__builtin_clzll
13559#else
13560/* https://en.wikipedia.org/wiki/Find_first_set#CLZ */
13561static const C_uchar clz_table_4bit[16] = { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
13562
13563int clz32(C_u32 x)
13564{
13565  int n;
13566  if ((x & 0xFFFF0000) == 0) {n  = 16; x <<= 16;} else {n = 0;}
13567  if ((x & 0xFF000000) == 0) {n +=  8; x <<=  8;}
13568  if ((x & 0xF0000000) == 0) {n +=  4; x <<=  4;}
13569  n += (int)clz_table_4bit[x >> (32-4)];
13570  return n;
13571}
13572
13573int clz64(C_u64 x)
13574{
13575    int y = clz32(x >> 32);
13576
13577    if(y == 32) return y + clz32(x);
13578
13579    return y;
13580}
13581#endif
13582
13583C_regparm C_word
13584C_a_i_random_real(C_word **ptr, C_word n) {
13585  int exponent = -64;
13586  uint64_t significand;
13587  unsigned shift;
13588
13589  while (C_unlikely((significand = random64()) == 0)) {
13590    exponent -= 64;
13591    if (C_unlikely(exponent < -1074))
13592      return 0;
13593  }
13594
13595  shift = clz64(significand);
13596  if (shift != 0) {
13597    exponent -= shift;
13598    significand <<= shift;
13599    significand |= (random64() >> (64 - shift));
13600  }
13601
13602  significand |= 1;
13603  return C_flonum(ptr, ldexp((double)significand, exponent));
13604}
13605
13606C_word C_set_random_seed(C_word buf, C_word n)
13607{
13608  int i, nsu = C_unfix(n) / sizeof(C_uword);
13609  int off = 0;
13610
13611  for(i = 0; i < (C_RANDOM_STATE_SIZE / sizeof(C_uword)); ++i) {
13612    if(off >= nsu) off = 0;
13613
13614    random_state[ i ] = *((C_uword *)C_data_pointer(buf) + off);
13615    ++off;
13616  }
13617
13618  random_state_index = 0;
13619  return C_SCHEME_FALSE;
13620}
13621
13622C_word C_a_extract_struct_2(C_word **ptr, size_t sz, void *sp)
13623{
13624    C_word bv = C_scratch_alloc(C_SIZEOF_BYTEVECTOR(sz));
13625    C_word w;
13626    C_block_header_init(bv, C_make_header(C_BYTEVECTOR_TYPE, sz));
13627    C_memcpy(C_data_pointer(bv), sp, sz);
13628    w = C_a_i_record2(ptr, 2, C_SCHEME_FALSE, bv);
13629    return w;
13630}
13631
13632C_regparm C_word C_i_setenv(C_word var, C_word val)
13633{
13634#if defined(_WIN32) && !defined(__CYGWIN__)
13635	C_WCHAR *wvar = C_utf16(var,0);
13636	C_WCHAR *wval = val == C_SCHEME_FALSE ? NULL : C_utf16(val, 1);
13637	SetEnvironmentVariableW(wvar, wval);
13638	return C_fix(0);
13639#elif defined(HAVE_SETENV)
13640	C_char *cvar = C_c_string(var);
13641	if(val == C_SCHEME_FALSE) unsetenv(C_c_string(var));
13642	else setenv(C_c_string(var), C_c_string(val), 1);
13643	return(C_fix(0));
13644#else
13645	char *sx = C_c_string(C_var),
13646	*sy = (val == C_SCHEME_FALSE ? "" : C_c_string(val));
13647	int n1 = C_strlen(sx), n2 = C_strlen(sy);
13648	int buf_len = n1 + n2 + 2;
13649	char *buf = (char *)C_malloc(buf_len);
13650	if(buf == NULL) return(C_fix(0));
13651	else {
13652		C_strlcpy(buf, sx, buf_len);
13653		C_strlcat(buf, "=", buf_len);
13654		C_strlcat(buf, sy, buf_len);
13655		return(C_fix(putenv(buf)));
13656	}
13657#endif
13658}
13659
13660C_char *C_getenv(C_word var)
13661{
13662#if defined(_WIN32) && !defined(__CYGWIN__)
13663	C_WCHAR *wvar = C_utf16(var, 0);
13664	if(GetEnvironmentVariableW(wvar, (C_WCHAR *)buffer, STRING_BUFFER_SIZE) ==
13665		0) return NULL;
13666	return C_utf8((C_WCHAR *)buffer);
13667#else
13668	return getenv(C_c_string(var));
13669#endif
13670}
13671
13672#ifdef HAVE_CRT_EXTERNS_H
13673# include <crt_externs.h>
13674# define environ (*_NSGetEnviron())
13675#elif !defined(_WIN32) || defined(__CYGWIN__)
13676extern char **environ;
13677#endif
13678
13679C_char *C_getenventry(int i)
13680{
13681#if defined(_WIN32) && !defined(__CYGWIN__)
13682	C_WCHAR *env = GetEnvironmentStringsW();
13683	C_WCHAR *p = env;
13684	while(i--) {
13685		while(*p != 0) ++p;
13686		if(*(++p) == 0) return NULL;
13687	}
13688	C_char *s = C_strdup(C_utf8(p));
13689	FreeEnvironmentStringsW(env);
13690	return s;
13691#else
13692	return environ[ i ] == NULL ? NULL : C_strdup(environ[ i ]);
13693#endif
13694}
Trap