#include "ikarus-data.h" #include #include #include #include ikptr ikrt_isapointer(ikptr x, ikpcb* pcb){ if ((tagof(x) == vector_tag) && (ref(x, -vector_tag) == pointer_tag)) { return true_object; } else { return false_object; } } ikptr ikrt_pointer_to_int(ikptr x, ikpcb* pcb) { long int p = (long int) ref(x, wordsize-vector_tag); ikptr pfx = fix(p); if (unfix(pfx) == p) { return pfx; } else { ikptr bn = ik_safe_alloc(pcb, align(wordsize+disp_bignum_data)); if (p > 0){ ref(bn, 0) = (ikptr)(bignum_tag | (1 << bignum_length_shift)); ref(bn, disp_bignum_data) = (ikptr)p; } else { ref(bn, 0) = (ikptr)(bignum_tag | (1 << bignum_length_shift) | (1 << bignum_sign_shift)); ref(bn, disp_bignum_data) = (ikptr)-p; } return bn+vector_tag; } } ikptr make_pointer(long x, ikpcb* pcb) { ikptr r = ik_safe_alloc(pcb, pointer_size); ref(r, 0) = pointer_tag; ref(r, wordsize) = (ikptr)x; return r+vector_tag; } #define bnfst_negative(x) \ (((unsigned long int)(x)) & bignum_sign_mask) static long integer_to_long(ikptr x) { if (is_fixnum(x)) { return ((long)x) >> fx_shift; } else { if(bnfst_negative(ref(x, -vector_tag))){ return -(long)ref(x, wordsize-vector_tag); } else { return (long)ref(x, wordsize-vector_tag); } } } ikptr ikrt_fx_to_pointer(ikptr x, ikpcb* pcb) { return make_pointer(unfix(x), pcb); } ikptr ikrt_bn_to_pointer(ikptr x, ikpcb* pcb) { if(bnfst_negative(ref(x, -vector_tag))){ return make_pointer(-ref(x, wordsize-vector_tag), pcb); } else { return make_pointer(ref(x, wordsize-vector_tag), pcb); } } #if 0 ikptr ikrt_pointer_null(ikptr x /*, ikpcb* pcb*/) { return ref(x, off_pointer_data) ? true_object : false_object; } #endif ikptr ikrt_dlerror(ikpcb* pcb) { char* str = dlerror(); if (str == NULL) { return false_object; } int len = strlen(str); ikptr bv = ik_safe_alloc(pcb, align(disp_bytevector_data + len + 1)); ref(bv, 0) = fix(len); memcpy((void*)(bv+disp_bytevector_data), str, len+1); return bv+bytevector_tag; } #ifndef RTLD_LOCAL #define RTLD_LOCAL 0 /* for cygwin, possibly incorrect */ #endif ikptr ikrt_dlopen(ikptr x, ikptr load_lazy, ikptr load_global, ikpcb* pcb) { int flags = ((load_lazy == false_object) ? RTLD_NOW : RTLD_LAZY) | ((load_global == false_object) ? RTLD_LOCAL : RTLD_GLOBAL); char* name = (x == false_object) ? NULL : (char*)(x + off_bytevector_data); void* p = dlopen(name, flags); if (p == NULL) { return false_object; } else { return make_pointer((long int) p, pcb); } } ikptr ikrt_dlclose(ikptr x /*, ikpcb* pcb*/) { int r = dlclose((void*) ref(x, off_pointer_data)); return (r == 0) ? true_object : false_object; } ikptr ikrt_dlsym(ikptr handle, ikptr sym, ikpcb* pcb) { void* p = dlsym((void*)ref(handle, off_pointer_data), ((char*)sym) + off_bytevector_data); if (p == NULL) { return false_object; } else { return make_pointer((long int) p, pcb); } } ikptr ikrt_malloc(ikptr len, ikpcb* pcb) { void* p = malloc(unfix(len)); if (p == NULL) { return false_object; } else { return make_pointer((long int) p, pcb); } } ikptr ikrt_free(ikptr x) { free((void*) ref(x, off_pointer_data)); return void_object; } ikptr ikrt_memcpy_to_bv(ikptr dst, ikptr dst_off, ikptr src, ikptr count /*, ikpcb* pcb */) { void *src_ptr, *dst_ptr; src_ptr = (void *)ref(src, off_pointer_data); dst_ptr = (void *)(dst + off_bytevector_data + unfix(dst_off)); memcpy(dst_ptr, src_ptr, unfix(count)); return void_object; } ikptr ikrt_memcpy_from_bv(ikptr dst, ikptr src, ikptr src_off, ikptr count /*, ikpcb* pcb */) { void *src_ptr, *dst_ptr; src_ptr = (void *)(src + off_bytevector_data + unfix(src_off)); dst_ptr = (void *)ref(dst, off_pointer_data); memcpy(dst_ptr, src_ptr, unfix(count)); return void_object; } ikptr ikrt_ref_char(ikptr p, ikptr off /*, ikpcb* pcb*/) { return fix(*((signed char*)(((long)ref(p, off_pointer_data)) + unfix(off)))); } ikptr ikrt_ref_uchar(ikptr p, ikptr off /*, ikpcb* pcb*/) { return fix(*((unsigned char*)(((long)ref(p, off_pointer_data)) + unfix(off)))); } ikptr ikrt_ref_short(ikptr p, ikptr off /*, ikpcb* pcb*/) { return fix(*((signed short*)(((long)ref(p, off_pointer_data)) + unfix(off)))); } ikptr ikrt_ref_ushort(ikptr p, ikptr off /*, ikpcb* pcb*/) { return fix(*((unsigned short*)(((long)ref(p, off_pointer_data)) + unfix(off)))); } ikptr ikrt_ref_pointer(ikptr p, ikptr off, ikpcb* pcb) { long idx = integer_to_long(off); void* ptr = (void*)ref(p, off_pointer_data); return make_pointer(ref(ptr, idx), pcb); } ikptr ikrt_set_pointer(ikptr p, ikptr off, ikptr v /*, ikpcb* pcb*/) { long idx = integer_to_long(off); void* ptr = (void*)ref(p, off_pointer_data); ref(ptr, idx) = ref(v, off_pointer_data); return void_object; } static ikptr double_to_flonum(double x, ikpcb* pcb){ ikptr r = ik_safe_alloc(pcb, flonum_size) + vector_tag; ref(r, -vector_tag) = flonum_tag; flonum_data(r) = x; return r; } ikptr ikrt_set_float(ikptr p, ikptr off, ikptr v /*, ikpcb* pcb*/) { long idx = integer_to_long(off); ikptr ptr = ref(p, off_pointer_data); *((float*)(ptr+idx)) = flonum_data(v); return void_object; } ikptr ikrt_ref_float(ikptr p, ikptr off, ikpcb* pcb) { long idx = integer_to_long(off); ikptr ptr = ref(p, off_pointer_data); double v = *((float*)(ptr+idx)); return double_to_flonum(v, pcb); } ikptr ikrt_set_double(ikptr p, ikptr off, ikptr v /*, ikpcb* pcb*/) { long idx = integer_to_long(off); ikptr ptr = ref(p, off_pointer_data); *((double*)(ptr+idx)) = flonum_data(v); return void_object; } ikptr ikrt_ref_double(ikptr p, ikptr off, ikpcb* pcb) { long idx = integer_to_long(off); ikptr ptr = ref(p, off_pointer_data); double v = *((double*)(ptr+idx)); return double_to_flonum(v, pcb); } ikptr s_to_number(signed long n, ikpcb* pcb) { ikptr fx = fix(n); if (unfix(fx) == n) { return fx; } ikptr bn = ik_safe_alloc(pcb, align(wordsize+disp_bignum_data)); if (n > 0){ ref(bn, 0) = (ikptr)(bignum_tag | (1 << bignum_length_shift)); ref(bn, disp_bignum_data) = (ikptr)n; } else { ref(bn, 0) = (ikptr)(bignum_tag | (1 << bignum_length_shift) | (1 << bignum_sign_shift)); ref(bn, disp_bignum_data) = (ikptr)-n; } return bn+vector_tag; } ikptr sll_to_number(signed long long n, ikpcb* pcb) { if (((signed long long)(signed long) n) == n) { return s_to_number(n, pcb); } int len = sizeof(long long) / sizeof(mp_limb_t); ikptr bn = ik_safe_alloc(pcb, align(sizeof(long long)+disp_bignum_data)); if (n > 0){ ref(bn, 0) = (ikptr)(bignum_tag | (len << bignum_length_shift)); *((long long*)(bn+disp_bignum_data)) = n; } else { ref(bn, 0) = (ikptr)(bignum_tag | (len << bignum_length_shift) | (1 << bignum_sign_shift)); *((long long*)(bn+disp_bignum_data)) = -n; } return bn+vector_tag; } ikptr u_to_number(unsigned long n, ikpcb* pcb) { unsigned long mxn = ((unsigned long)-1)>>(fx_shift+1); if (n <= mxn) { return fix(n); } ikptr bn = ik_safe_alloc(pcb, align(wordsize+disp_bignum_data)); ref(bn, 0) = (ikptr)(bignum_tag | (1 << bignum_length_shift)); ref(bn, disp_bignum_data) = (ikptr)n; return bn+vector_tag; } ikptr ull_to_number(unsigned long long n, ikpcb* pcb) { if (((unsigned long long)(unsigned long) n) == n) { return u_to_number(n, pcb); } ikptr bn = ik_safe_alloc(pcb, align(disp_bignum_data+sizeof(long long))); bcopy((char*)(&n), (char*)(bn+disp_bignum_data), sizeof(long long)); return normalize_bignum(sizeof(long long)/sizeof(mp_limb_t), 0, bn); } ikptr d_to_number(double n, ikpcb* pcb) { ikptr x = ik_safe_alloc(pcb, flonum_size) + vector_tag; ref(x, -vector_tag) = flonum_tag; flonum_data(x) = n; return x; } ikptr ikrt_ref_int(ikptr p, ikptr off , ikpcb* pcb) { signed int r = *((signed int*)(((long)ref(p, off_pointer_data)) + unfix(off))); if (wordsize == 8) { return fix(r); } else { return s_to_number(r, pcb); } } ikptr ikrt_ref_uint(ikptr p, ikptr off , ikpcb* pcb) { unsigned int r = *((unsigned int*)(((long)ref(p, off_pointer_data)) + unfix(off))); if (wordsize == 8) { return fix(r); } else { return u_to_number(r, pcb); } } ikptr ikrt_ref_long(ikptr p, ikptr off , ikpcb* pcb) { signed long r = *((signed long*)(((long)ref(p, off_pointer_data)) + unfix(off))); return s_to_number(r, pcb); } ikptr ikrt_ref_ulong(ikptr p, ikptr off , ikpcb* pcb) { unsigned long r = *((unsigned long*)(((long)ref(p, off_pointer_data)) + unfix(off))); return u_to_number(r, pcb); } ikptr ikrt_ref_longlong(ikptr p, ikptr off , ikpcb* pcb) { signed long long r = *((signed long long*)(((long)ref(p, off_pointer_data)) + unfix(off))); return sll_to_number(r, pcb); } ikptr ikrt_ref_ulonglong(ikptr p, ikptr off , ikpcb* pcb) { unsigned long long r = *((unsigned long long*)(((long)ref(p, off_pointer_data)) + unfix(off))); return ull_to_number(r, pcb); } long extract_num(ikptr x) { if (is_fixnum(x)) { return unfix(x); } else if (x == void_object) { return 0; } else { if (bnfst_negative(ref(x, -vector_tag))){ return (long)(-ref(x, wordsize-vector_tag)); } else { return (long)(ref(x, wordsize-vector_tag)); } } } long long extract_num_longlong(ikptr x) { if (is_fixnum(x)) { return unfix(x); } else if (x == void_object) { return 0; } else { ikptr fst = ref(x, -vector_tag); ikptr pos_one_limb_tag = (ikptr)(bignum_tag | (1 << bignum_length_shift)); ikptr neg_one_limb_tag = (ikptr)(pos_one_limb_tag | (1 << bignum_sign_shift)); if (fst == pos_one_limb_tag) { return (unsigned long)ref(x, wordsize-vector_tag); } else if (fst == neg_one_limb_tag) { return -(signed long)ref(x, wordsize-vector_tag); } else if (bnfst_negative(fst)) { return -(*((long long*)(x+wordsize-vector_tag))); } else { return *((long long*)(x+wordsize-vector_tag)); } } } ikptr ikrt_set_char(ikptr p, ikptr off, ikptr v/*, ikpcb* pcb*/) { *((char*)(((long)ref(p, off_pointer_data)) + unfix(off))) = extract_num(v); return void_object; } ikptr ikrt_set_short(ikptr p, ikptr off, ikptr v/*, ikpcb* pcb*/) { *((short*)(((long)ref(p, off_pointer_data)) + unfix(off))) = extract_num(v); return void_object; } ikptr ikrt_set_int(ikptr p, ikptr off, ikptr v/*, ikpcb* pcb*/) { *((int*)(((long)ref(p, off_pointer_data)) + unfix(off))) = extract_num(v); return void_object; } ikptr ikrt_set_long(ikptr p, ikptr off, ikptr v/*, ikpcb* pcb*/) { *((long*)(((long)ref(p, off_pointer_data)) + unfix(off))) = extract_num(v); return void_object; } ikptr ikrt_set_longlong(ikptr p, ikptr off, ikptr v/*, ikpcb* pcb*/) { *((long long*)(((long)ref(p, off_pointer_data)) + unfix(off))) = extract_num_longlong(v); return void_object; }