
This commit does four things: * Adds "pb.ss" and "pb.c", which implement a portable bytecode backend and interpreter that is intended for bootstrapping. A single set of pb bootfiles can support bootstrapping on all platforms --- as long as the C compiler supports a 64-bit integer type. The pb machine supports foreign calls for only a small set of recognized prototypes, and it does not support foriegn callables. Use `./configure --pb` to build the pb variant. * Changes the kernel's casts between `ptr` and `void*` types. In a pb build, the `ptr` type can be a 64-bit integer type while `void*` is a 32-bit pointer type, so casts must go through an intermediate integer type. * Adjusts the compiler to accomodate run-time-determined endianness. Making the compiler agnostic to word size is not practical, but only a few pieces depend on the target machine's endianness, and those can generally be deferred to a run-time choice of byte-based operations. The one exception is that ftype bit fields are not allowed unless accompanied by an explicit endianness declaration. * Start reducing duplication among platform-specific makefiles. For example, `Mf-ta6osx` chains to `Mf-a6osx` to avoid repeating most of it. A lot more can be done here. original commit: 97533fa9d8b8400b0dc1a890768c7d30c91257e0
346 lines
9.0 KiB
C
346 lines
9.0 KiB
C
/* intern.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"
|
|
|
|
/* locally defined functions */
|
|
static void oblist_insert PROTO((ptr sym, iptr idx, IGEN g));
|
|
static iptr hash PROTO((const unsigned char *s, iptr n));
|
|
static iptr hash_sc PROTO((const string_char *s, iptr n));
|
|
static iptr hash_uname PROTO((const string_char *s, iptr n));
|
|
static ptr mkstring PROTO((const string_char *s, iptr n));
|
|
|
|
#define OBINDEX(hc, len) ((hc) & ((len) - 1))
|
|
#define MIN_OBLIST_LENGTH 4096
|
|
|
|
void S_intern_init() {
|
|
IGEN g;
|
|
|
|
if (!S_boot_time) return;
|
|
|
|
S_G.oblist_length = MIN_OBLIST_LENGTH;
|
|
S_G.oblist_count = 0;
|
|
S_G.oblist = S_getmem(S_G.oblist_length * sizeof(bucket *), 1);
|
|
for (g = 0; g < static_generation; g += 1) S_G.buckets_of_generation[g] = NULL;
|
|
}
|
|
|
|
static void oblist_insert(ptr sym, iptr idx, IGEN g) {
|
|
bucket *b, *oldb, **pb;
|
|
|
|
find_room_voidp(g == 0 ? space_new : space_data, g, ptr_align(sizeof(bucket)), b);
|
|
b->sym = sym;
|
|
if (g == 0) {
|
|
b->next = S_G.oblist[idx];
|
|
S_G.oblist[idx] = b;
|
|
} else {
|
|
for (pb = &S_G.oblist[idx]; (oldb = *pb) != NULL && SegmentGeneration(addr_get_segment(TO_PTR(oldb))) < g; pb = &oldb->next);
|
|
b->next = oldb;
|
|
*pb = b;
|
|
}
|
|
|
|
if (g != static_generation) {
|
|
bucket_list *bl;
|
|
find_room_voidp(g == 0 ? space_new : space_data, g, ptr_align(sizeof(bucket_list)), bl);
|
|
bl->car = b;
|
|
bl->cdr = S_G.buckets_of_generation[g];
|
|
S_G.buckets_of_generation[g] = bl;
|
|
}
|
|
|
|
S_G.oblist_count += 1;
|
|
}
|
|
|
|
void S_resize_oblist(void) {
|
|
bucket **new_oblist, *b, *oldb, **pb, *bnext;
|
|
iptr new_oblist_length, i, idx, inc = 0, dinc = 0;
|
|
ptr sym;
|
|
IGEN g;
|
|
|
|
new_oblist_length = MIN_OBLIST_LENGTH;
|
|
while ((new_oblist_length >> 1) < S_G.oblist_count)
|
|
new_oblist_length <<= 1;
|
|
|
|
if (new_oblist_length == S_G.oblist_length)
|
|
return;
|
|
|
|
new_oblist = S_getmem(new_oblist_length * sizeof(bucket *), 1);
|
|
|
|
for (i = 0; i < S_G.oblist_length; i += 1) {
|
|
for (b = S_G.oblist[i]; b != NULL; b = bnext) {
|
|
int done = 0;
|
|
bnext = b->next;
|
|
sym = b->sym;
|
|
idx = OBINDEX(UNFIX(SYMHASH(sym)), new_oblist_length);
|
|
g = GENERATION(sym);
|
|
|
|
for (pb = &new_oblist[idx]; (oldb = *pb) != NULL && SegmentGeneration(addr_get_segment(TO_PTR(oldb))) < g; pb = &oldb->next) {
|
|
inc++;
|
|
if (done)
|
|
dinc++;
|
|
done = 1;
|
|
}
|
|
b->next = oldb;
|
|
*pb = b;
|
|
}
|
|
}
|
|
|
|
S_freemem(S_G.oblist, S_G.oblist_length * sizeof(bucket *));
|
|
S_G.bytesof[static_generation][countof_oblist] += (new_oblist_length - S_G.oblist_length) * sizeof(bucket *);
|
|
|
|
S_G.oblist_length = new_oblist_length;
|
|
S_G.oblist = new_oblist;
|
|
}
|
|
|
|
#define MIX_HASH(hc) (hc += (hc << 10), hc ^= (hc >> 6))
|
|
|
|
static iptr hash(const unsigned char *s, iptr n) {
|
|
uptr h = (uptr)n + 401887359;
|
|
while (n--) { h += *s++; MIX_HASH(h); }
|
|
return (iptr)h & most_positive_fixnum;
|
|
}
|
|
|
|
static iptr hash_sc(const string_char *s, iptr n) {
|
|
uptr h = (uptr)n + 401887359;
|
|
while (n--) { h += Schar_value(*s++); MIX_HASH(h); }
|
|
return (iptr)h & most_positive_fixnum;
|
|
}
|
|
|
|
static iptr hash_uname(const string_char *s, iptr n) {
|
|
/* attempting to get dissimilar hash codes for gensyms created in the same session */
|
|
iptr i = n, h = 0; iptr pos = 1; int d, c;
|
|
|
|
while (i-- > 0) {
|
|
if ((c = Schar_value(s[i])) == '-') {
|
|
if (pos <= 10) break;
|
|
return (h + 523658599) & most_positive_fixnum;
|
|
}
|
|
d = c - '0';
|
|
if (d < 0 || d > 9) break;
|
|
h += d * pos;
|
|
pos *= 10;
|
|
}
|
|
|
|
return hash_sc(s, n);
|
|
}
|
|
|
|
static ptr mkstring(const string_char *s, iptr n) {
|
|
iptr i;
|
|
ptr str = S_string(NULL, n);
|
|
for (i = 0; i != n; i += 1) STRIT(str, i) = s[i];
|
|
STRTYPE(str) |= string_immutable_flag;
|
|
return str;
|
|
}
|
|
|
|
ptr S_mkstring(const string_char *s, iptr n) {
|
|
return mkstring(s, n);
|
|
}
|
|
|
|
/* handles single-byte characters, implicit length */
|
|
ptr S_intern(const unsigned char *s) {
|
|
iptr n = strlen((const char *)s);
|
|
iptr hc = hash(s, n);
|
|
iptr idx = OBINDEX(hc, S_G.oblist_length);
|
|
ptr sym;
|
|
bucket *b;
|
|
|
|
tc_mutex_acquire()
|
|
|
|
b = S_G.oblist[idx];
|
|
while (b != NULL) {
|
|
sym = b->sym;
|
|
if (!GENSYMP(sym)) {
|
|
ptr str = SYMNAME(sym);
|
|
if (Sstring_length(str) == n) {
|
|
iptr i;
|
|
for (i = 0; ; i += 1) {
|
|
if (i == n) {
|
|
tc_mutex_release()
|
|
return sym;
|
|
}
|
|
if (Sstring_ref(str, i) != s[i]) break;
|
|
}
|
|
}
|
|
}
|
|
b = b->next;
|
|
}
|
|
|
|
sym = S_symbol(S_string((const char *)s, n));
|
|
INITSYMHASH(sym) = FIX(hc);
|
|
oblist_insert(sym, idx, 0);
|
|
|
|
tc_mutex_release()
|
|
return sym;
|
|
}
|
|
|
|
/* handles string_chars, explicit length */
|
|
ptr S_intern_sc(const string_char *name, iptr n, ptr name_str) {
|
|
iptr hc = hash_sc(name, n);
|
|
iptr idx = OBINDEX(hc, S_G.oblist_length);
|
|
ptr sym;
|
|
bucket *b;
|
|
|
|
tc_mutex_acquire()
|
|
|
|
b = S_G.oblist[idx];
|
|
while (b != NULL) {
|
|
sym = b->sym;
|
|
if (!GENSYMP(sym)) {
|
|
ptr str = SYMNAME(sym);
|
|
if (Sstring_length(str) == n) {
|
|
iptr i;
|
|
for (i = 0; ; i += 1) {
|
|
if (i == n) {
|
|
tc_mutex_release()
|
|
return sym;
|
|
}
|
|
if (STRIT(str, i) != name[i]) break;
|
|
}
|
|
}
|
|
}
|
|
b = b->next;
|
|
}
|
|
|
|
if ((name_str == Sfalse) || !(STRTYPE(name_str) & string_immutable_flag))
|
|
name_str = mkstring(name, n);
|
|
sym = S_symbol(name_str);
|
|
INITSYMHASH(sym) = FIX(hc);
|
|
oblist_insert(sym, idx, 0);
|
|
|
|
tc_mutex_release()
|
|
return sym;
|
|
}
|
|
|
|
ptr S_intern3(const string_char *pname, iptr plen, const string_char *uname, iptr ulen, ptr pname_str, ptr uname_str) {
|
|
iptr hc = hash_uname(uname, ulen);
|
|
iptr idx = OBINDEX(hc, S_G.oblist_length);
|
|
ptr sym;
|
|
bucket *b;
|
|
|
|
tc_mutex_acquire()
|
|
|
|
b = S_G.oblist[idx];
|
|
while (b != NULL) {
|
|
sym = b->sym;
|
|
if (GENSYMP(sym)) {
|
|
ptr str = Scar(SYMNAME(sym));
|
|
if (Sstring_length(str) == ulen) {
|
|
iptr i;
|
|
for (i = 0; ; i += 1) {
|
|
if (i == ulen) {
|
|
tc_mutex_release()
|
|
return sym;
|
|
}
|
|
if (STRIT(str, i) != uname[i]) break;
|
|
}
|
|
}
|
|
}
|
|
b = b->next;
|
|
}
|
|
|
|
if ((pname_str == Sfalse) || !(STRTYPE(pname_str) & string_immutable_flag))
|
|
pname_str = mkstring(pname, plen);
|
|
if ((uname_str == Sfalse) || !(STRTYPE(uname_str) & string_immutable_flag))
|
|
uname_str = mkstring(uname, ulen);
|
|
sym = S_symbol(Scons(uname_str, pname_str));
|
|
INITSYMHASH(sym) = FIX(hc);
|
|
oblist_insert(sym, idx, 0);
|
|
|
|
tc_mutex_release()
|
|
return sym;
|
|
}
|
|
|
|
void S_intern_gensym(sym) ptr sym; {
|
|
ptr uname_str = Scar(SYMNAME(sym));
|
|
const string_char *uname = &STRIT(uname_str, 0);
|
|
iptr ulen = Sstring_length(uname_str);
|
|
iptr hc = hash_uname(uname, ulen);
|
|
iptr idx = OBINDEX(hc, S_G.oblist_length);
|
|
bucket *b;
|
|
|
|
tc_mutex_acquire()
|
|
|
|
b = S_G.oblist[idx];
|
|
while (b != NULL) {
|
|
ptr x = b->sym;
|
|
if (GENSYMP(x)) {
|
|
ptr str = Scar(SYMNAME(x));
|
|
if (Sstring_length(str) == ulen) {
|
|
iptr i;
|
|
for (i = 0; ; i += 1) {
|
|
if (i == ulen) {
|
|
tc_mutex_release()
|
|
S_error1("intern-gensym", "unique name ~s already interned", uname_str);
|
|
}
|
|
if (STRIT(str, i) != uname[i]) break;
|
|
}
|
|
}
|
|
}
|
|
b = b->next;
|
|
}
|
|
|
|
INITSYMHASH(sym) = FIX(hc);
|
|
oblist_insert(sym, idx, GENERATION(sym));
|
|
|
|
tc_mutex_release()
|
|
}
|
|
|
|
/* must hold mutex */
|
|
ptr S_intern4(sym) ptr sym; {
|
|
ptr name = SYMNAME(sym);
|
|
ptr uname_str = (Sstringp(name) ? name : Scar(name));
|
|
const string_char *uname = &STRIT(uname_str, 0);
|
|
iptr ulen = Sstring_length(uname_str);
|
|
iptr hc = UNFIX(SYMHASH(sym));
|
|
iptr idx = OBINDEX(hc, S_G.oblist_length);
|
|
bucket *b;
|
|
|
|
b = S_G.oblist[idx];
|
|
while (b != NULL) {
|
|
ptr x = b->sym;
|
|
ptr x_name = SYMNAME(x);
|
|
if (Sstringp(name) == Sstringp(x_name)) {
|
|
ptr str = (Sstringp(x_name) ? x_name : Scar(x_name));
|
|
if (Sstring_length(str) == ulen) {
|
|
iptr i;
|
|
for (i = 0; ; i += 1) {
|
|
if (i == ulen) {
|
|
return x;
|
|
}
|
|
if (STRIT(str, i) != uname[i]) break;
|
|
}
|
|
}
|
|
}
|
|
b = b->next;
|
|
}
|
|
|
|
oblist_insert(sym, idx, GENERATION(sym));
|
|
|
|
return sym;
|
|
}
|
|
|
|
/* retrofit existing symbols once nonprocedure_code is available */
|
|
void S_retrofit_nonprocedure_code() {
|
|
ptr npc, sym, val; bucket_list *bl;
|
|
|
|
npc = S_G.nonprocedure_code;
|
|
|
|
/* assuming this happens early, before collector has been called, so need look only for generation 0 symbols */
|
|
for (bl = S_G.buckets_of_generation[0]; bl != NULL; bl = bl->cdr) {
|
|
sym = bl->car->sym;
|
|
val = SYMVAL(sym);
|
|
SETSYMCODE(sym, Sprocedurep(val) ? CLOSCODE(val) : npc);
|
|
}
|
|
}
|