2053 lines
67 KiB
C
2053 lines
67 KiB
C
|
/* prim5.c
|
||
|
* Copyright 1984-2017 Cisco Systems, Inc.
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
#include "system.h"
|
||
|
#include "sort.h"
|
||
|
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <limits.h>
|
||
|
#include <ctype.h>
|
||
|
#include <math.h>
|
||
|
|
||
|
/* locally defined functions */
|
||
|
static INT s_errno(void);
|
||
|
static iptr s_addr_in_heap(uptr x);
|
||
|
static iptr s_ptr_in_heap(ptr x);
|
||
|
static ptr s_generation(ptr x);
|
||
|
static iptr s_fxmul(iptr x, iptr y);
|
||
|
static iptr s_fxdiv(iptr x, iptr y);
|
||
|
static ptr s_trunc_rem(ptr x, ptr y);
|
||
|
static ptr s_fltofx(ptr x);
|
||
|
static ptr s_weak_pairp(ptr p);
|
||
|
static ptr s_ephemeron_cons(ptr car, ptr cdr);
|
||
|
static ptr s_ephemeron_pairp(ptr p);
|
||
|
static ptr s_oblist(void);
|
||
|
static ptr s_bigoddp(ptr n);
|
||
|
static ptr s_float(ptr x);
|
||
|
static ptr s_decode_float(ptr x);
|
||
|
#ifdef segment_t2_bits
|
||
|
static void s_show_info(FILE *out);
|
||
|
#endif
|
||
|
static void s_show_chunks(FILE *out, ptr sorted_chunks);
|
||
|
static ptr sort_chunks(ptr ls, uptr n);
|
||
|
static ptr merge_chunks(ptr ls1, ptr ls2);
|
||
|
static ptr sorted_chunk_list(void);
|
||
|
static void s_showalloc(IBOOL show_dump, const char *outfn);
|
||
|
static ptr s_system(const char *s);
|
||
|
static ptr s_process(char *s, IBOOL stderrp);
|
||
|
static I32 s_chdir(const char *inpath);
|
||
|
static char *s_getwd(void);
|
||
|
static ptr s_set_code_byte(ptr p, ptr n, ptr x);
|
||
|
static ptr s_set_code_word(ptr p, ptr n, ptr x);
|
||
|
static ptr s_set_code_long(ptr p, ptr n, ptr x);
|
||
|
static void s_set_code_long2(ptr p, ptr n, ptr h, ptr l);
|
||
|
static ptr s_set_code_quad(ptr p, ptr n, ptr x);
|
||
|
static ptr s_set_reloc(ptr p, ptr n, ptr e);
|
||
|
static ptr s_flush_instruction_cache(void);
|
||
|
static ptr s_make_code(iptr flags, iptr free, ptr name, ptr arity_mark, iptr n, ptr info, ptr pinfos);
|
||
|
static ptr s_make_reloc_table(ptr codeobj, ptr n);
|
||
|
static ptr s_make_closure(ptr offset, ptr codeobj);
|
||
|
static ptr s_fxrandom(ptr n);
|
||
|
static ptr s_flrandom(ptr x);
|
||
|
static U32 s_random_seed(void);
|
||
|
static void s_set_random_seed(U32 x);
|
||
|
static ptr s_intern(ptr x);
|
||
|
static ptr s_intern2(ptr x, ptr n);
|
||
|
static ptr s_strings_to_gensym(ptr pname_str, ptr uname_str);
|
||
|
static ptr s_intern3(ptr x, ptr n, ptr m);
|
||
|
static ptr s_delete_file(const char *inpath);
|
||
|
static ptr s_delete_directory(const char *inpath);
|
||
|
static ptr s_rename_file(const char *inpath1, const char *inpath2);
|
||
|
static ptr s_mkdir(const char *inpath, INT mode);
|
||
|
static ptr s_chmod(const char *inpath, INT mode);
|
||
|
static ptr s_getmod(const char *inpath, IBOOL followp);
|
||
|
static ptr s_path_atime(const char *inpath, IBOOL followp);
|
||
|
static ptr s_path_ctime(const char *inpath, IBOOL followp);
|
||
|
static ptr s_path_mtime(const char *inpath, IBOOL followp);
|
||
|
static ptr s_fd_atime(INT fd);
|
||
|
static ptr s_fd_ctime(INT fd);
|
||
|
static ptr s_fd_mtime(INT fd);
|
||
|
static IBOOL s_fd_regularp(INT fd);
|
||
|
static void s_nanosleep(ptr sec, ptr nsec);
|
||
|
static ptr s_set_collect_trip_bytes(ptr n);
|
||
|
static void c_exit(I32 status);
|
||
|
static ptr s_get_reloc(ptr co);
|
||
|
#ifdef PTHREADS
|
||
|
static s_thread_rv_t s_backdoor_thread_start(void *p);
|
||
|
static iptr s_backdoor_thread(ptr p);
|
||
|
static ptr s_threads(void);
|
||
|
static void s_mutex_acquire(scheme_mutex_t *m);
|
||
|
static ptr s_mutex_acquire_noblock(scheme_mutex_t *m);
|
||
|
static void s_condition_broadcast(s_thread_cond_t *c);
|
||
|
static void s_condition_signal(s_thread_cond_t *c);
|
||
|
#endif
|
||
|
static void s_byte_copy(ptr src, iptr srcoff, ptr dst, iptr dstoff, iptr cnt);
|
||
|
static void s_ptr_copy(ptr src, iptr srcoff, ptr dst, iptr dstoff, iptr cnt);
|
||
|
static ptr s_tlv(ptr x);
|
||
|
static void s_stlv(ptr x, ptr v);
|
||
|
static void s_test_schlib(void);
|
||
|
static void s_breakhere(ptr x);
|
||
|
static IBOOL s_interactivep(void);
|
||
|
static IBOOL s_same_devicep(INT fd1, INT fd2);
|
||
|
static uptr s_malloc(iptr n);
|
||
|
static void s_free(uptr n);
|
||
|
#ifdef FEATURE_ICONV
|
||
|
static ptr s_iconv_open(const char *tocode, const char *fromcode);
|
||
|
static void s_iconv_close(uptr cd);
|
||
|
static ptr s_iconv_from_string(uptr cd, ptr in, uptr i, uptr iend, ptr out, uptr o, uptr oend);
|
||
|
static ptr s_iconv_to_string(uptr cd, ptr in, uptr i, uptr iend, ptr out, uptr o, uptr oend);
|
||
|
#endif
|
||
|
#ifdef WIN32
|
||
|
static ptr s_multibytetowidechar(unsigned cp, ptr inbv);
|
||
|
static ptr s_widechartomultibyte(unsigned cp, ptr inbv);
|
||
|
#endif
|
||
|
static ptr s_profile_counters(void);
|
||
|
static ptr s_profile_release_counters(void);
|
||
|
|
||
|
#define require(test,who,msg,arg) if (!(test)) S_error1(who, msg, arg)
|
||
|
|
||
|
ptr S_strerror(INT errnum) {
|
||
|
ptr p; char *msg;
|
||
|
|
||
|
tc_mutex_acquire()
|
||
|
#ifdef WIN32
|
||
|
msg = Swide_to_utf8(_wcserror(errnum));
|
||
|
if (msg == NULL)
|
||
|
p = Sfalse;
|
||
|
else {
|
||
|
p = Sstring_utf8(msg, -1);
|
||
|
free(msg);
|
||
|
}
|
||
|
#else
|
||
|
p = (msg = strerror(errnum)) == NULL ? Sfalse : Sstring_utf8(msg, -1);
|
||
|
#endif
|
||
|
tc_mutex_release()
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
static INT s_errno(void) {
|
||
|
return errno;
|
||
|
}
|
||
|
|
||
|
static iptr s_addr_in_heap(uptr x) {
|
||
|
return MaybeSegInfo(addr_get_segment(x)) != NULL;
|
||
|
}
|
||
|
|
||
|
static iptr s_ptr_in_heap(ptr x) {
|
||
|
return MaybeSegInfo(ptr_get_segment(x)) != NULL;
|
||
|
}
|
||
|
|
||
|
static ptr s_generation(ptr x) {
|
||
|
seginfo *si = MaybeSegInfo(ptr_get_segment(x));
|
||
|
return si == NULL ? Sfalse : FIX(si->generation);
|
||
|
}
|
||
|
|
||
|
static iptr s_fxmul(iptr x, iptr y) {
|
||
|
return x * y;
|
||
|
}
|
||
|
|
||
|
static iptr s_fxdiv(iptr x, iptr y) {
|
||
|
return x / y;
|
||
|
}
|
||
|
|
||
|
static ptr s_trunc_rem(ptr x, ptr y) {
|
||
|
ptr q, r;
|
||
|
S_trunc_rem(get_thread_context(), x, y, &q, &r);
|
||
|
return Scons(q, r);
|
||
|
}
|
||
|
|
||
|
static ptr s_fltofx(ptr x) {
|
||
|
return FIX((iptr)FLODAT(x));
|
||
|
}
|
||
|
|
||
|
static ptr s_weak_pairp(ptr p) {
|
||
|
seginfo *si;
|
||
|
return Spairp(p) && (si = MaybeSegInfo(ptr_get_segment(p))) != NULL && (si->space & ~space_locked) == space_weakpair ? Strue : Sfalse;
|
||
|
}
|
||
|
|
||
|
static ptr s_ephemeron_cons(ptr car, ptr cdr) {
|
||
|
ptr p;
|
||
|
|
||
|
tc_mutex_acquire()
|
||
|
p = S_cons_in(space_ephemeron, 0, car, cdr);
|
||
|
tc_mutex_release()
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
static ptr s_ephemeron_pairp(ptr p) {
|
||
|
seginfo *si;
|
||
|
return Spairp(p) && (si = MaybeSegInfo(ptr_get_segment(p))) != NULL && (si->space & ~space_locked) == space_ephemeron ? Strue : Sfalse;
|
||
|
}
|
||
|
|
||
|
static ptr s_oblist(void) {
|
||
|
ptr ls = Snil;
|
||
|
iptr idx = S_G.oblist_length;
|
||
|
bucket *b;
|
||
|
|
||
|
while (idx-- != 0) {
|
||
|
for (b = S_G.oblist[idx]; b != NULL; b = b->next) {
|
||
|
ls = Scons(b->sym, ls);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ls;
|
||
|
}
|
||
|
|
||
|
static ptr s_bigoddp(ptr n) {
|
||
|
return Sboolean(BIGIT(n, BIGLEN(n) - 1) & 1); /* last bigit */;
|
||
|
}
|
||
|
|
||
|
static ptr s_float(ptr x) {
|
||
|
return Sflonum(S_floatify(x));
|
||
|
}
|
||
|
|
||
|
static ptr s_decode_float(ptr x) {
|
||
|
require(Sflonump(x),"decode-float","~s is not a float",x);
|
||
|
return S_decode_float(FLODAT(x));
|
||
|
}
|
||
|
|
||
|
#define FMTBUFSIZE 120
|
||
|
#define CHUNKADDRLT(x, y) (((chunkinfo *)(Scar(x)))->addr < ((chunkinfo *)(Scar(y)))->addr)
|
||
|
mkmergesort(sort_chunks, merge_chunks, ptr, Snil, CHUNKADDRLT, INITCDR)
|
||
|
|
||
|
static ptr sorted_chunk_list(void) {
|
||
|
chunkinfo *chunk; INT i, n = 0; ptr ls = Snil;
|
||
|
|
||
|
for (i = PARTIAL_CHUNK_POOLS; i >= -1; i -= 1) {
|
||
|
for (chunk = (i == -1) ? S_chunks_full : S_chunks[i]; chunk != NULL; chunk = chunk->next) {
|
||
|
ls = Scons(chunk, ls);
|
||
|
n += 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return sort_chunks(ls, n);
|
||
|
}
|
||
|
|
||
|
#ifdef segment_t2_bits
|
||
|
static void s_show_info(FILE *out) {
|
||
|
void *max_addr = 0;
|
||
|
INT addrwidth;
|
||
|
const char *addrtitle = "address";
|
||
|
char fmtbuf[FMTBUFSIZE];
|
||
|
uptr i2;
|
||
|
#ifdef segment_t3_bits
|
||
|
INT byteswidth;
|
||
|
uptr i3;
|
||
|
for (i3 = 0; i3 < SEGMENT_T3_SIZE; i3 += 1) {
|
||
|
t2table *t2t = S_segment_info[i3];
|
||
|
if (t2t != NULL) {
|
||
|
if ((void *)t2t > max_addr) max_addr = (void *)t2t;
|
||
|
for (i2 = 0; i2 < SEGMENT_T2_SIZE; i2 += 1) {
|
||
|
t1table *t1t = t2t->t2[i2];
|
||
|
if (t1t != NULL) {
|
||
|
if ((void *)t1t > max_addr) max_addr = (void *)t1t;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
addrwidth = snprintf(fmtbuf, FMTBUFSIZE, "%#tx", (ptrdiff_t)max_addr);
|
||
|
if (addrwidth < (INT)strlen(addrtitle)) addrwidth = (INT)strlen(addrtitle);
|
||
|
byteswidth = snprintf(fmtbuf, FMTBUFSIZE, "%#tx", (ptrdiff_t)(sizeof(t1table) > sizeof(t2table) ? sizeof(t1table) : sizeof(t2table)));
|
||
|
snprintf(fmtbuf, FMTBUFSIZE, "%%s %%-%ds %%-%ds\n\n", addrwidth, byteswidth);
|
||
|
fprintf(out, fmtbuf, "level", addrtitle, "bytes");
|
||
|
snprintf(fmtbuf, FMTBUFSIZE, "%%-5d %%#0%dtx %%#0%dtx\n", addrwidth, byteswidth);
|
||
|
for (i3 = 0; i3 < SEGMENT_T3_SIZE; i3 += 1) {
|
||
|
t2table *t2t = S_segment_info[i3];
|
||
|
if (t2t != NULL) {
|
||
|
fprintf(out, fmtbuf, 2, t2t, sizeof(t2table));
|
||
|
for (i2 = 0; i2 < SEGMENT_T2_SIZE; i2 += 1) {
|
||
|
t1table *t1t = t2t->t2[i2];
|
||
|
if (t1t != NULL) {
|
||
|
fprintf(out, fmtbuf, 1, (ptrdiff_t)t1t, (ptrdiff_t)sizeof(t1table));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#else
|
||
|
for (i2 = 0; i2 < SEGMENT_T2_SIZE; i2 += 1) {
|
||
|
t1table *t1t = S_segment_info[i2];
|
||
|
if (t1t != NULL) {
|
||
|
if ((void *)t1t > max_addr) max_addr = (void *)t1t;
|
||
|
}
|
||
|
}
|
||
|
addrwidth = 1 + snprintf(fmtbuf, FMTBUFSIZE, "%#tx", (ptrdiff_t)max_addr);
|
||
|
if (addrwidth < (INT)strlen(addrtitle) + 1) addrwidth = (INT)strlen(addrtitle) + 1;
|
||
|
snprintf(fmtbuf, FMTBUFSIZE, "%%s %%-%ds %%s\n\n", addrwidth);
|
||
|
fprintf(out, fmtbuf, "level", addrtitle, "bytes");
|
||
|
snprintf(fmtbuf, FMTBUFSIZE, "%%-5d %%#0%dtx %%#tx\n", (ptrdiff_t)addrwidth);
|
||
|
for (i2 = 0; i2 < SEGMENT_T2_SIZE; i2 += 1) {
|
||
|
t1table *t1t = S_segment_info[i2];
|
||
|
if (t1t != NULL) {
|
||
|
fprintf(out, fmtbuf, 1, (ptrdiff_t)t1t, (ptrdiff_t)sizeof(t1table));
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static void s_show_chunks(FILE *out, ptr sorted_chunks) {
|
||
|
char fmtbuf[FMTBUFSIZE];
|
||
|
chunkinfo *chunk;
|
||
|
void *max_addr = 0;
|
||
|
void *max_header_addr = 0;
|
||
|
iptr max_segs = 0;
|
||
|
INT addrwidth, byteswidth, headeraddrwidth, headerbyteswidth, segswidth, headerwidth;
|
||
|
const char *addrtitle = "address", *bytestitle = "bytes", *headertitle = "(+ header)";
|
||
|
ptr ls;
|
||
|
|
||
|
for (ls = sorted_chunks; ls != Snil; ls = Scdr(ls)) {
|
||
|
chunk = Scar(ls);
|
||
|
max_addr = chunk->addr;
|
||
|
if (chunk->segs > max_segs) max_segs = chunk->segs;
|
||
|
if ((void *)chunk > max_header_addr) max_header_addr = (void *)chunk;
|
||
|
}
|
||
|
|
||
|
addrwidth = (INT)snprintf(fmtbuf, FMTBUFSIZE, "%#tx", (ptrdiff_t)max_addr);
|
||
|
if (addrwidth < (INT)strlen(addrtitle)) addrwidth = (INT)strlen(addrtitle);
|
||
|
byteswidth = (INT)snprintf(fmtbuf, FMTBUFSIZE, "%#tx", (ptrdiff_t)(max_segs * bytes_per_segment));
|
||
|
if (byteswidth < (INT)strlen(bytestitle)) byteswidth = (INT)strlen(bytestitle);
|
||
|
headerbyteswidth = (INT)snprintf(fmtbuf, FMTBUFSIZE, "%#tx", (ptrdiff_t)(sizeof(chunkinfo) + sizeof(seginfo) * max_segs));
|
||
|
headeraddrwidth = (INT)snprintf(fmtbuf, FMTBUFSIZE, "%#tx", (ptrdiff_t)max_header_addr);
|
||
|
segswidth = (INT)snprintf(fmtbuf, FMTBUFSIZE, "%td", (ptrdiff_t)max_segs);
|
||
|
headerwidth = headerbyteswidth + headeraddrwidth + 13;
|
||
|
|
||
|
snprintf(fmtbuf, FMTBUFSIZE, "%%-%ds %%-%ds %%-%ds %%s\n\n", addrwidth, byteswidth, headerwidth);
|
||
|
fprintf(out, fmtbuf, addrtitle, bytestitle, headertitle, "segments used");
|
||
|
snprintf(fmtbuf, FMTBUFSIZE, "%%#0%dtx %%#0%dtx (+ %%#0%dtx bytes @ %%#0%dtx) %%%dtd of %%%dtd\n",
|
||
|
addrwidth, byteswidth, headerbyteswidth, headeraddrwidth, segswidth, segswidth);
|
||
|
for (ls = sorted_chunks; ls != Snil; ls = Scdr(ls)) {
|
||
|
chunk = Scar(ls);
|
||
|
fprintf(out, fmtbuf, (ptrdiff_t)chunk->addr, (ptrdiff_t)chunk->bytes,
|
||
|
(ptrdiff_t)(sizeof(chunkinfo) + sizeof(seginfo) * chunk->segs),
|
||
|
(ptrdiff_t)chunk, (ptrdiff_t)chunk->nused_segs, (ptrdiff_t)chunk->segs);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#define space_bogus (max_space + 1)
|
||
|
#define space_total (space_bogus + 1)
|
||
|
#define generation_total (static_generation + 1)
|
||
|
#define INCRGEN(g) (g = g == S_G.max_nonstatic_generation ? static_generation : g+1)
|
||
|
static void s_showalloc(IBOOL show_dump, const char *outfn) {
|
||
|
FILE *out;
|
||
|
iptr count[generation_total+1][space_total+1];
|
||
|
uptr bytes[generation_total+1][space_total+1];
|
||
|
int i, column_size[generation_total+1];
|
||
|
char fmtbuf[FMTBUFSIZE];
|
||
|
static char *spacename[space_total+1] = { alloc_space_names, "bogus", "total" };
|
||
|
static char spacechar[space_total+1] = { alloc_space_chars, '?', 't' };
|
||
|
chunkinfo *chunk; seginfo *si; ISPC s; IGEN g;
|
||
|
ptr sorted_chunks;
|
||
|
|
||
|
tc_mutex_acquire()
|
||
|
|
||
|
if (outfn == NULL) {
|
||
|
out = stderr;
|
||
|
} else {
|
||
|
#ifdef WIN32
|
||
|
wchar_t *outfnw = Sutf8_to_wide(outfn);
|
||
|
out = _wfopen(outfnw, L"w");
|
||
|
free(outfnw);
|
||
|
#else
|
||
|
out = fopen(outfn, "w");
|
||
|
#endif
|
||
|
if (out == NULL) {
|
||
|
ptr msg = S_strerror(errno);
|
||
|
if (msg != Sfalse) {
|
||
|
tc_mutex_release()
|
||
|
S_error2("fopen", "open of ~s failed: ~a", Sstring_utf8(outfn, -1), msg);
|
||
|
} else {
|
||
|
tc_mutex_release()
|
||
|
S_error1("fopen", "open of ~s failed", Sstring_utf8(outfn, -1));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
for (g = 0; g <= generation_total; INCRGEN(g))
|
||
|
for (s = 0; s <= space_total; s++)
|
||
|
count[g][s] = bytes[g][s] = 0;
|
||
|
|
||
|
for (g = 0; g <= static_generation; INCRGEN(g)) {
|
||
|
for (s = 0; s <= max_real_space; s++) {
|
||
|
/* add in bytes previously recorded */
|
||
|
bytes[g][s] += S_G.bytes_of_space[g][s];
|
||
|
/* add in bytes in active segments */
|
||
|
if (S_G.next_loc[g][s] != FIX(0))
|
||
|
bytes[g][s] += (char *)S_G.next_loc[g][s] - (char *)S_G.base_loc[g][s];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (g = 0; g <= static_generation; INCRGEN(g)) {
|
||
|
for (s = 0; s <= max_real_space; s++) {
|
||
|
for (si = S_G.occupied_segments[g][s]; si != NULL; si = si->next) {
|
||
|
count[g][s] += 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (g = 0; g < generation_total; INCRGEN(g)) {
|
||
|
for (s = 0; s < space_total; s++) {
|
||
|
count[g][space_total] += count[g][s];
|
||
|
count[generation_total][s] += count[g][s];
|
||
|
count[generation_total][space_total] += count[g][s];
|
||
|
bytes[g][space_total] += bytes[g][s];
|
||
|
bytes[generation_total][s] += bytes[g][s];
|
||
|
bytes[generation_total][space_total] += bytes[g][s];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (g = 0; g <= generation_total; INCRGEN(g)) {
|
||
|
if (count[g][space_total] != 0) {
|
||
|
int n = 1 + snprintf(fmtbuf, FMTBUFSIZE, "%td", (ptrdiff_t)count[g][space_total]);
|
||
|
column_size[g] = n < 8 ? 8 : n;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fprintf(out, "Segments per space & generation:\n\n");
|
||
|
fprintf(out, "%8s", "");
|
||
|
for (g = 0; g <= generation_total; INCRGEN(g)) {
|
||
|
if (count[g][space_total] != 0) {
|
||
|
if (g == generation_total) {
|
||
|
/* coverity[uninit_use] */
|
||
|
snprintf(fmtbuf, FMTBUFSIZE, "%%%ds", column_size[g]);
|
||
|
fprintf(out, fmtbuf, "total");
|
||
|
} else if (g == static_generation) {
|
||
|
/* coverity[uninit_use] */
|
||
|
snprintf(fmtbuf, FMTBUFSIZE, "%%%ds", column_size[g]);
|
||
|
fprintf(out, fmtbuf, "static");
|
||
|
} else {
|
||
|
/* coverity[uninit_use] */
|
||
|
snprintf(fmtbuf, FMTBUFSIZE, "%%%dd", column_size[g]);
|
||
|
fprintf(out, fmtbuf, g);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
fprintf(out, "\n");
|
||
|
for (s = 0; s <= space_total; s++) {
|
||
|
if (s != space_empty) {
|
||
|
if (count[generation_total][s] != 0) {
|
||
|
fprintf(out, "%7s:", spacename[s]);
|
||
|
for (g = 0; g <= generation_total; INCRGEN(g)) {
|
||
|
if (count[g][space_total] != 0) {
|
||
|
/* coverity[uninit_use] */
|
||
|
snprintf(fmtbuf, FMTBUFSIZE, "%%%dtd", column_size[g]);
|
||
|
fprintf(out, fmtbuf, (ptrdiff_t)(count[g][s]));
|
||
|
}
|
||
|
}
|
||
|
fprintf(out, "\n");
|
||
|
fprintf(out, "%8s", "");
|
||
|
for (g = 0; g <= generation_total; INCRGEN(g)) {
|
||
|
if (count[g][space_total] != 0) {
|
||
|
if (count[g][s] != 0 && s <= max_real_space) {
|
||
|
/* coverity[uninit_use] */
|
||
|
snprintf(fmtbuf, FMTBUFSIZE, "%%%dd%%%%", column_size[g] - 1);
|
||
|
fprintf(out, fmtbuf,
|
||
|
(int)(((double)bytes[g][s] /
|
||
|
((double)count[g][s] * bytes_per_segment)) * 100.0));
|
||
|
} else {
|
||
|
/* coverity[uninit_use] */
|
||
|
snprintf(fmtbuf, FMTBUFSIZE, "%%%ds", column_size[g]);
|
||
|
fprintf(out, fmtbuf, "");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
fprintf(out, "\n");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fprintf(out, "segment size = %#tx bytes. percentages show the portion actually occupied.\n", (ptrdiff_t)bytes_per_segment);
|
||
|
fprintf(out, "%td segments are presently reserved for future allocation or collection.\n", (ptrdiff_t)S_G.number_of_empty_segments);
|
||
|
|
||
|
fprintf(out, "\nMemory chunks obtained and not returned to the O/S:\n\n");
|
||
|
sorted_chunks = sorted_chunk_list();
|
||
|
s_show_chunks(out, sorted_chunks);
|
||
|
|
||
|
#ifdef segment_t2_bits
|
||
|
fprintf(out, "\nDynamic memory occupied by segment info table:\n\n");
|
||
|
s_show_info(out);
|
||
|
#endif
|
||
|
|
||
|
fprintf(out, "\nAdditional memory might be used by C libraries and programs in the\nsame address space.\n");
|
||
|
|
||
|
if (show_dump) {
|
||
|
iptr max_seg = 0;
|
||
|
int segwidth, segsperline;
|
||
|
iptr next_base = 0;
|
||
|
int segsprinted = 0;
|
||
|
char spaceline[100], genline[100];
|
||
|
ptr ls;
|
||
|
|
||
|
for (ls = sorted_chunks; ls != Snil; ls = Scdr(ls)) {
|
||
|
iptr last_seg;
|
||
|
chunk = Scar(ls);
|
||
|
last_seg = chunk->base + chunk->segs;
|
||
|
if (last_seg > max_seg) max_seg = last_seg;
|
||
|
}
|
||
|
|
||
|
segwidth = snprintf(fmtbuf, FMTBUFSIZE, "%#tx ", (ptrdiff_t)max_seg);
|
||
|
segsperline = (99 - segwidth) & ~0xf;
|
||
|
|
||
|
snprintf(fmtbuf, FMTBUFSIZE, " %%-%ds", segwidth);
|
||
|
snprintf(genline, 100, fmtbuf, "");
|
||
|
|
||
|
fprintf(out, "\nMap of occupied segments:\n");
|
||
|
for (ls = sorted_chunks; ls != Snil; ls = Scdr(ls)) {
|
||
|
seginfo *si; ISPC real_s;
|
||
|
|
||
|
chunk = Scar(ls);
|
||
|
|
||
|
if (chunk->base != next_base && segsprinted != 0) {
|
||
|
for (;;) {
|
||
|
if (segsprinted == segsperline) {
|
||
|
fprintf(out, "\n%s", spaceline);
|
||
|
fprintf(out, "\n%s", genline);
|
||
|
break;
|
||
|
}
|
||
|
if (next_base == chunk->base) break;
|
||
|
spaceline[segwidth+segsprinted] = ' ';
|
||
|
genline[segwidth+segsprinted] = ' ';
|
||
|
segsprinted += 1;
|
||
|
next_base += 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (chunk->base > next_base && next_base != 0) {
|
||
|
fprintf(out, "\n-------- skipping %td segments --------", (ptrdiff_t)(chunk->base - next_base));
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < chunk->segs; i += 1) {
|
||
|
if (segsprinted >= segsperline) segsprinted = 0;
|
||
|
|
||
|
if (segsprinted == 0) {
|
||
|
if (i != 0) {
|
||
|
fprintf(out, "\n%s", spaceline);
|
||
|
fprintf(out, "\n%s", genline);
|
||
|
}
|
||
|
snprintf(fmtbuf, FMTBUFSIZE, "%%#0%dtx ", segwidth - 1);
|
||
|
snprintf(spaceline, 100, fmtbuf, (ptrdiff_t)(chunk->base + i));
|
||
|
segsprinted = 0;
|
||
|
}
|
||
|
|
||
|
si = &chunk->sis[i];
|
||
|
real_s = si->space;
|
||
|
s = real_s & ~(space_locked | space_old);
|
||
|
if (s < 0 || s > max_space) s = space_bogus;
|
||
|
spaceline[segwidth+segsprinted] =
|
||
|
real_s & (space_locked | space_old) ? toupper(spacechar[s]) : spacechar[s];
|
||
|
|
||
|
g = si->generation;
|
||
|
genline[segwidth+segsprinted] =
|
||
|
(s == space_empty) ? '.' :
|
||
|
(g < 10) ? '0' + g :
|
||
|
(g < 36) ? 'A' + g - 10 :
|
||
|
(g == static_generation) ? '*' : '+';
|
||
|
segsprinted += 1;
|
||
|
}
|
||
|
next_base = chunk->base + chunk->segs;
|
||
|
}
|
||
|
|
||
|
if (segsprinted != 0) {
|
||
|
spaceline[segwidth+segsprinted] = 0;
|
||
|
genline[segwidth+segsprinted] = 0;
|
||
|
fprintf(out, "\n%s", spaceline);
|
||
|
fprintf(out, "\n%s", genline);
|
||
|
}
|
||
|
|
||
|
fprintf(out, "\n\nSpaces:");
|
||
|
for (s = 0; s < space_total; s += 1)
|
||
|
fprintf(out, "%s%c = %s", s % 5 == 0 ? "\n " : "\t",
|
||
|
spacechar[s], spacename[s]);
|
||
|
fprintf(out, "\n\nGenerations:\n 0-9: 0<=g<=9; A-Z: 10<=g<=35; +: g>=36; *: g=static; .: empty\n\n");
|
||
|
}
|
||
|
|
||
|
if (outfn == NULL) {
|
||
|
fflush(out);
|
||
|
} else {
|
||
|
fclose(out);
|
||
|
}
|
||
|
|
||
|
tc_mutex_release()
|
||
|
}
|
||
|
|
||
|
#include <signal.h>
|
||
|
#ifdef WIN32
|
||
|
#include <io.h>
|
||
|
#include <process.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <direct.h>
|
||
|
#include <malloc.h>
|
||
|
#else /* WIN32 */
|
||
|
#include <sys/param.h>
|
||
|
#include <sys/wait.h>
|
||
|
#endif /* WIN32 */
|
||
|
|
||
|
static ptr s_system(const char *s) {
|
||
|
INT status;
|
||
|
#ifdef PTHREADS
|
||
|
ptr tc = get_thread_context();
|
||
|
#endif
|
||
|
|
||
|
#ifdef PTHREADS
|
||
|
if (DISABLECOUNT(tc) == FIX(0)) deactivate_thread(tc);
|
||
|
#endif
|
||
|
status = SYSTEM(s);
|
||
|
#ifdef PTHREADS
|
||
|
if (DISABLECOUNT(tc) == FIX(0)) reactivate_thread(tc);
|
||
|
#endif
|
||
|
|
||
|
if ((status == -1) && (errno != 0)) {
|
||
|
ptr msg = S_strerror(errno);
|
||
|
|
||
|
if (msg != Sfalse)
|
||
|
S_error1("system", "~a", msg);
|
||
|
else
|
||
|
S_error("system", "subprocess execution failed");
|
||
|
}
|
||
|
|
||
|
#ifdef WIN32
|
||
|
return Sinteger(status);
|
||
|
#else
|
||
|
if WIFEXITED(status) return Sinteger(WEXITSTATUS(status));
|
||
|
if WIFSIGNALED(status) return Sinteger(-WTERMSIG(status));
|
||
|
S_error("system", "cannot determine subprocess exit status");
|
||
|
return 0 /* not reached */;
|
||
|
#endif /* WIN32 */
|
||
|
}
|
||
|
|
||
|
static ptr s_process(char *s, IBOOL stderrp) {
|
||
|
INT ifd = -1, ofd = -1, efd = -1, child = -1;
|
||
|
|
||
|
#ifdef WIN32
|
||
|
HANDLE hToRead, hToWrite, hFromRead, hFromWrite, hFromReadErr, hFromWriteErr, hProcess;
|
||
|
STARTUPINFOW si = {0};
|
||
|
PROCESS_INFORMATION pi;
|
||
|
char *comspec;
|
||
|
char *buffer;
|
||
|
wchar_t* bufferw;
|
||
|
|
||
|
/* Create non-inheritable pipes, important to eliminate zombee children
|
||
|
* when the parent sides are closed. */
|
||
|
if (!CreatePipe(&hToRead, &hToWrite, NULL, 0))
|
||
|
S_error("process", "cannot open pipes");
|
||
|
if (!CreatePipe(&hFromRead, &hFromWrite, NULL, 0)) {
|
||
|
CloseHandle(hToRead);
|
||
|
CloseHandle(hToWrite);
|
||
|
S_error("process", "cannot open pipes");
|
||
|
}
|
||
|
if (stderrp && !CreatePipe(&hFromReadErr, &hFromWriteErr, NULL, 0)) {
|
||
|
CloseHandle(hToRead);
|
||
|
CloseHandle(hToWrite);
|
||
|
CloseHandle(hFromRead);
|
||
|
CloseHandle(hFromWrite);
|
||
|
S_error("process", "cannot open pipes");
|
||
|
}
|
||
|
|
||
|
si.cb = sizeof(STARTUPINFO);
|
||
|
si.dwFlags = STARTF_USESTDHANDLES;
|
||
|
hProcess = GetCurrentProcess();
|
||
|
|
||
|
/* Duplicate the ToRead handle so that the child can inherit it. */
|
||
|
if (!DuplicateHandle(hProcess, hToRead, hProcess, &si.hStdInput,
|
||
|
GENERIC_READ, TRUE, 0)) {
|
||
|
CloseHandle(hToRead);
|
||
|
CloseHandle(hToWrite);
|
||
|
CloseHandle(hFromRead);
|
||
|
CloseHandle(hFromWrite);
|
||
|
if (stderrp) {
|
||
|
CloseHandle(hFromReadErr);
|
||
|
CloseHandle(hFromWriteErr);
|
||
|
}
|
||
|
S_error("process", "cannot open pipes");
|
||
|
}
|
||
|
CloseHandle(hToRead);
|
||
|
|
||
|
/* Duplicate the FromWrite handle so that the child can inherit it. */
|
||
|
if (!DuplicateHandle(hProcess, hFromWrite, hProcess, &si.hStdOutput,
|
||
|
GENERIC_WRITE, TRUE, 0)) {
|
||
|
CloseHandle(si.hStdInput);
|
||
|
CloseHandle(hToWrite);
|
||
|
CloseHandle(hFromRead);
|
||
|
CloseHandle(hFromWrite);
|
||
|
if (stderrp) {
|
||
|
CloseHandle(hFromReadErr);
|
||
|
CloseHandle(hFromWriteErr);
|
||
|
}
|
||
|
S_error("process", "cannot open pipes");
|
||
|
}
|
||
|
CloseHandle(hFromWrite);
|
||
|
|
||
|
if (stderrp) {
|
||
|
/* Duplicate the FromWrite handle so that the child can inherit it. */
|
||
|
if (!DuplicateHandle(hProcess, hFromWriteErr, hProcess, &si.hStdError,
|
||
|
GENERIC_WRITE, TRUE, 0)) {
|
||
|
CloseHandle(si.hStdInput);
|
||
|
CloseHandle(hToWrite);
|
||
|
CloseHandle(hFromRead);
|
||
|
CloseHandle(hFromWrite);
|
||
|
CloseHandle(hFromReadErr);
|
||
|
CloseHandle(hFromWriteErr);
|
||
|
S_error("process", "cannot open pipes");
|
||
|
}
|
||
|
CloseHandle(hFromWriteErr);
|
||
|
} else {
|
||
|
si.hStdError = si.hStdOutput;
|
||
|
}
|
||
|
|
||
|
if ((comspec = Sgetenv("COMSPEC"))) {
|
||
|
size_t n = strlen(comspec) + strlen(s) + 7;
|
||
|
buffer = (char *)_alloca(n);
|
||
|
snprintf(buffer, n, "\"%s\" /c %s", comspec, s);
|
||
|
free(comspec);
|
||
|
} else
|
||
|
buffer = s;
|
||
|
bufferw = Sutf8_to_wide(buffer);
|
||
|
if (!CreateProcessW(NULL, bufferw, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
|
||
|
free(bufferw);
|
||
|
CloseHandle(si.hStdInput);
|
||
|
CloseHandle(hToWrite);
|
||
|
CloseHandle(hFromRead);
|
||
|
CloseHandle(si.hStdOutput);
|
||
|
if (stderrp) {
|
||
|
CloseHandle(hFromReadErr);
|
||
|
CloseHandle(si.hStdError);
|
||
|
}
|
||
|
S_error("process", "cannot spawn subprocess");
|
||
|
}
|
||
|
free(bufferw);
|
||
|
CloseHandle(si.hStdInput);
|
||
|
CloseHandle(si.hStdOutput);
|
||
|
if (stderrp) {
|
||
|
CloseHandle(si.hStdError);
|
||
|
}
|
||
|
CloseHandle(pi.hProcess);
|
||
|
CloseHandle(pi.hThread);
|
||
|
|
||
|
ifd = _open_osfhandle((intptr_t)hFromRead, 0);
|
||
|
ofd = _open_osfhandle((intptr_t)hToWrite, 0);
|
||
|
if (stderrp) {
|
||
|
efd = _open_osfhandle((intptr_t)hFromReadErr, 0);
|
||
|
}
|
||
|
child = pi.dwProcessId;
|
||
|
|
||
|
#else /* WIN32 */
|
||
|
|
||
|
INT tofds[2], fromfds[2], errfds[2];
|
||
|
struct sigaction act, oint_act;
|
||
|
|
||
|
if (pipe(tofds)) S_error("process","cannot open pipes");
|
||
|
if (pipe(fromfds)) {
|
||
|
CLOSE(tofds[0]); CLOSE(tofds[1]);
|
||
|
S_error("process","cannot open pipes");
|
||
|
}
|
||
|
if (stderrp) {
|
||
|
if (pipe(errfds)) {
|
||
|
CLOSE(tofds[0]); CLOSE(tofds[1]);
|
||
|
CLOSE(fromfds[0]); CLOSE(fromfds[1]);
|
||
|
S_error("process","cannot open pipes");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sigemptyset(&act.sa_mask);
|
||
|
act.sa_flags = 0;
|
||
|
act.sa_handler = SIG_IGN;
|
||
|
sigaction(SIGINT, &act, &oint_act);
|
||
|
|
||
|
if ((child = fork()) == 0) {
|
||
|
/* child does this: */
|
||
|
CLOSE(0); if (dup(tofds[0]) != 0) _exit(1);
|
||
|
CLOSE(1); if (dup(fromfds[1]) != 1) _exit(1);
|
||
|
CLOSE(2); if (dup(stderrp ? errfds[1] : 1) != 2) _exit(1);
|
||
|
{INT i; for (i = 3; i < NOFILE; i++) (void)CLOSE(i);}
|
||
|
execl("/bin/sh", "/bin/sh", "-c", s, NULL);
|
||
|
_exit(1) /* only if execl fails */;
|
||
|
/*NOTREACHED*/
|
||
|
} else {
|
||
|
/* parent does this: */
|
||
|
CLOSE(tofds[0]); CLOSE(fromfds[1]); if (stderrp) CLOSE(errfds[1]);
|
||
|
if (child < 0) {
|
||
|
CLOSE(tofds[1]); CLOSE(fromfds[0]); if (stderrp) CLOSE(errfds[0]);
|
||
|
sigaction(SIGINT, &oint_act, (struct sigaction *)0);
|
||
|
S_error("process", "cannot fork subprocess");
|
||
|
/*NOTREACHED*/
|
||
|
} else {
|
||
|
ifd = fromfds[0];
|
||
|
ofd = tofds[1];
|
||
|
if (stderrp) efd = errfds[0];
|
||
|
sigaction(SIGINT, &oint_act, (struct sigaction *)0);
|
||
|
S_register_child_process(child);
|
||
|
}
|
||
|
}
|
||
|
#endif /* WIN32 */
|
||
|
|
||
|
if (stderrp)
|
||
|
return LIST4(FIX(ifd), FIX(efd), FIX(ofd), FIX(child));
|
||
|
else
|
||
|
return LIST3(FIX(ifd), FIX(ofd), FIX(child));
|
||
|
}
|
||
|
|
||
|
static I32 s_chdir(const char *inpath) {
|
||
|
char *path;
|
||
|
I32 status;
|
||
|
|
||
|
path = S_malloc_pathname(inpath);
|
||
|
#ifdef EINTR
|
||
|
while ((status = CHDIR(path)) != 0 && errno == EINTR) ;
|
||
|
#else /* EINTR */
|
||
|
status = CHDIR(path);
|
||
|
#endif /* EINTR */
|
||
|
free(path);
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
#ifdef GETWD
|
||
|
static char *s_getwd() {
|
||
|
return GETWD((char *)&BVIT(S_bytevector(PATH_MAX), 0));
|
||
|
}
|
||
|
#endif /* GETWD */
|
||
|
|
||
|
static ptr s_set_code_byte(ptr p, ptr n, ptr x) {
|
||
|
I8 *a;
|
||
|
|
||
|
a = (I8 *)((uptr)p + UNFIX(n));
|
||
|
*a = (I8)UNFIX(x);
|
||
|
return Svoid;
|
||
|
}
|
||
|
|
||
|
static ptr s_set_code_word(ptr p, ptr n, ptr x) {
|
||
|
I16 *a;
|
||
|
|
||
|
a = (I16 *)((uptr)p + UNFIX(n));
|
||
|
*a = (I16)UNFIX(x);
|
||
|
return Svoid;
|
||
|
}
|
||
|
|
||
|
static ptr s_set_code_long(ptr p, ptr n, ptr x) {
|
||
|
I32 *a;
|
||
|
|
||
|
a = (I32 *)((uptr)p + UNFIX(n));
|
||
|
*a = (I32)(Sfixnump(x) ? UNFIX(x) : Sinteger_value(x));
|
||
|
return Svoid;
|
||
|
}
|
||
|
|
||
|
static void s_set_code_long2(ptr p, ptr n, ptr h, ptr l) {
|
||
|
I32 *a;
|
||
|
|
||
|
a = (I32 *)((uptr)p + UNFIX(n));
|
||
|
*a = (I32)((UNFIX(h) << 16) + UNFIX(l));
|
||
|
}
|
||
|
|
||
|
static ptr s_set_code_quad(ptr p, ptr n, ptr x) {
|
||
|
I64 *a;
|
||
|
|
||
|
a = (I64 *)((uptr)p + UNFIX(n));
|
||
|
*a = Sfixnump(x) ? UNFIX(x) : S_int64_value("\\#set-code-quad!", x);
|
||
|
return Svoid;
|
||
|
}
|
||
|
|
||
|
static ptr s_set_reloc(ptr p, ptr n, ptr e) {
|
||
|
iptr *a;
|
||
|
|
||
|
a = (iptr *)(&RELOCIT(CODERELOC(p), UNFIX(n)));
|
||
|
*a = Sfixnump(e) ? UNFIX(e) : Sinteger_value(e);
|
||
|
return e;
|
||
|
}
|
||
|
|
||
|
static ptr s_flush_instruction_cache(void) {
|
||
|
tc_mutex_acquire()
|
||
|
S_flush_instruction_cache(get_thread_context());
|
||
|
tc_mutex_release()
|
||
|
return Svoid;
|
||
|
}
|
||
|
|
||
|
static ptr s_make_code(flags, free, name, arity_mark, n, info, pinfos)
|
||
|
iptr flags, free, n; ptr name, arity_mark, info, pinfos; {
|
||
|
ptr co;
|
||
|
|
||
|
tc_mutex_acquire()
|
||
|
co = S_code(get_thread_context(), type_code | (flags << code_flags_offset), n);
|
||
|
tc_mutex_release()
|
||
|
CODEFREE(co) = free;
|
||
|
CODENAME(co) = name;
|
||
|
CODEARITYMASK(co) = arity_mark;
|
||
|
CODEINFO(co) = info;
|
||
|
CODEPINFOS(co) = pinfos;
|
||
|
if (pinfos != Snil) {
|
||
|
S_G.profile_counters = Scons(S_weak_cons(co, pinfos), S_G.profile_counters);
|
||
|
}
|
||
|
return co;
|
||
|
}
|
||
|
|
||
|
static ptr s_make_reloc_table(ptr codeobj, ptr n) {
|
||
|
CODERELOC(codeobj) = S_relocation_table(UNFIX(n));
|
||
|
RELOCCODE(CODERELOC(codeobj)) = codeobj;
|
||
|
return Svoid;
|
||
|
}
|
||
|
|
||
|
static ptr s_make_closure(ptr offset, ptr codeobj) {
|
||
|
|
||
|
return S_closure((ptr)((iptr)codeobj + UNFIX(offset)), 0);
|
||
|
}
|
||
|
|
||
|
/* the random formula is based on Knuth. It returns a random fixnum
|
||
|
* between 0 and n-1.
|
||
|
*/
|
||
|
static ptr s_fxrandom(ptr p) {
|
||
|
ptr tc = get_thread_context();
|
||
|
uptr t, n = UNFIX(p);
|
||
|
|
||
|
t = (RANDOMSEED(tc) = RANDOMSEED(tc) * 72931 + 90763387) >> 16;
|
||
|
t = t | ((RANDOMSEED(tc) = RANDOMSEED(tc) * 72931 + 90763387) & 0xffff0000);
|
||
|
if (n <= 0xffffffff) /* trivially true if sizeof(ptr) <= sizeof(U32) */
|
||
|
return FIX(t % n);
|
||
|
else {
|
||
|
t = (t << 16) | ((RANDOMSEED(tc) = RANDOMSEED(tc) * 72931 + 90763387) >> 16);
|
||
|
t = (t << 16) | ((RANDOMSEED(tc) = RANDOMSEED(tc) * 72931 + 90763387) >> 16);
|
||
|
return FIX(t % n);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static ptr s_flrandom(ptr x) {
|
||
|
ptr tc = get_thread_context();
|
||
|
U32 t1, t2, t3, t4;
|
||
|
|
||
|
t1 = RANDOMSEED(tc) = RANDOMSEED(tc) * 72931 + 90763387;
|
||
|
t2 = RANDOMSEED(tc) = RANDOMSEED(tc) * 72931 + 90763387;
|
||
|
t3 = RANDOMSEED(tc) = RANDOMSEED(tc) * 72931 + 90763387;
|
||
|
t4 = RANDOMSEED(tc) = RANDOMSEED(tc) * 72931 + 90763387;
|
||
|
return Sflonum(S_random_double(t1, t2, t3, t4, FLODAT(x)));
|
||
|
}
|
||
|
|
||
|
static U32 s_random_seed() {
|
||
|
ptr tc = get_thread_context();
|
||
|
return RANDOMSEED(tc);
|
||
|
}
|
||
|
|
||
|
static void s_set_random_seed(U32 x) {
|
||
|
ptr tc = get_thread_context();
|
||
|
RANDOMSEED(tc) = x;
|
||
|
}
|
||
|
|
||
|
static ptr s_intern(ptr x) {
|
||
|
require(Sstringp(x),"string->symbol","~s is not a string",x);
|
||
|
|
||
|
return S_intern_sc(&STRIT(x, 0), Sstring_length(x), x);
|
||
|
}
|
||
|
|
||
|
static ptr s_intern2(ptr x, ptr n) {
|
||
|
return S_intern_sc(&STRIT(x, 0), UNFIX(n), Sfalse);
|
||
|
}
|
||
|
|
||
|
/* first n chars str are pretty name; remaining m-n are unique name */
|
||
|
static ptr s_intern3(ptr x, ptr n, ptr m) {
|
||
|
iptr plen = UNFIX(n);
|
||
|
return S_intern3(&STRIT(x, 0), plen, &STRIT(x, plen), UNFIX(m) - plen, Sfalse, Sfalse);
|
||
|
}
|
||
|
|
||
|
static ptr s_strings_to_gensym(ptr pname_str, ptr uname_str) {
|
||
|
return S_intern3(&STRIT(pname_str, 0), Sstring_length(pname_str),
|
||
|
&STRIT(uname_str, 0), Sstring_length(uname_str),
|
||
|
pname_str, uname_str);
|
||
|
}
|
||
|
|
||
|
static ptr s_mkdir(const char *inpath, INT mode) {
|
||
|
INT status; ptr res; char *path;
|
||
|
|
||
|
path = S_malloc_pathname(inpath);
|
||
|
#ifdef WIN32
|
||
|
status = S_windows_mkdir(path);
|
||
|
#else /* WIN32 */
|
||
|
status = mkdir(path, mode);
|
||
|
#endif /* WIN32 */
|
||
|
|
||
|
res = status == 0 ? Strue : S_strerror(errno);
|
||
|
free(path);
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
static ptr s_delete_file(const char *inpath) {
|
||
|
ptr res; char *path;
|
||
|
|
||
|
path = S_malloc_pathname(inpath);
|
||
|
res = UNLINK(path) == 0 ? Strue : S_strerror(errno);
|
||
|
free(path);
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
static ptr s_delete_directory(const char *inpath) {
|
||
|
ptr res; char *path;
|
||
|
|
||
|
path = S_malloc_pathname(inpath);
|
||
|
res = RMDIR(path) == 0 ? Strue : S_strerror(errno);
|
||
|
free(path);
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
static ptr s_rename_file(const char *inpath1, const char *inpath2) {
|
||
|
ptr res; char *path1, *path2;
|
||
|
|
||
|
path1 = S_malloc_pathname(inpath1);
|
||
|
path2 = S_malloc_pathname(inpath2);
|
||
|
res = RENAME(path1, path2) == 0 ? Strue : S_strerror(errno);
|
||
|
free(path1);
|
||
|
free(path2);
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
static ptr s_chmod(const char *inpath, INT mode) {
|
||
|
ptr res; INT status; char *path;
|
||
|
|
||
|
path = S_malloc_pathname(inpath);
|
||
|
#ifdef WIN32
|
||
|
/* pathetic approximation: (a) only handles user permissions, (b) doesn't
|
||
|
handle execute permissions, (c) windows won't make file not readable */
|
||
|
status = CHMOD(path,
|
||
|
(mode & 0400 ? S_IREAD : 0) |
|
||
|
(mode & 0200 ? S_IWRITE : 0));
|
||
|
#else /* WIN32 */
|
||
|
status = CHMOD(path, mode);
|
||
|
#endif /* WIN32 */
|
||
|
res = status == 0 ? Strue : S_strerror(errno);
|
||
|
free(path);
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
static ptr s_getmod(const char *inpath, IBOOL followp) {
|
||
|
ptr res; char *path; struct STATBUF statbuf;
|
||
|
|
||
|
path = S_malloc_pathname(inpath);
|
||
|
|
||
|
/* according to msdn, user read/write bits are set according to the file's
|
||
|
permission mode, and user execute bits are set according to the
|
||
|
filename extension. it says nothing about group and other execute bits. */
|
||
|
|
||
|
if ((followp ? STAT(path, &statbuf) : LSTAT(path, &statbuf)) != 0) {
|
||
|
res = S_strerror(errno);
|
||
|
} else {
|
||
|
res = FIX(statbuf.st_mode & 07777);
|
||
|
}
|
||
|
free(path);
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
static ptr s_path_atime(const char *inpath, IBOOL followp) {
|
||
|
#ifdef WIN32
|
||
|
ptr res;
|
||
|
wchar_t *wpath;
|
||
|
WIN32_FILE_ATTRIBUTE_DATA filedata;
|
||
|
__int64 total, sec; int nsec;
|
||
|
|
||
|
if ((wpath = S_malloc_wide_pathname(inpath)) == NULL) {
|
||
|
res = S_LastErrorString();
|
||
|
} else if (!GetFileAttributesExW(wpath, GetFileExInfoStandard, &filedata)) {
|
||
|
DWORD err = GetLastError();
|
||
|
res = err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND ?
|
||
|
Sstring("no such file or directory") :
|
||
|
S_LastErrorString();
|
||
|
} else {
|
||
|
total = filedata.ftLastAccessTime.dwHighDateTime;
|
||
|
total <<= 32;
|
||
|
total |= filedata.ftLastAccessTime.dwLowDateTime;
|
||
|
sec = total / 10000000 - 11644473600L;
|
||
|
nsec = (total % 10000000) * 100;
|
||
|
res = Scons(Sinteger64(sec), Sinteger32(nsec));
|
||
|
}
|
||
|
free(wpath);
|
||
|
return res;
|
||
|
#else /* WIN32 */
|
||
|
ptr res;
|
||
|
char *path;
|
||
|
struct STATBUF statbuf;
|
||
|
|
||
|
path = S_malloc_pathname(inpath);
|
||
|
if ((followp ? STAT(path, &statbuf) : LSTAT(path, &statbuf)) != 0) {
|
||
|
res = S_strerror(errno);
|
||
|
} else {
|
||
|
res = Scons(Sinteger64(SECATIME(statbuf)), Sinteger32(NSECATIME(statbuf)));
|
||
|
}
|
||
|
free(path);
|
||
|
return res;
|
||
|
#endif /* WIN32 */
|
||
|
}
|
||
|
|
||
|
static ptr s_path_ctime(const char *inpath, IBOOL followp) {
|
||
|
#ifdef WIN32
|
||
|
ptr res;
|
||
|
wchar_t *wpath;
|
||
|
WIN32_FILE_ATTRIBUTE_DATA filedata;
|
||
|
__int64 total, sec; int nsec;
|
||
|
|
||
|
if ((wpath = S_malloc_wide_pathname(inpath)) == NULL) {
|
||
|
res = S_LastErrorString();
|
||
|
} else if (!GetFileAttributesExW(wpath, GetFileExInfoStandard, &filedata)) {
|
||
|
DWORD err = GetLastError();
|
||
|
res = err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND ?
|
||
|
Sstring("no such file or directory") :
|
||
|
S_LastErrorString();
|
||
|
} else {
|
||
|
total = filedata.ftLastWriteTime.dwHighDateTime;
|
||
|
total <<= 32;
|
||
|
total |= filedata.ftLastWriteTime.dwLowDateTime;
|
||
|
sec = total / 10000000 - 11644473600L;
|
||
|
nsec = (total % 10000000) * 100;
|
||
|
res = Scons(Sinteger64(sec), Sinteger32(nsec));
|
||
|
}
|
||
|
free(wpath);
|
||
|
return res;
|
||
|
#else /* WIN32 */
|
||
|
ptr res;
|
||
|
char *path;
|
||
|
struct STATBUF statbuf;
|
||
|
|
||
|
path = S_malloc_pathname(inpath);
|
||
|
if ((followp ? STAT(path, &statbuf) : LSTAT(path, &statbuf)) != 0) {
|
||
|
res = S_strerror(errno);
|
||
|
} else {
|
||
|
res = Scons(Sinteger64(SECCTIME(statbuf)), Sinteger32(NSECCTIME(statbuf)));
|
||
|
}
|
||
|
free(path);
|
||
|
return res;
|
||
|
#endif /* WIN32 */
|
||
|
}
|
||
|
|
||
|
static ptr s_path_mtime(const char *inpath, IBOOL followp) {
|
||
|
#ifdef WIN32
|
||
|
ptr res;
|
||
|
wchar_t *wpath;
|
||
|
WIN32_FILE_ATTRIBUTE_DATA filedata;
|
||
|
__int64 total, sec; int nsec;
|
||
|
|
||
|
if ((wpath = S_malloc_wide_pathname(inpath)) == NULL) {
|
||
|
res = S_LastErrorString();
|
||
|
} else if (!GetFileAttributesExW(wpath, GetFileExInfoStandard, &filedata)) {
|
||
|
DWORD err = GetLastError();
|
||
|
res = err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND ?
|
||
|
Sstring("no such file or directory") :
|
||
|
S_LastErrorString();
|
||
|
} else {
|
||
|
total = filedata.ftLastWriteTime.dwHighDateTime;
|
||
|
total <<= 32;
|
||
|
total |= filedata.ftLastWriteTime.dwLowDateTime;
|
||
|
sec = total / 10000000 - 11644473600L;
|
||
|
nsec = (total % 10000000) * 100;
|
||
|
res = Scons(Sinteger64(sec), Sinteger32(nsec));
|
||
|
}
|
||
|
free(wpath);
|
||
|
return res;
|
||
|
#else /* WIN32 */
|
||
|
ptr res;
|
||
|
char *path;
|
||
|
struct STATBUF statbuf;
|
||
|
|
||
|
path = S_malloc_pathname(inpath);
|
||
|
if ((followp ? STAT(path, &statbuf) : LSTAT(path, &statbuf)) != 0) {
|
||
|
res = S_strerror(errno);
|
||
|
} else {
|
||
|
res = Scons(Sinteger64(SECMTIME(statbuf)), Sinteger32(NSECMTIME(statbuf)));
|
||
|
}
|
||
|
free(path);
|
||
|
return res;
|
||
|
#endif /* WIN32 */
|
||
|
}
|
||
|
|
||
|
static ptr s_fd_atime(INT fd) {
|
||
|
struct STATBUF statbuf;
|
||
|
|
||
|
if (FSTAT(fd, &statbuf) != 0) return S_strerror(errno);
|
||
|
|
||
|
return Scons(Sinteger64(SECATIME(statbuf)), Sinteger32(NSECATIME(statbuf)));
|
||
|
}
|
||
|
|
||
|
static ptr s_fd_ctime(INT fd) {
|
||
|
struct STATBUF statbuf;
|
||
|
|
||
|
if (FSTAT(fd, &statbuf) != 0) return S_strerror(errno);
|
||
|
|
||
|
return Scons(Sinteger64(SECCTIME(statbuf)), Sinteger32(NSECCTIME(statbuf)));
|
||
|
}
|
||
|
|
||
|
static ptr s_fd_mtime(INT fd) {
|
||
|
struct STATBUF statbuf;
|
||
|
|
||
|
if (FSTAT(fd, &statbuf) != 0) return S_strerror(errno);
|
||
|
|
||
|
return Scons(Sinteger64(SECMTIME(statbuf)), Sinteger32(NSECMTIME(statbuf)));
|
||
|
}
|
||
|
|
||
|
static IBOOL s_fd_regularp(INT fd) {
|
||
|
struct STATBUF statbuf;
|
||
|
|
||
|
if (FSTAT(fd, &statbuf) != 0) return 0;
|
||
|
|
||
|
return statbuf.st_mode & S_IFREG;
|
||
|
}
|
||
|
|
||
|
static void s_nanosleep(ptr xsec, ptr xnsec) {
|
||
|
ptr tc = get_thread_context();
|
||
|
U64 sec = Sunsigned64_value(xsec);
|
||
|
U32 nsec = Sunsigned32_value(xnsec);
|
||
|
#ifdef PTHREADS
|
||
|
if (DISABLECOUNT(tc) == 0) {
|
||
|
deactivate_thread(tc)
|
||
|
}
|
||
|
#endif /* PTHREADS */
|
||
|
/* give up our lightweight thread "quanta" */
|
||
|
if (DISABLECOUNT(tc) == 0) {
|
||
|
TRAP(get_thread_context()) = (ptr)1;
|
||
|
}
|
||
|
#ifdef WIN32
|
||
|
/* round to nearest ms represented by sec and nsec */
|
||
|
Sleep((DWORD)(sec * 1000 + (nsec + 500000) / 1000000));
|
||
|
#else /* WIN32 */
|
||
|
struct timespec rqtp;
|
||
|
rqtp.tv_sec = sec;
|
||
|
rqtp.tv_nsec = nsec;
|
||
|
nanosleep(&rqtp, NULL);
|
||
|
#endif /* WIN32 */
|
||
|
#ifdef PTHREADS
|
||
|
if (DISABLECOUNT(tc) == 0) {
|
||
|
reactivate_thread(tc)
|
||
|
}
|
||
|
#endif /* PTHREADS */
|
||
|
}
|
||
|
|
||
|
static int s_getpid(void) {
|
||
|
return GETPID();
|
||
|
}
|
||
|
|
||
|
static ptr s_set_collect_trip_bytes(ptr n) {
|
||
|
S_G.collect_trip_bytes = Sunsigned_value(n);
|
||
|
return Svoid;
|
||
|
}
|
||
|
|
||
|
static void c_exit(UNUSED I32 status) {
|
||
|
S_abnormal_exit();
|
||
|
}
|
||
|
|
||
|
static double s_mod(double x, double y) { return fmod(x, y); }
|
||
|
|
||
|
static double s_exp(double x) { return exp(x); }
|
||
|
|
||
|
static double s_log(double x) { return log(x); }
|
||
|
|
||
|
#if (machine_type == machine_type_i3fb || machine_type == machine_type_ti3fb)
|
||
|
#include <ieeefp.h>
|
||
|
/* freebsd's pow delivers precise results for integer inputs, e.g.,
|
||
|
* 10.0^21.0, only with * extended-precision (80-bit) floats */
|
||
|
static double s_pow(double x, double y) {
|
||
|
fp_prec_t p;
|
||
|
p = fpgetprec();
|
||
|
if (p != FP_PE) {
|
||
|
double ans;
|
||
|
fpsetprec(FP_PE);
|
||
|
ans = pow(x, y);
|
||
|
fpsetprec(p);
|
||
|
return ans;
|
||
|
} else
|
||
|
return pow(x, y);
|
||
|
}
|
||
|
#elif defined(MACOSX)
|
||
|
/* intel macosx delivers precise results for integer inputs, e.g.,
|
||
|
* 10.0^21.0, only with long double version of pow */
|
||
|
static double s_pow(double x, double y) { return powl(x, y); }
|
||
|
#else /* i3fb/ti3fb */
|
||
|
static double s_pow(double x, double y) { return pow(x, y); }
|
||
|
#endif /* i3fb/ti3fb */
|
||
|
|
||
|
static double s_sqrt(double x) { return sqrt(x); }
|
||
|
|
||
|
static double s_sin(double x) { return sin(x); }
|
||
|
|
||
|
static double s_cos(double x) { return cos(x); }
|
||
|
|
||
|
static double s_tan(double x) { return tan(x); }
|
||
|
|
||
|
static double s_asin(double x) { return asin(x); }
|
||
|
|
||
|
static double s_acos(double x) { return acos(x); }
|
||
|
|
||
|
static double s_atan(double x) { return atan(x); }
|
||
|
|
||
|
static double s_atan2(double x, double y) { return atan2(x, y); }
|
||
|
|
||
|
static double s_sinh(double x) { return sinh(x); }
|
||
|
|
||
|
static double s_cosh(double x) { return cosh(x); }
|
||
|
|
||
|
static double s_tanh(double x) { return tanh(x); }
|
||
|
|
||
|
static double s_floor(double x) { return floor(x); }
|
||
|
|
||
|
static double s_ceil(double x) { return ceil(x); }
|
||
|
|
||
|
static double s_hypot(double x, double y) { return HYPOT(x, y); }
|
||
|
|
||
|
#ifdef ARCHYPERBOLIC
|
||
|
static double s_asinh(double x) { return asinh(x); }
|
||
|
|
||
|
static double s_acosh(double x){ return acosh(x); }
|
||
|
|
||
|
static double s_atanh(double x) { return atanh(x); }
|
||
|
#endif /* ARCHHYPERBOLIC */
|
||
|
|
||
|
#ifdef LOG1P
|
||
|
static double s_log1p(double x) { return log1p(x); }
|
||
|
#endif /* LOG1P */
|
||
|
|
||
|
static ptr s_getenv(char *name) {
|
||
|
#ifdef WIN32
|
||
|
char *s = Sgetenv(name);
|
||
|
#else /* WIN32 */
|
||
|
char *s = getenv(name);
|
||
|
#endif /* WIN32 */
|
||
|
if (s == (char *)0)
|
||
|
return Sfalse;
|
||
|
else {
|
||
|
ptr r = Sstring_utf8(s, -1);
|
||
|
#ifdef WIN32
|
||
|
free(s);
|
||
|
#endif
|
||
|
return r;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void s_putenv(char *name, char *value) {
|
||
|
#ifdef WIN32
|
||
|
wchar_t* namew;
|
||
|
wchar_t* valuew;
|
||
|
BOOL rc;
|
||
|
namew = Sutf8_to_wide(name);
|
||
|
valuew = Sutf8_to_wide(value);
|
||
|
rc = SetEnvironmentVariableW(namew, valuew);
|
||
|
free(namew);
|
||
|
free(valuew);
|
||
|
if (rc == 0)
|
||
|
S_error1("putenv", "environment extension failed: ~a", S_LastErrorString());
|
||
|
#else /* WIN32 */
|
||
|
if (setenv(name, value, 1) != 0) {
|
||
|
ptr msg = S_strerror(errno);
|
||
|
|
||
|
if (msg != Sfalse)
|
||
|
S_error1("putenv", "environment extension failed: ~a", msg);
|
||
|
else
|
||
|
S_error("putenv", "environment extension failed");
|
||
|
}
|
||
|
#endif /* WIN32 */
|
||
|
}
|
||
|
|
||
|
#ifdef PTHREADS
|
||
|
/* backdoor thread is for testing thread creation by Sactivate_thread */
|
||
|
#define display(s) { const char *S = (s); if (WRITE(1, S, (unsigned int)strlen(S))) {} }
|
||
|
static s_thread_rv_t s_backdoor_thread_start(void *p) {
|
||
|
display("backdoor thread started\n")
|
||
|
(void) Sactivate_thread();
|
||
|
display("thread activated\n")
|
||
|
Scall0((ptr)p);
|
||
|
(void) Sdeactivate_thread();
|
||
|
display("thread deactivated\n")
|
||
|
(void) Sactivate_thread();
|
||
|
display("thread reactivated\n")
|
||
|
Scall0((ptr)p);
|
||
|
Sdestroy_thread();
|
||
|
display("thread destroyed\n")
|
||
|
s_thread_return;
|
||
|
}
|
||
|
|
||
|
static iptr s_backdoor_thread(ptr p) {
|
||
|
display("creating thread\n");
|
||
|
return s_thread_create(s_backdoor_thread_start, (void *)p);
|
||
|
}
|
||
|
|
||
|
static ptr s_threads(void) {
|
||
|
return S_threads;
|
||
|
}
|
||
|
|
||
|
static void s_mutex_acquire(scheme_mutex_t *m) {
|
||
|
ptr tc = get_thread_context();
|
||
|
|
||
|
if (m == &S_tc_mutex) {
|
||
|
S_mutex_acquire(m);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (S_mutex_tryacquire(m) == 0) return;
|
||
|
|
||
|
if (DISABLECOUNT(tc) == 0) {
|
||
|
deactivate_thread(tc)
|
||
|
}
|
||
|
S_mutex_acquire(m);
|
||
|
if (DISABLECOUNT(tc) == 0) {
|
||
|
reactivate_thread(tc)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static ptr s_mutex_acquire_noblock(scheme_mutex_t *m) {
|
||
|
return S_mutex_tryacquire(m) == 0 ? Strue : Sfalse;
|
||
|
}
|
||
|
|
||
|
static void s_condition_broadcast(s_thread_cond_t *c) {
|
||
|
s_thread_cond_broadcast(c);
|
||
|
}
|
||
|
|
||
|
static void s_condition_signal(s_thread_cond_t *c) {
|
||
|
s_thread_cond_signal(c);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static ptr s_profile_counters(void) {
|
||
|
return S_G.profile_counters;
|
||
|
}
|
||
|
|
||
|
/* s_profile_release_counters assumes and maintains the property that each pair's
|
||
|
tail is not younger than the pair and thereby avoids dirty sets. */
|
||
|
static ptr s_profile_release_counters(void) {
|
||
|
ptr tossed, *p_keep, *p_toss, ls;
|
||
|
p_keep = &S_G.profile_counters;
|
||
|
p_toss = &tossed;
|
||
|
for (ls = *p_keep; ls != Snil && (MaybeSegInfo(ptr_get_segment(ls)))->generation <= S_G.prcgeneration; ls = Scdr(ls)) {
|
||
|
if (Sbwp_objectp(CAAR(ls))) {
|
||
|
*p_toss = ls;
|
||
|
p_toss = &Scdr(ls);
|
||
|
} else {
|
||
|
*p_keep = ls;
|
||
|
p_keep = &Scdr(ls);
|
||
|
}
|
||
|
}
|
||
|
*p_keep = ls;
|
||
|
*p_toss = Snil;
|
||
|
S_G.prcgeneration = 0;
|
||
|
return tossed;
|
||
|
}
|
||
|
|
||
|
void S_dump_tc(ptr tc) {
|
||
|
INT i;
|
||
|
|
||
|
printf("AC0=%p AC1=%p SFP=%p CP=%p\n", AC0(tc), AC1(tc), SFP(tc), CP(tc));
|
||
|
printf("ESP=%p AP=%p EAP=%p\n", ESP(tc), AP(tc), EAP(tc));
|
||
|
printf("TRAP=%p XP=%p YP=%p REAL_EAP=%p\n", TRAP(tc), XP(tc), YP(tc), REAL_EAP(tc));
|
||
|
printf("CCHAIN=%p RANDOMSEED=%ld SCHEMESTACK=%p STACKCACHE=%p\n", CCHAIN(tc), (long)RANDOMSEED(tc), SCHEMESTACK(tc), STACKCACHE(tc));
|
||
|
printf("STACKLINK=%p SCHEMESTACKSIZE=%ld WINDERS=%p U=%p\n", STACKLINK(tc), (long)SCHEMESTACKSIZE(tc), WINDERS(tc), U(tc));
|
||
|
printf("V=%p W=%p X=%p Y=%p\n", V(tc), W(tc), X(tc), Y(tc));
|
||
|
printf("SOMETHING=%p KBDPEND=%p SIGPEND=%p TIMERTICKS=%p\n", SOMETHINGPENDING(tc), KEYBOARDINTERRUPTPENDING(tc), SIGNALINTERRUPTPENDING(tc), TIMERTICKS(tc));
|
||
|
printf("DISABLECOUNT=%p PARAMETERS=%p\n", DISABLECOUNT(tc), PARAMETERS(tc));
|
||
|
for (i = 0 ; i < virtual_register_count ; i += 1) {
|
||
|
printf("VIRTREG[%d]=%p", i, VIRTREG(tc, i));
|
||
|
if ((i & 0x11) == 0x11 || i == virtual_register_count - 1) printf("\n");
|
||
|
}
|
||
|
fflush(stdout);
|
||
|
}
|
||
|
|
||
|
void S_prim5_init(void) {
|
||
|
if (!S_boot_time) return;
|
||
|
|
||
|
#ifdef PTHREADS
|
||
|
Sforeign_symbol("(cs)fork_thread", (void *)S_fork_thread);
|
||
|
Sforeign_symbol("(cs)make_mutex", (void *)S_make_mutex);
|
||
|
Sforeign_symbol("(cs)mutex_free", (void *)S_mutex_free);
|
||
|
Sforeign_symbol("(cs)backdoor_thread", (void *)s_backdoor_thread);
|
||
|
Sforeign_symbol("(cs)threads", (void *)s_threads);
|
||
|
Sforeign_symbol("(cs)mutex_acquire", (void *)s_mutex_acquire);
|
||
|
Sforeign_symbol("(cs)mutex_release", (void *)S_mutex_release);
|
||
|
Sforeign_symbol("(cs)mutex_acquire_noblock", (void *)s_mutex_acquire_noblock);
|
||
|
Sforeign_symbol("(cs)make_condition", (void *)S_make_condition);
|
||
|
Sforeign_symbol("(cs)condition_free", (void *)S_condition_free);
|
||
|
Sforeign_symbol("(cs)condition_broadcast", (void *)s_condition_broadcast);
|
||
|
Sforeign_symbol("(cs)condition_signal", (void *)s_condition_signal);
|
||
|
Sforeign_symbol("(cs)condition_wait", (void *)S_condition_wait);
|
||
|
#endif
|
||
|
Sforeign_symbol("(cs)s_addr_in_heap", (void *)s_addr_in_heap);
|
||
|
Sforeign_symbol("(cs)s_ptr_in_heap", (void *)s_ptr_in_heap);
|
||
|
Sforeign_symbol("(cs)generation", (void *)s_generation);
|
||
|
Sforeign_symbol("(cs)s_fltofx", (void *)s_fltofx);
|
||
|
Sforeign_symbol("(cs)s_weak_cons", (void *)S_weak_cons);
|
||
|
Sforeign_symbol("(cs)s_weak_pairp", (void *)s_weak_pairp);
|
||
|
Sforeign_symbol("(cs)s_ephemeron_cons", (void *)s_ephemeron_cons);
|
||
|
Sforeign_symbol("(cs)s_ephemeron_pairp", (void *)s_ephemeron_pairp);
|
||
|
Sforeign_symbol("(cs)continuation_depth", (void *)S_continuation_depth);
|
||
|
Sforeign_symbol("(cs)single_continuation", (void *)S_single_continuation);
|
||
|
Sforeign_symbol("(cs)c_exit", (void *)c_exit);
|
||
|
Sforeign_symbol("(cs)s_set_collect_trip_bytes", (void *)s_set_collect_trip_bytes);
|
||
|
Sforeign_symbol("(cs)s_oblist", (void *)s_oblist);
|
||
|
Sforeign_symbol("(cs)s_showalloc", (void *)s_showalloc);
|
||
|
Sforeign_symbol("(cs)s_system", (void *)s_system);
|
||
|
Sforeign_symbol("(cs)s_process", (void *)s_process);
|
||
|
Sforeign_symbol("(cs)s_set_code_byte", (void *)s_set_code_byte);
|
||
|
Sforeign_symbol("(cs)s_set_code_word", (void *)s_set_code_word);
|
||
|
Sforeign_symbol("(cs)s_set_code_long", (void *)s_set_code_long);
|
||
|
Sforeign_symbol("(cs)s_set_code_quad", (void *)s_set_code_quad);
|
||
|
Sforeign_symbol("(cs)s_set_reloc", (void *)s_set_reloc);
|
||
|
Sforeign_symbol("(cs)get_code_obj", (void *)S_get_code_obj);
|
||
|
Sforeign_symbol("(cs)s_flush_instruction_cache", (void *)s_flush_instruction_cache);
|
||
|
Sforeign_symbol("(cs)s_make_reloc_table", (void *)s_make_reloc_table);
|
||
|
Sforeign_symbol("(cs)s_make_closure", (void *)s_make_closure);
|
||
|
Sforeign_symbol("(cs)s_intern", (void *)s_intern);
|
||
|
Sforeign_symbol("(cs)s_intern2", (void *)s_intern2);
|
||
|
Sforeign_symbol("(cs)s_intern3", (void *)s_intern3);
|
||
|
Sforeign_symbol("(cs)s_strings_to_gensym", (void *)s_strings_to_gensym);
|
||
|
Sforeign_symbol("(cs)s_intern_gensym", (void *)S_intern_gensym);
|
||
|
Sforeign_symbol("(cs)cputime", (void *)S_cputime);
|
||
|
Sforeign_symbol("(cs)realtime", (void *)S_realtime);
|
||
|
Sforeign_symbol("(cs)clock_gettime", (void *)S_clock_gettime);
|
||
|
Sforeign_symbol("(cs)gmtime", (void *)S_gmtime);
|
||
|
Sforeign_symbol("(cs)asctime", (void *)S_asctime);
|
||
|
Sforeign_symbol("(cs)mktime", (void *)S_mktime);
|
||
|
Sforeign_symbol("(cs)unique_id", (void *)S_unique_id);
|
||
|
Sforeign_symbol("(cs)file_existsp", (void *)S_file_existsp);
|
||
|
Sforeign_symbol("(cs)file_regularp", (void *)S_file_regularp);
|
||
|
Sforeign_symbol("(cs)file_directoryp", (void *)S_file_directoryp);
|
||
|
Sforeign_symbol("(cs)file_symbolic_linkp", (void *)S_file_symbolic_linkp);
|
||
|
Sforeign_symbol("(cs)delete_file", (void *)s_delete_file);
|
||
|
Sforeign_symbol("(cs)delete_directory", (void *)s_delete_directory);
|
||
|
Sforeign_symbol("(cs)rename_file", (void *)s_rename_file);
|
||
|
Sforeign_symbol("(cs)mkdir", (void *)s_mkdir);
|
||
|
Sforeign_symbol("(cs)chmod", (void *)s_chmod);
|
||
|
Sforeign_symbol("(cs)getmod", (void *)s_getmod);
|
||
|
Sforeign_symbol("(cs)path_atime", (void *)s_path_atime);
|
||
|
Sforeign_symbol("(cs)path_ctime", (void *)s_path_ctime);
|
||
|
Sforeign_symbol("(cs)path_mtime", (void *)s_path_mtime);
|
||
|
Sforeign_symbol("(cs)fd_atime", (void *)s_fd_atime);
|
||
|
Sforeign_symbol("(cs)fd_ctime", (void *)s_fd_ctime);
|
||
|
Sforeign_symbol("(cs)fd_mtime", (void *)s_fd_mtime);
|
||
|
Sforeign_symbol("(cs)fd_regularp", (void *)s_fd_regularp);
|
||
|
Sforeign_symbol("(cs)nanosleep", (void *)s_nanosleep);
|
||
|
Sforeign_symbol("(cs)getpid", (void *)s_getpid);
|
||
|
Sforeign_symbol("(cs)fasl_read", (void *)S_fasl_read);
|
||
|
Sforeign_symbol("(cs)bv_fasl_read", (void *)S_bv_fasl_read);
|
||
|
Sforeign_symbol("(cs)s_decode_float", (void *)s_decode_float);
|
||
|
|
||
|
Sforeign_symbol("(cs)new_open_input_fd", (void *)S_new_open_input_fd);
|
||
|
Sforeign_symbol("(cs)new_open_output_fd", (void *)S_new_open_output_fd);
|
||
|
Sforeign_symbol("(cs)new_open_input_output_fd", (void *)S_new_open_input_output_fd);
|
||
|
Sforeign_symbol("(cs)close_fd", (void *)S_close_fd);
|
||
|
Sforeign_symbol("(cs)gzxfile_fd", (void *)S_gzxfile_fd);
|
||
|
Sforeign_symbol("(cs)compress_input_fd", (void *)S_compress_input_fd);
|
||
|
Sforeign_symbol("(cs)compress_output_fd", (void *)S_compress_output_fd);
|
||
|
|
||
|
Sforeign_symbol("(cs)bytevector_read", (void*)S_bytevector_read);
|
||
|
Sforeign_symbol("(cs)bytevector_read_nb", (void*)S_bytevector_read_nb);
|
||
|
Sforeign_symbol("(cs)bytevector_write", (void*)S_bytevector_write);
|
||
|
Sforeign_symbol("(cs)put_byte", (void*)S_put_byte);
|
||
|
Sforeign_symbol("(cs)get_fd_pos", (void*)S_get_fd_pos);
|
||
|
Sforeign_symbol("(cs)set_fd_pos", (void*)S_set_fd_pos);
|
||
|
Sforeign_symbol("(cs)get_fd_non_blocking", (void*)S_get_fd_non_blocking);
|
||
|
Sforeign_symbol("(cs)set_fd_non_blocking", (void*)S_set_fd_non_blocking);
|
||
|
Sforeign_symbol("(cs)get_fd_length", (void*)S_get_fd_length);
|
||
|
Sforeign_symbol("(cs)set_fd_length", (void*)S_set_fd_length);
|
||
|
|
||
|
Sforeign_symbol("(cs)bytevector_compress_size", (void*)S_bytevector_compress_size);
|
||
|
Sforeign_symbol("(cs)bytevector_compress", (void*)S_bytevector_compress);
|
||
|
Sforeign_symbol("(cs)bytevector_uncompress", (void*)S_bytevector_uncompress);
|
||
|
|
||
|
Sforeign_symbol("(cs)logand", (void *)S_logand);
|
||
|
Sforeign_symbol("(cs)logbitp", (void *)S_logbitp);
|
||
|
Sforeign_symbol("(cs)logbit0", (void *)S_logbit0);
|
||
|
Sforeign_symbol("(cs)logbit1", (void *)S_logbit1);
|
||
|
Sforeign_symbol("(cs)logtest", (void *)S_logtest);
|
||
|
Sforeign_symbol("(cs)logor", (void *)S_logor);
|
||
|
Sforeign_symbol("(cs)logxor", (void *)S_logxor);
|
||
|
Sforeign_symbol("(cs)lognot", (void *)S_lognot);
|
||
|
Sforeign_symbol("(cs)fxmul", (void *)s_fxmul);
|
||
|
Sforeign_symbol("(cs)fxdiv", (void *)s_fxdiv);
|
||
|
Sforeign_symbol("(cs)s_big_negate", (void *)S_big_negate);
|
||
|
Sforeign_symbol("(cs)add", (void *)S_add);
|
||
|
Sforeign_symbol("(cs)gcd", (void *)S_gcd);
|
||
|
Sforeign_symbol("(cs)mul", (void *)S_mul);
|
||
|
Sforeign_symbol("(cs)s_ash", (void *)S_ash);
|
||
|
Sforeign_symbol("(cs)s_big_positive_bit_field", (void *)S_big_positive_bit_field);
|
||
|
Sforeign_symbol("(cs)s_big_eq", (void *)S_big_eq);
|
||
|
Sforeign_symbol("(cs)s_big_lt", (void *)S_big_lt);
|
||
|
Sforeign_symbol("(cs)s_bigoddp", (void *)s_bigoddp);
|
||
|
Sforeign_symbol("(cs)s_div", (void *)S_div);
|
||
|
Sforeign_symbol("(cs)s_float", (void *)s_float);
|
||
|
Sforeign_symbol("(cs)s_flrandom", (void *)s_flrandom);
|
||
|
Sforeign_symbol("(cs)s_fxrandom", (void *)s_fxrandom);
|
||
|
Sforeign_symbol("(cs)s_integer_length", (void *)S_integer_length);
|
||
|
Sforeign_symbol("(cs)s_big_first_bit_set", (void *)S_big_first_bit_set);
|
||
|
Sforeign_symbol("(cs)s_make_code", (void *)s_make_code);
|
||
|
Sforeign_symbol("(cs)s_random_seed", (void *)s_random_seed);
|
||
|
Sforeign_symbol("(cs)s_set_code_long2", (void *)s_set_code_long2);
|
||
|
Sforeign_symbol("(cs)s_set_random_seed", (void *)s_set_random_seed);
|
||
|
Sforeign_symbol("(cs)ss_trunc", (void *)S_trunc);
|
||
|
Sforeign_symbol("(cs)ss_trunc_rem", (void *)s_trunc_rem);
|
||
|
Sforeign_symbol("(cs)sub", (void *)S_sub);
|
||
|
Sforeign_symbol("(cs)rem", (void *)S_rem);
|
||
|
#ifdef GETWD
|
||
|
Sforeign_symbol("(cs)s_getwd", (void *)s_getwd);
|
||
|
#endif
|
||
|
Sforeign_symbol("(cs)s_chdir", (void *)s_chdir);
|
||
|
#ifdef WIN32
|
||
|
Sforeign_symbol("(cs)find_files", (void *)S_find_files);
|
||
|
#else
|
||
|
Sforeign_symbol("(cs)directory_list", (void *)S_directory_list);
|
||
|
#endif
|
||
|
Sforeign_symbol("(cs)dequeue_scheme_signals", (void *)S_dequeue_scheme_signals);
|
||
|
Sforeign_symbol("(cs)register_scheme_signal", (void *)S_register_scheme_signal);
|
||
|
|
||
|
Sforeign_symbol("(cs)mod", (void *)s_mod);
|
||
|
Sforeign_symbol("(cs)exp", (void *)s_exp);
|
||
|
Sforeign_symbol("(cs)log", (void *)s_log);
|
||
|
Sforeign_symbol("(cs)pow", (void *)s_pow);
|
||
|
Sforeign_symbol("(cs)sqrt", (void *)s_sqrt);
|
||
|
Sforeign_symbol("(cs)sin", (void *)s_sin);
|
||
|
Sforeign_symbol("(cs)cos", (void *)s_cos);
|
||
|
Sforeign_symbol("(cs)tan", (void *)s_tan);
|
||
|
Sforeign_symbol("(cs)asin", (void *)s_asin);
|
||
|
Sforeign_symbol("(cs)acos", (void *)s_acos);
|
||
|
Sforeign_symbol("(cs)atan", (void *)s_atan);
|
||
|
Sforeign_symbol("(cs)atan2", (void *)s_atan2);
|
||
|
Sforeign_symbol("(cs)sinh", (void *)s_sinh);
|
||
|
Sforeign_symbol("(cs)cosh", (void *)s_cosh);
|
||
|
Sforeign_symbol("(cs)tanh", (void *)s_tanh);
|
||
|
Sforeign_symbol("(cs)floor", (void *)s_floor);
|
||
|
Sforeign_symbol("(cs)ceil", (void *)s_ceil);
|
||
|
Sforeign_symbol("(cs)hypot", (void *)s_hypot);
|
||
|
|
||
|
#ifdef ARCHYPERBOLIC
|
||
|
Sforeign_symbol("(cs)asinh", (void *)s_asinh);
|
||
|
Sforeign_symbol("(cs)acosh", (void *)s_acosh);
|
||
|
Sforeign_symbol("(cs)atanh", (void *)s_atanh);
|
||
|
#endif /* ARCHHYPERBOLIC */
|
||
|
|
||
|
#ifdef LOG1P
|
||
|
Sforeign_symbol("(cs)log1p", (void *)s_log1p);
|
||
|
#endif /* LOG1P */
|
||
|
|
||
|
Sforeign_symbol("(cs)s_get_reloc", (void *)s_get_reloc);
|
||
|
Sforeign_symbol("(cs)getenv", (void *)s_getenv);
|
||
|
Sforeign_symbol("(cs)putenv", (void *)s_putenv);
|
||
|
Sforeign_symbol("(cs)byte-copy", (void *)s_byte_copy);
|
||
|
Sforeign_symbol("(cs)ptr-copy", (void *)s_ptr_copy);
|
||
|
Sforeign_symbol("(cs)boot-error", (void *)S_boot_error);
|
||
|
Sforeign_symbol("(cs)s_tlv", (void *)s_tlv);
|
||
|
Sforeign_symbol("(cs)s_stlv", (void *)s_stlv);
|
||
|
Sforeign_symbol("(cs)s_test_schlib", (void *)s_test_schlib);
|
||
|
Sforeign_symbol("(cs)Sinteger_value", (void *)Sinteger_value);
|
||
|
Sforeign_symbol("(cs)Sinteger32_value", (void *)Sinteger32_value);
|
||
|
Sforeign_symbol("(cs)Sinteger64_value", (void *)Sinteger64_value);
|
||
|
Sforeign_symbol("(cs)s_breakhere", (void *)s_breakhere);
|
||
|
Sforeign_symbol("(cs)s_interactivep", (void *)s_interactivep);
|
||
|
Sforeign_symbol("(cs)same_devicep", (void *)s_same_devicep);
|
||
|
Sforeign_symbol("(cs)malloc", (void *)s_malloc);
|
||
|
Sforeign_symbol("(cs)free", (void *)s_free);
|
||
|
#ifdef FEATURE_ICONV
|
||
|
Sforeign_symbol("(cs)s_iconv_open", (void *)s_iconv_open);
|
||
|
Sforeign_symbol("(cs)s_iconv_close", (void *)s_iconv_close);
|
||
|
Sforeign_symbol("(cs)s_iconv_from_string", (void *)s_iconv_from_string);
|
||
|
Sforeign_symbol("(cs)s_iconv_to_string", (void *)s_iconv_to_string);
|
||
|
#endif
|
||
|
Sforeign_symbol("(cs)s_strerror", (void *)S_strerror);
|
||
|
Sforeign_symbol("(cs)s_errno", (void *)s_errno);
|
||
|
#ifdef WIN32
|
||
|
Sforeign_symbol("(cs)s_multibytetowidechar", (void *)s_multibytetowidechar);
|
||
|
Sforeign_symbol("(cs)s_widechartomultibyte", (void *)s_widechartomultibyte);
|
||
|
#endif
|
||
|
Sforeign_symbol("(cs)s_profile_counters", (void *)s_profile_counters);
|
||
|
Sforeign_symbol("(cs)s_profile_release_counters", (void *)s_profile_release_counters);
|
||
|
}
|
||
|
|
||
|
static ptr s_get_reloc(ptr co) {
|
||
|
ptr t, ls; uptr a, m, n;
|
||
|
|
||
|
require(Scodep(co),"s_get_reloc","~s is not a code object",co);
|
||
|
ls = Snil;
|
||
|
t = CODERELOC(co);
|
||
|
m = RELOCSIZE(t);
|
||
|
a = 0;
|
||
|
n = 0;
|
||
|
while (n < m) {
|
||
|
uptr entry, item_off, code_off; ptr obj;
|
||
|
entry = RELOCIT(t, n); n += 1;
|
||
|
if (RELOC_EXTENDED_FORMAT(entry)) {
|
||
|
item_off = RELOCIT(t, n); n += 1;
|
||
|
code_off = RELOCIT(t, n); n += 1;
|
||
|
} else {
|
||
|
item_off = RELOC_ITEM_OFFSET(entry);
|
||
|
code_off = RELOC_CODE_OFFSET(entry);
|
||
|
}
|
||
|
a += code_off;
|
||
|
obj = S_get_code_obj(RELOC_TYPE(entry), co, a, item_off);
|
||
|
if (!Sfixnump(obj)) {
|
||
|
ptr x;
|
||
|
for (x = ls; ; x = Scdr(x)) {
|
||
|
if (x == Snil) {
|
||
|
ls = Scons(obj,ls);
|
||
|
break;
|
||
|
} else if (Scar(x) == obj)
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return ls;
|
||
|
}
|
||
|
|
||
|
static void s_byte_copy(ptr src, iptr srcoff, ptr dst, iptr dstoff, iptr cnt) {
|
||
|
void *srcaddr = (void *)((iptr)src + srcoff);
|
||
|
void *dstaddr = (void *)((iptr)dst + dstoff);
|
||
|
if (dst != src)
|
||
|
memcpy(dstaddr, srcaddr, cnt);
|
||
|
else
|
||
|
memmove(dstaddr, srcaddr, cnt);
|
||
|
}
|
||
|
|
||
|
static void s_ptr_copy(ptr src, iptr srcoff, ptr dst, iptr dstoff, iptr cnt) {
|
||
|
void *srcaddr = (void *)((iptr)src + srcoff);
|
||
|
void *dstaddr = (void *)((iptr)dst + dstoff);
|
||
|
cnt = cnt << log2_ptr_bytes;
|
||
|
if (dst != src)
|
||
|
memcpy(dstaddr, srcaddr, cnt);
|
||
|
else
|
||
|
memmove(dstaddr, srcaddr, cnt);
|
||
|
}
|
||
|
|
||
|
/* these are used only for testing */
|
||
|
static ptr s_tlv(ptr x) {
|
||
|
return Stop_level_value(x);
|
||
|
}
|
||
|
|
||
|
static void s_stlv(ptr x, ptr v) {
|
||
|
Sset_top_level_value(x, v);
|
||
|
}
|
||
|
|
||
|
#define SCHLIBTEST(expr) {\
|
||
|
test += 1;\
|
||
|
if (!(expr)) S_error1("s_test_schlib", "test ~s failed", FIX(test));\
|
||
|
}
|
||
|
|
||
|
static void s_test_schlib(void) {
|
||
|
INT test = 0;
|
||
|
I32 n1 = 0x73215609;
|
||
|
I64 n2 = n1 * 37;
|
||
|
I32 n3 = (I32)1<<31;
|
||
|
I64 n4 = (I64)1<<63;
|
||
|
I32 n5 = -1;
|
||
|
|
||
|
SCHLIBTEST(Sinteger_value(Sinteger(n1)) == n1)
|
||
|
SCHLIBTEST(Sinteger_value(Sinteger(-n1)) == -n1)
|
||
|
SCHLIBTEST(Sinteger_value(Sunsigned(n1)) == n1)
|
||
|
SCHLIBTEST(Sinteger_value(Sunsigned(-n1)) == -n1)
|
||
|
SCHLIBTEST(Sinteger32_value(Sinteger32(n1)) == n1)
|
||
|
SCHLIBTEST(Sinteger32_value(Sinteger32(-n1)) == -n1)
|
||
|
SCHLIBTEST(Sinteger32_value(Sunsigned32(n1)) == n1)
|
||
|
SCHLIBTEST(Sinteger32_value(Sunsigned32(-n1)) == -n1)
|
||
|
SCHLIBTEST(Sinteger64_value(Sinteger64(n1)) == n1)
|
||
|
SCHLIBTEST(Sinteger64_value(Sinteger64(-n1)) == -n1)
|
||
|
SCHLIBTEST(Sinteger64_value(Sunsigned64(n1)) == n1)
|
||
|
SCHLIBTEST(Sinteger64_value(Sunsigned64(-n1)) == -n1)
|
||
|
#if (ptr_bits == 64)
|
||
|
SCHLIBTEST(Sinteger_value(Sinteger(n2)) == n2)
|
||
|
SCHLIBTEST(Sinteger_value(Sinteger(-n2)) == -n2)
|
||
|
SCHLIBTEST(Sinteger_value(Sunsigned(n2)) == n2)
|
||
|
SCHLIBTEST(Sinteger_value(Sunsigned(-n2)) == -n2)
|
||
|
#endif
|
||
|
SCHLIBTEST(Sinteger64_value(Sinteger64(n2)) == n2)
|
||
|
SCHLIBTEST(Sinteger64_value(Sinteger64(-n2)) == -n2)
|
||
|
SCHLIBTEST(Sinteger64_value(Sunsigned64(n2)) == n2)
|
||
|
SCHLIBTEST(Sinteger64_value(Sunsigned64(-n2)) == -n2)
|
||
|
|
||
|
SCHLIBTEST(Sinteger_value(Sinteger(n3)) == n3)
|
||
|
SCHLIBTEST(Sinteger_value(Sunsigned(n3)) == n3)
|
||
|
SCHLIBTEST(Sinteger32_value(Sinteger32(n3)) == n3)
|
||
|
SCHLIBTEST(Sinteger32_value(Sunsigned32(n3)) == n3)
|
||
|
SCHLIBTEST(Sinteger64_value(Sinteger64(n3)) == n3)
|
||
|
SCHLIBTEST(Sinteger64_value(Sunsigned64(n3)) == n3)
|
||
|
#if (ptr_bits == 64)
|
||
|
SCHLIBTEST(Sinteger_value(Sunsigned(n4)) == n4)
|
||
|
SCHLIBTEST(Sinteger_value(Sinteger(n4)) == n4)
|
||
|
SCHLIBTEST(Sinteger_value(Sunsigned(n4)) == n4)
|
||
|
#endif
|
||
|
SCHLIBTEST(Sinteger64_value(Sinteger64(n4)) == n4)
|
||
|
SCHLIBTEST(Sinteger64_value(Sunsigned64(n4)) == n4)
|
||
|
|
||
|
SCHLIBTEST(Sinteger_value(Sinteger(n5)) == n5)
|
||
|
SCHLIBTEST(Sinteger_value(Sinteger(-n5)) == -n5)
|
||
|
SCHLIBTEST(Sinteger_value(Sunsigned(n5)) == n5)
|
||
|
SCHLIBTEST(Sinteger_value(Sunsigned(-n5)) == -n5)
|
||
|
SCHLIBTEST(Sinteger32_value(Sinteger32(n5)) == n5)
|
||
|
SCHLIBTEST(Sinteger32_value(Sinteger32(-n5)) == -n5)
|
||
|
SCHLIBTEST(Sinteger32_value(Sunsigned32(n5)) == n5)
|
||
|
SCHLIBTEST(Sinteger32_value(Sunsigned32(-n5)) == -n5)
|
||
|
SCHLIBTEST(Sinteger64_value(Sinteger64(n5)) == n5)
|
||
|
SCHLIBTEST(Sinteger64_value(Sinteger64(-n5)) == -n5)
|
||
|
SCHLIBTEST(Sinteger64_value(Sunsigned64(n5)) == n5)
|
||
|
SCHLIBTEST(Sinteger64_value(Sunsigned64(-n5)) == -n5)
|
||
|
}
|
||
|
|
||
|
/* place to break when debugging */
|
||
|
static void s_breakhere(UNUSED ptr x) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
static IBOOL s_interactivep(void) {
|
||
|
static INT interactivep = -1;
|
||
|
if (interactivep == -1) {
|
||
|
#ifdef WIN32
|
||
|
HANDLE hStdout, hStdin;
|
||
|
CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
|
||
|
DWORD InMode, OutMode;
|
||
|
interactivep =
|
||
|
(hStdin = GetStdHandle(STD_INPUT_HANDLE)) != INVALID_HANDLE_VALUE
|
||
|
&& (hStdout = GetStdHandle(STD_OUTPUT_HANDLE)) != INVALID_HANDLE_VALUE
|
||
|
&& GetConsoleScreenBufferInfo(hStdout, &csbiInfo)
|
||
|
&& GetConsoleMode(hStdin, &InMode)
|
||
|
&& GetConsoleMode(hStdout, &OutMode);
|
||
|
#else /* WIN32 */
|
||
|
interactivep = isatty(0) && isatty(1);
|
||
|
#endif /* WIN32 */
|
||
|
}
|
||
|
return interactivep;
|
||
|
}
|
||
|
|
||
|
static IBOOL s_same_devicep(INT fd1, INT fd2) {
|
||
|
#ifdef WIN32
|
||
|
HANDLE h1, h2; DWORD mode1, mode2;
|
||
|
if ((h1 = (HANDLE)_get_osfhandle(fd1)) != INVALID_HANDLE_VALUE)
|
||
|
if ((h2 = (HANDLE)_get_osfhandle(fd2)) != INVALID_HANDLE_VALUE)
|
||
|
switch (GetFileType(h1)) {
|
||
|
case FILE_TYPE_CHAR:
|
||
|
if (GetFileType(h2) == FILE_TYPE_CHAR)
|
||
|
return GetConsoleMode(h1, &mode1) && GetConsoleMode(h2, &mode2);
|
||
|
break;
|
||
|
case FILE_TYPE_DISK:
|
||
|
if (GetFileType(h2) == FILE_TYPE_DISK) {
|
||
|
BY_HANDLE_FILE_INFORMATION info1, info2;
|
||
|
if (GetFileInformationByHandle(h1, &info1) && GetFileInformationByHandle(h1, &info2))
|
||
|
return info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber
|
||
|
&& info1.nFileIndexHigh == info2.nFileIndexHigh
|
||
|
&& info1.nFileIndexLow == info2.nFileIndexLow;
|
||
|
}
|
||
|
break;
|
||
|
case FILE_TYPE_PIPE:
|
||
|
/* no clue */
|
||
|
break;
|
||
|
default: break;
|
||
|
}
|
||
|
#else /* WIN32 */
|
||
|
struct STATBUF statbuf1, statbuf2;
|
||
|
if (FSTAT(fd1, &statbuf1) == 0 && FSTAT(fd2, &statbuf2) == 0)
|
||
|
return statbuf1.st_ino == statbuf2.st_ino;
|
||
|
#endif /* WIN32 */
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static uptr s_malloc(iptr n) {
|
||
|
void *p;
|
||
|
if ((p = malloc((size_t)n)) == NULL) {
|
||
|
ptr msg = S_strerror(errno);
|
||
|
|
||
|
if (msg != Sfalse)
|
||
|
S_error1("foreign-alloc", "~a", msg);
|
||
|
else
|
||
|
S_error("foreign-alloc", "malloc failed");
|
||
|
}
|
||
|
return (uptr)p;
|
||
|
}
|
||
|
|
||
|
static void s_free(uptr addr) {
|
||
|
free((void *)addr);
|
||
|
}
|
||
|
|
||
|
#ifdef FEATURE_ICONV
|
||
|
#ifdef WIN32
|
||
|
typedef void *iconv_t;
|
||
|
typedef __declspec(dllimport) iconv_t (*iconv_open_ft)(const char *tocode, const char *fromcode);
|
||
|
typedef __declspec(dllimport) size_t (*iconv_ft)(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
|
||
|
typedef __declspec(dllimport) int (*iconv_close_ft)(iconv_t cd);
|
||
|
|
||
|
static iconv_open_ft iconv_open_f = (iconv_open_ft)0;
|
||
|
static iconv_ft iconv_f = (iconv_ft)0;
|
||
|
static iconv_close_ft iconv_close_f = (iconv_close_ft)0;
|
||
|
#define ICONV_OPEN iconv_open_f
|
||
|
#define ICONV iconv_f
|
||
|
#define ICONV_CLOSE iconv_close_f
|
||
|
#else
|
||
|
#include <iconv.h>
|
||
|
#define ICONV_OPEN iconv_open
|
||
|
#define ICONV iconv
|
||
|
#define ICONV_CLOSE iconv_close
|
||
|
#endif
|
||
|
|
||
|
#ifdef WIN32
|
||
|
static ptr s_iconv_trouble(HMODULE h, const char *what) {
|
||
|
wchar_t dllw[PATH_MAX];
|
||
|
char *dll;
|
||
|
size_t n;
|
||
|
char *msg;
|
||
|
ptr r;
|
||
|
if (0 != GetModuleFileNameW(h, dllw, PATH_MAX))
|
||
|
dll = Swide_to_utf8(dllw);
|
||
|
else
|
||
|
dll = NULL;
|
||
|
FreeLibrary(h);
|
||
|
n = strlen(what) + strlen(dll) + 17;
|
||
|
msg = (char *)malloc(n);
|
||
|
sprintf_s(msg, n, "cannot find %s in %s", what, dll);
|
||
|
free(dll);
|
||
|
r = Sstring_utf8(msg, -1);
|
||
|
free(msg);
|
||
|
return r;
|
||
|
}
|
||
|
#endif /* WIN32 */
|
||
|
|
||
|
static ptr s_iconv_open(const char *tocode, const char *fromcode) {
|
||
|
iconv_t cd;
|
||
|
#ifdef WIN32
|
||
|
static int iconv_is_loaded = 0;
|
||
|
if (!iconv_is_loaded) {
|
||
|
HMODULE h = LoadLibraryW(L"iconv.dll");
|
||
|
if (h == NULL) h = LoadLibraryW(L"libiconv.dll");
|
||
|
if (h == NULL) h = LoadLibraryW(L"libiconv-2.dll");
|
||
|
if (h == NULL) h = LoadLibraryW(L".\\iconv.dll");
|
||
|
if (h == NULL) h = LoadLibraryW(L".\\libiconv.dll");
|
||
|
if (h == NULL) h = LoadLibraryW(L".\\libiconv-2.dll");
|
||
|
if (h == NULL) return Sstring("cannot load iconv.dll, libiconv.dll, or libiconv-2.dll");
|
||
|
if ((iconv_open_f = (iconv_open_ft)GetProcAddress(h, "iconv_open")) == NULL &&
|
||
|
(iconv_open_f = (iconv_open_ft)GetProcAddress(h, "libiconv_open")) == NULL)
|
||
|
return s_iconv_trouble(h, "iconv_open or libiconv_open");
|
||
|
if ((iconv_f = (iconv_ft)GetProcAddress(h, "iconv")) == NULL &&
|
||
|
(iconv_f = (iconv_ft)GetProcAddress(h, "libiconv")) == NULL)
|
||
|
return s_iconv_trouble(h, "iconv or libiconv");
|
||
|
if ((iconv_close_f = (iconv_close_ft)GetProcAddress(h, "iconv_close")) == NULL &&
|
||
|
(iconv_close_f = (iconv_close_ft)GetProcAddress(h, "libiconv_close")) == NULL)
|
||
|
return s_iconv_trouble(h, "iconv_close or libiconv_close");
|
||
|
iconv_is_loaded = 1;
|
||
|
}
|
||
|
#endif /* WIN32 */
|
||
|
|
||
|
if ((cd = ICONV_OPEN(tocode, fromcode)) == (iconv_t)-1) return Sfalse;
|
||
|
|
||
|
/* have to be able to cast to int, since iconv_open can return (iconv_t)-1 */
|
||
|
return Sunsigned((uptr)cd);
|
||
|
}
|
||
|
|
||
|
static void s_iconv_close(uptr cd) {
|
||
|
ICONV_CLOSE((iconv_t)cd);
|
||
|
}
|
||
|
|
||
|
#define ICONV_BUFSIZ 400
|
||
|
|
||
|
static ptr s_iconv_from_string(uptr cd, ptr in, uptr i, uptr iend, ptr out, uptr o, uptr oend) {
|
||
|
U32 buf[ICONV_BUFSIZ];
|
||
|
char *inbuf, *outbuf;
|
||
|
size_t inbytesleft, outbytesleft;
|
||
|
uptr inmax, k, new_i, new_o;
|
||
|
|
||
|
outbuf = (char *)&BVIT(out, o);
|
||
|
outbytesleft = oend - o;
|
||
|
|
||
|
inmax = iend - i;
|
||
|
if (inmax > ICONV_BUFSIZ) inmax = ICONV_BUFSIZ;
|
||
|
if (inmax > outbytesleft) inmax = outbytesleft;
|
||
|
for (k = 0; k < inmax; k += 1) buf[k] = Sstring_ref(in, i + k);
|
||
|
|
||
|
inbuf = (char *)buf;
|
||
|
inbytesleft = inmax * sizeof(string_char);
|
||
|
|
||
|
/* we ignore the iconv return value because we consider success to be the consumption
|
||
|
of input or production of output. we set errno to 0 before calling iconv, even though
|
||
|
it should be set properly if neither input is consumed nor output is produced, because,
|
||
|
under Windows, the iconv dll might have been linked against a different C runtime
|
||
|
and might therefore set a different errno */
|
||
|
errno = 0;
|
||
|
ICONV((iconv_t)cd, (ICONV_INBUF_TYPE)&inbuf, &inbytesleft, &outbuf, &outbytesleft);
|
||
|
new_i = i + inmax - inbytesleft / sizeof(string_char);
|
||
|
new_o = oend - outbytesleft;
|
||
|
if (new_i != i || new_o != o) return Scons(Sinteger(new_i), Sinteger(new_o));
|
||
|
|
||
|
switch (errno) {
|
||
|
case EILSEQ: return FIX(SICONV_INVALID);
|
||
|
case EINVAL: return FIX(SICONV_INCOMPLETE);
|
||
|
case E2BIG: return FIX(SICONV_NOROOM);
|
||
|
default: return FIX(SICONV_DUNNO);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static ptr s_iconv_to_string(uptr cd, ptr in, uptr i, uptr iend, ptr out, uptr o, uptr oend) {
|
||
|
U32 buf[ICONV_BUFSIZ];
|
||
|
char *inbuf, *outbuf;
|
||
|
size_t inbytesleft, outbytesleft;
|
||
|
uptr outmax, k, new_i, new_o;
|
||
|
|
||
|
inbuf = (char *)&BVIT(in, i);
|
||
|
inbytesleft = iend - i;
|
||
|
|
||
|
outmax = oend - o;
|
||
|
if (outmax > ICONV_BUFSIZ) outmax = ICONV_BUFSIZ;
|
||
|
if (outmax > inbytesleft) outmax = inbytesleft;
|
||
|
|
||
|
outbuf = (char *)buf;
|
||
|
outbytesleft = outmax * sizeof(string_char);
|
||
|
|
||
|
/* see the comment about the iconv return value and errno in s_iconv_from_string */
|
||
|
errno = 0;
|
||
|
ICONV((iconv_t)cd, (ICONV_INBUF_TYPE)&inbuf, &inbytesleft, &outbuf, &outbytesleft);
|
||
|
|
||
|
outmax -= outbytesleft / sizeof(string_char);
|
||
|
for (k = 0; k < outmax; k += 1) Sstring_set(out, o + k, buf[k]);
|
||
|
new_i = iend - inbytesleft;
|
||
|
new_o = o + outmax;
|
||
|
if (new_i != i || new_o != o) return Scons(Sinteger(new_i), Sinteger(new_o));
|
||
|
|
||
|
switch (errno) {
|
||
|
case EILSEQ: return FIX(SICONV_INVALID);
|
||
|
case EINVAL: return FIX(SICONV_INCOMPLETE);
|
||
|
case E2BIG: return FIX(SICONV_NOROOM);
|
||
|
default: return FIX(SICONV_DUNNO);
|
||
|
}
|
||
|
}
|
||
|
#endif /* FEATURE_ICONV */
|
||
|
|
||
|
#ifdef WIN32
|
||
|
static ptr s_multibytetowidechar(unsigned cp, ptr inbv) {
|
||
|
uptr inbytes; int outwords; ptr outbv;
|
||
|
|
||
|
inbytes = Sbytevector_length(inbv);
|
||
|
|
||
|
#if (ptr_bits > int_bits)
|
||
|
if ((int)inbytes != inbytes) S_error1("multibyte->string", "input size ~s is beyond MultiByteToWideChar's limit", Sinteger(inbytes));
|
||
|
#endif
|
||
|
|
||
|
if ((outwords = MultiByteToWideChar(cp, 0, &BVIT(inbv,0), (int)inbytes, NULL, 0)) == 0)
|
||
|
S_error1("multibyte->string", "conversion failed: ~a", S_LastErrorString());
|
||
|
|
||
|
outbv = S_bytevector(outwords * 2);
|
||
|
|
||
|
if (MultiByteToWideChar(cp, 0, &BVIT(inbv,0), (int)inbytes, (wchar_t *)&BVIT(outbv, 0), outwords) == 0)
|
||
|
S_error1("multibyte->string", "conversion failed: ~a", S_LastErrorString());
|
||
|
|
||
|
return outbv;
|
||
|
}
|
||
|
|
||
|
static ptr s_widechartomultibyte(unsigned cp, ptr inbv) {
|
||
|
uptr inwords; int outbytes; ptr outbv;
|
||
|
|
||
|
inwords = Sbytevector_length(inbv) / 2;
|
||
|
|
||
|
#if (ptr_bits > int_bits)
|
||
|
if ((int)inwords != inwords) S_error1("multibyte->string", "input size ~s is beyond WideCharToMultiByte's limit", Sinteger(inwords));
|
||
|
#endif
|
||
|
|
||
|
if ((outbytes = WideCharToMultiByte(cp, 0, (wchar_t *)&BVIT(inbv,0), (int)inwords, NULL, 0, NULL, NULL)) == 0)
|
||
|
S_error1("string->multibyte", "conversion failed: ~a", S_LastErrorString());
|
||
|
|
||
|
outbv = S_bytevector(outbytes);
|
||
|
|
||
|
if (WideCharToMultiByte(cp, 0, (wchar_t *)&BVIT(inbv,0), (int)inwords, &BVIT(outbv, 0), outbytes, NULL, NULL) == 0)
|
||
|
S_error1("string->multibyte", "conversion failed: ~a", S_LastErrorString());
|
||
|
|
||
|
return outbv;
|
||
|
}
|
||
|
#endif /* WIN32 */
|