LCOV - code coverage report
Current view: top level - src/flisp - cvalues.c (source / functions) Hit Total Coverage
Test: [build process] commit ef510b1f346f4c9f9d86eaceace5ca54961a1dbc Lines: 341 839 40.6 %
Date: 2022-07-17 01:01:28 Functions: 55 95 57.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 204 647 31.5 %

           Branch data     Line data    Source code
       1                 :            : #ifdef _P64
       2                 :            : #define NWORDS(sz) (((sz)+7)>>3)
       3                 :            : #else
       4                 :            : #define NWORDS(sz) (((sz)+3)>>2)
       5                 :            : #endif
       6                 :            : 
       7                 :            : struct prim_int16{ char a; int16_t i; };
       8                 :            : struct prim_int32{ char a; int32_t i; };
       9                 :            : struct prim_int64{ char a; int64_t i; };
      10                 :            : struct prim_ptr{ char a;  void   *i; };
      11                 :            : 
      12                 :            : // compute struct field alignment required for primitives
      13                 :            : static const int ALIGN2   = sizeof(struct prim_int16) - 2;
      14                 :            : static const int ALIGN4   = sizeof(struct prim_int32) - 4;
      15                 :            : static const int ALIGN8   = sizeof(struct prim_int64) - 8;
      16                 :            : static const int ALIGNPTR = sizeof(struct prim_ptr) - sizeof(void*);
      17                 :            : 
      18                 :            : static void cvalue_init(fl_context_t *fl_ctx, fltype_t *type, value_t v, void *dest);
      19                 :            : 
      20                 :            : // cvalues-specific builtins
      21                 :            : value_t cvalue_new(fl_context_t *fl_ctx, value_t *args, uint32_t nargs);
      22                 :            : value_t cvalue_sizeof(fl_context_t *fl_ctx, value_t *args, uint32_t nargs);
      23                 :            : value_t cvalue_typeof(fl_context_t *fl_ctx, value_t *args, uint32_t nargs);
      24                 :            : 
      25                 :            : // trigger unconditional GC after this many bytes are allocated
      26                 :            : #define ALLOC_LIMIT_TRIGGER 67108864
      27                 :            : 
      28                 :    2193280 : void add_finalizer(fl_context_t *fl_ctx, cvalue_t *cv)
      29                 :            : {
      30         [ +  + ]:    2193280 :     if (fl_ctx->nfinalizers == fl_ctx->maxfinalizers) {
      31         [ +  + ]:        142 :         size_t nn = (fl_ctx->maxfinalizers==0 ? 256 : fl_ctx->maxfinalizers*2);
      32                 :        142 :         cvalue_t **temp = (cvalue_t**)realloc(fl_ctx->Finalizers, nn*sizeof(value_t));
      33         [ -  + ]:        142 :         if (temp == NULL)
      34                 :          0 :             lerror(fl_ctx, fl_ctx->OutOfMemoryError, "out of memory");
      35                 :        142 :         fl_ctx->Finalizers = temp;
      36                 :        142 :         fl_ctx->maxfinalizers = nn;
      37                 :            :     }
      38                 :    2193280 :     fl_ctx->Finalizers[fl_ctx->nfinalizers++] = cv;
      39                 :    2193280 : }
      40                 :            : 
      41                 :            : // remove dead objects from finalization list in-place
      42                 :       4474 : static void sweep_finalizers(fl_context_t *fl_ctx)
      43                 :            : {
      44                 :       4474 :     cvalue_t **lst = fl_ctx->Finalizers;
      45                 :       4474 :     size_t n=0, ndel=0, l=fl_ctx->nfinalizers;
      46                 :            :     cvalue_t *tmp;
      47                 :            : #define SWAP_sf(a,b) (tmp=a,a=b,b=tmp,1)
      48         [ -  + ]:       4474 :     if (l == 0)
      49                 :          0 :         return;
      50                 :            :     do {
      51                 :    9562320 :         tmp = lst[n];
      52         [ +  + ]:    9562320 :         if (isforwarded((value_t)tmp)) {
      53                 :            :             // object is alive
      54                 :    7422700 :             lst[n] = (cvalue_t*)ptr(forwardloc((value_t)tmp));
      55                 :    7422700 :             n++;
      56                 :            :         }
      57                 :            :         else {
      58                 :    2139620 :             fltype_t *t = cv_class(tmp);
      59   [ +  +  +  + ]:    2139620 :             if (t->vtable != NULL && t->vtable->finalize != NULL) {
      60                 :    2077980 :                 t->vtable->finalize(fl_ctx, tagptr(tmp, TAG_CVALUE));
      61                 :            :             }
      62   [ +  +  +  - ]:    2139620 :             if (!isinlined(tmp) && owned(tmp)) {
      63                 :            : #ifdef DEBUG
      64                 :            :                 memset(cv_data(tmp), 0xbb, cv_len(tmp));
      65                 :            : #endif
      66                 :      56674 :                 free(cv_data(tmp));
      67                 :            :             }
      68                 :    2139620 :             ndel++;
      69                 :            :         }
      70         [ +  + ]:    9562320 :     } while ((n < l-ndel) && SWAP_sf(lst[n],lst[n+ndel]));
      71                 :            : 
      72                 :       4474 :     fl_ctx->nfinalizers -= ndel;
      73                 :            : #ifdef VERBOSEGC
      74                 :            :     if (ndel > 0)
      75                 :            :         printf("GC: finalized %d objects\n", ndel);
      76                 :            : #endif
      77                 :            : 
      78                 :       4474 :     fl_ctx->malloc_pressure = 0;
      79                 :            : }
      80                 :            : 
      81                 :            : // compute the size of the metadata object for a cvalue
      82                 :    9920320 : static size_t cv_nwords(fl_context_t *fl_ctx, cvalue_t *cv)
      83                 :            : {
      84         [ +  + ]:    9920320 :     if (isinlined(cv)) {
      85                 :    2586240 :         size_t n = cv_len(cv);
      86   [ +  -  +  + ]:    2586240 :         if (n==0 || cv_isstr(fl_ctx, cv))
      87                 :    2323100 :             n++;
      88                 :    2586240 :         return CVALUE_NWORDS - 1 + NWORDS(n);
      89                 :            :     }
      90                 :    7334080 :     return CVALUE_NWORDS;
      91                 :            : }
      92                 :            : 
      93                 :     105706 : static void autorelease(fl_context_t *fl_ctx, cvalue_t *cv)
      94                 :            : {
      95                 :     105706 :     cv->type = (fltype_t*)(((uintptr_t)cv->type) | CV_OWNED_BIT);
      96                 :     105706 :     add_finalizer(fl_ctx, cv);
      97                 :     105706 : }
      98                 :            : 
      99                 :      45632 : void cv_autorelease(fl_context_t *fl_ctx, cvalue_t *cv)
     100                 :            : {
     101                 :      45632 :     autorelease(fl_ctx, cv);
     102                 :      45632 : }
     103                 :            : 
     104                 :   40843800 : static value_t cprim(fl_context_t *fl_ctx, fltype_t *type, size_t sz)
     105                 :            : {
     106                 :   40843800 :     cprim_t *pcp = (cprim_t*)alloc_words(fl_ctx, CPRIM_NWORDS-1+NWORDS(sz));
     107                 :   40843800 :     pcp->type = type;
     108                 :   40843800 :     return tagptr(pcp, TAG_CPRIM);
     109                 :            : }
     110                 :            : 
     111                 :   10900100 : value_t cvalue(fl_context_t *fl_ctx, fltype_t *type, size_t sz)
     112                 :            : {
     113                 :            :     cvalue_t *pcv;
     114                 :   10900100 :     int str=0;
     115                 :            : 
     116         [ -  + ]:   10900100 :     if (valid_numtype(type->numtype)) {
     117                 :          0 :         return cprim(fl_ctx, type, sz);
     118                 :            :     }
     119         [ +  + ]:   10900100 :     if (type->eltype == fl_ctx->bytetype) {
     120         [ +  + ]:    1838896 :         if (sz == 0)
     121                 :      36162 :             return symbol_value(fl_ctx->emptystringsym);
     122                 :    1802734 :         sz++;
     123                 :    1802734 :         str=1;
     124                 :            :     }
     125         [ +  + ]:   10863940 :     if (sz <= MAX_INL_SIZE) {
     126         [ -  + ]:   10851840 :         size_t nw = CVALUE_NWORDS - 1 + NWORDS(sz) + (sz==0 ? 1 : 0);
     127                 :   10851840 :         pcv = (cvalue_t*)alloc_words(fl_ctx, nw);
     128                 :   10851840 :         pcv->type = type;
     129                 :   10851840 :         pcv->data = &pcv->_space[0];
     130   [ +  +  +  + ]:   10851840 :         if (type->vtable != NULL && type->vtable->finalize != NULL)
     131                 :    2042800 :             add_finalizer(fl_ctx, pcv);
     132                 :            :     }
     133                 :            :     else {
     134         [ -  + ]:      12104 :         if (fl_ctx->malloc_pressure > ALLOC_LIMIT_TRIGGER)
     135                 :          0 :             gc(fl_ctx, 0);
     136                 :      12104 :         pcv = (cvalue_t*)alloc_words(fl_ctx, CVALUE_NWORDS);
     137                 :      12104 :         pcv->type = type;
     138                 :      12104 :         pcv->data = malloc(sz);
     139                 :            :         // TODO: if pcv->data == NULL
     140                 :      12104 :         autorelease(fl_ctx, pcv);
     141                 :      12104 :         fl_ctx->malloc_pressure += sz;
     142                 :            :     }
     143         [ +  + ]:   10863940 :     if (str) {
     144                 :    1802734 :         sz--;
     145                 :    1802734 :         ((char*)pcv->data)[sz] = '\0';
     146                 :            :     }
     147                 :   10863940 :     pcv->len = sz;
     148                 :   10863940 :     return tagptr(pcv, TAG_CVALUE);
     149                 :            : }
     150                 :            : 
     151                 :          0 : value_t cvalue_from_data(fl_context_t *fl_ctx, fltype_t *type, void *data, size_t sz)
     152                 :            : {
     153                 :            :     value_t cv;
     154                 :          0 :     cv = cvalue(fl_ctx, type, sz);
     155         [ #  # ]:          0 :     memcpy(cptr(cv), data, sz);
     156                 :          0 :     return cv;
     157                 :            : }
     158                 :            : 
     159                 :            : // this effectively dereferences a pointer
     160                 :            : // just like *p in C, it only removes a level of indirection from the type,
     161                 :            : // it doesn't copy any data.
     162                 :            : // this method of creating a cvalue only allocates metadata.
     163                 :            : // ptr is user-managed; we don't autorelease it unless the
     164                 :            : // user explicitly calls (autorelease ) on the result of this function.
     165                 :            : // 'parent' is an optional cvalue that this pointer is known to point
     166                 :            : // into; fl_ctx->NIL if none.
     167                 :      69640 : value_t cvalue_from_ref(fl_context_t *fl_ctx, fltype_t *type, void *ptr, size_t sz, value_t parent)
     168                 :            : {
     169                 :            :     cvalue_t *pcv;
     170                 :            :     value_t cv;
     171                 :            : 
     172                 :      69640 :     pcv = (cvalue_t*)alloc_words(fl_ctx, CVALUE_NWORDS);
     173                 :      69640 :     pcv->data = ptr;
     174                 :      69640 :     pcv->len = sz;
     175                 :      69640 :     pcv->type = type;
     176         [ -  + ]:      69640 :     if (parent != fl_ctx->NIL) {
     177                 :          0 :         pcv->type = (fltype_t*)(((uintptr_t)pcv->type) | CV_PARENT_BIT);
     178                 :          0 :         pcv->parent = parent;
     179                 :            :     }
     180                 :      69640 :     cv = tagptr(pcv, TAG_CVALUE);
     181                 :      69640 :     return cv;
     182                 :            : }
     183                 :            : 
     184                 :    1838896 : value_t cvalue_string(fl_context_t *fl_ctx, size_t sz)
     185                 :            : {
     186                 :    1838896 :     return cvalue(fl_ctx, fl_ctx->stringtype, sz);
     187                 :            : }
     188                 :            : 
     189                 :      23918 : value_t cvalue_static_cstrn(fl_context_t *fl_ctx, const char *str, size_t n)
     190                 :            : {
     191                 :      23918 :     return cvalue_from_ref(fl_ctx, fl_ctx->stringtype, (char*)str, n, fl_ctx->NIL);
     192                 :            : }
     193                 :            : 
     194                 :         90 : value_t cvalue_static_cstring(fl_context_t *fl_ctx, const char *str)
     195                 :            : {
     196                 :         90 :     return cvalue_static_cstrn(fl_ctx, str, strlen(str));
     197                 :            : }
     198                 :            : 
     199                 :          0 : value_t string_from_cstrn(fl_context_t *fl_ctx, char *str, size_t n)
     200                 :            : {
     201                 :          0 :     value_t v = cvalue_string(fl_ctx, n);
     202                 :          0 :     memcpy(cvalue_data(v), str, n);
     203                 :          0 :     return v;
     204                 :            : }
     205                 :            : 
     206                 :          0 : value_t string_from_cstr(fl_context_t *fl_ctx, char *str)
     207                 :            : {
     208                 :          0 :     return string_from_cstrn(fl_ctx, str, strlen(str));
     209                 :            : }
     210                 :            : 
     211                 :   39399400 : int fl_isstring(fl_context_t *fl_ctx, value_t v)
     212                 :            : {
     213   [ +  +  +  + ]:   39399400 :     return (iscvalue(v) && cv_isstr(fl_ctx, (cvalue_t*)ptr(v)));
     214                 :            : }
     215                 :            : 
     216                 :            : // convert to malloc representation (fixed address)
     217                 :      50010 : void cv_pin(fl_context_t *fl_ctx, cvalue_t *cv)
     218                 :            : {
     219         [ +  + ]:      50010 :     if (!isinlined(cv))
     220                 :       2040 :         return;
     221                 :      47970 :     size_t sz = cv_len(cv);
     222         [ +  - ]:      47970 :     if (cv_isstr(fl_ctx, cv)) sz++;
     223                 :      47970 :     void *data = malloc(sz);
     224                 :            :     // TODO: if data == NULL
     225                 :      47970 :     memcpy(data, cv_data(cv), sz);
     226                 :      47970 :     cv->data = data;
     227                 :      47970 :     autorelease(fl_ctx, cv);
     228                 :            : }
     229                 :            : 
     230                 :            : #define num_init(ctype, cnvt, tag)                                     \
     231                 :            : static int cvalue_##ctype##_init(fl_context_t *fl_ctx, fltype_t *type, \
     232                 :            :                                  value_t arg, void *dest)              \
     233                 :            : {                                                                      \
     234                 :            :     fl_##ctype##_t n=0;                                                \
     235                 :            :     (void)type;                                                        \
     236                 :            :     if (isfixnum(arg)) {                                               \
     237                 :            :         n = numval(arg);                                               \
     238                 :            :     }                                                                  \
     239                 :            :     else if (iscprim(arg)) {                                           \
     240                 :            :         cprim_t *cp = (cprim_t*)ptr(arg);                              \
     241                 :            :         void *p = cp_data(cp);                                         \
     242                 :            :         n = (fl_##ctype##_t)conv_to_##cnvt(p, cp_numtype(cp));         \
     243                 :            :     }                                                                  \
     244                 :            :     else {                                                             \
     245                 :            :         return 1;                                                      \
     246                 :            :     }                                                                  \
     247                 :            :     memcpy(jl_assume_aligned(dest, sizeof(void*)), &n,                 \
     248                 :            :             sizeof(fl_##ctype##_t));                                   \
     249                 :            :     return 0;                                                          \
     250                 :            : }
     251   [ #  #  #  # ]:          0 : num_init(int8, int32, T_INT8)
     252   [ +  -  -  - ]:       1706 : num_init(uint8, uint32, T_UINT8)
     253   [ #  #  #  # ]:          0 : num_init(int16, int32, T_INT16)
     254   [ +  -  -  - ]:        740 : num_init(uint16, uint32, T_UINT16)
     255   [ +  -  -  - ]:         30 : num_init(int32, int32, T_INT32)
     256   [ +  -  -  - ]:       1510 : num_init(uint32, uint32, T_UINT32)
     257   [ -  +  +  - ]:         60 : num_init(int64, int64, T_INT64)
     258   [ +  +  +  - ]:       4864 : num_init(uint64, uint64, T_UINT64)
     259   [ -  +  +  - ]:       1368 : num_init(float, double, T_FLOAT)
     260   [ -  +  +  - ]:         68 : num_init(double, double, T_DOUBLE)
     261                 :            : 
     262                 :            : #define num_ctor_init(typenam, ctype, tag)                              \
     263                 :            : value_t cvalue_##typenam(fl_context_t *fl_ctx, value_t *args, uint32_t nargs) \
     264                 :            : {                                                                       \
     265                 :            :     if (nargs==0) { PUSH(fl_ctx, fixnum(0)); args = &fl_ctx->Stack[fl_ctx->SP-1]; } \
     266                 :            :     value_t cp = cprim(fl_ctx, fl_ctx->typenam##type, sizeof(fl_##ctype##_t)); \
     267                 :            :     if (cvalue_##ctype##_init(fl_ctx, fl_ctx->typenam##type,            \
     268                 :            :                               args[0], cp_data((cprim_t*)ptr(cp))))     \
     269                 :            :         type_error(fl_ctx, #typenam, "number", args[0]);                \
     270                 :            :     return cp;                                                          \
     271                 :            : }
     272                 :            : 
     273                 :            : #define num_ctor_ctor(typenam, ctype, tag)                              \
     274                 :            : value_t mk_##typenam(fl_context_t *fl_ctx, fl_##ctype##_t n)            \
     275                 :            : {                                                                       \
     276                 :            :     value_t cp = cprim(fl_ctx, fl_ctx->typenam##type, sizeof(fl_##ctype##_t)); \
     277                 :            :     *(fl_##ctype##_t*)cp_data((cprim_t*)ptr(cp)) = n;                   \
     278                 :            :     return cp;                                                          \
     279                 :            : }
     280                 :            : 
     281                 :            : #define num_ctor(typenam, ctype, tag)  \
     282                 :            :     num_ctor_init(typenam, ctype, tag) \
     283                 :            :     num_ctor_ctor(typenam, ctype, tag)
     284                 :            : 
     285   [ #  #  #  # ]:          0 : num_ctor(int8, int8, T_INT8)
     286   [ -  +  -  + ]:       1706 : num_ctor(uint8, uint8, T_UINT8)
     287   [ #  #  #  # ]:          0 : num_ctor(int16, int16, T_INT16)
     288   [ -  +  -  + ]:        740 : num_ctor(uint16, uint16, T_UINT16)
     289   [ -  +  -  + ]:         30 : num_ctor(int32, int32, T_INT32)
     290   [ -  +  -  + ]:       2846 : num_ctor(uint32, uint32, T_UINT32)
     291   [ -  +  -  + ]:        818 : num_ctor(int64, int64, T_INT64)
     292   [ -  +  -  + ]:       6510 : num_ctor(uint64, uint64, T_UINT64)
     293   [ #  #  #  # ]:          0 : num_ctor(byte,  uint8, T_UINT8)
     294   [ #  #  #  # ]:   40820200 : num_ctor(wchar, int32, T_INT32)
     295                 :            : #ifdef _P64
     296   [ #  #  #  # ]:          0 : num_ctor(ptrdiff, int64, T_INT64)
     297   [ #  #  #  # ]:          0 : num_ctor(size, uint64, T_UINT64)
     298                 :            : #else
     299                 :            : num_ctor(ptrdiff, int32, T_INT32)
     300                 :            : num_ctor(size, uint32, T_UINT32)
     301                 :            : #endif
     302   [ -  +  -  + ]:       1368 : num_ctor(float, float, T_FLOAT)
     303   [ -  +  -  + ]:       9660 : num_ctor(double, double, T_DOUBLE)
     304                 :            : 
     305                 :    4071160 : value_t size_wrap(fl_context_t *fl_ctx, size_t sz)
     306                 :            : {
     307   [ -  +  -  - ]:    4071160 :     if (fits_fixnum(sz))
     308                 :    4071160 :         return fixnum(sz);
     309                 :            :     assert(sizeof(void*) == sizeof(size_t));
     310                 :          0 :     return mk_size(fl_ctx, sz);
     311                 :            : }
     312                 :            : 
     313                 :    1014466 : size_t tosize(fl_context_t *fl_ctx, value_t n, const char *fname)
     314                 :            : {
     315         [ +  - ]:    1014466 :     if (isfixnum(n))
     316                 :    1014466 :         return numval(n);
     317         [ #  # ]:          0 :     if (iscprim(n)) {
     318                 :          0 :         cprim_t *cp = (cprim_t*)ptr(n);
     319                 :          0 :         return conv_to_size(cp_data(cp), cp_numtype(cp));
     320                 :            :     }
     321                 :          0 :     type_error(fl_ctx, fname, "number", n);
     322                 :            :     return 0;
     323                 :            : }
     324                 :            : 
     325                 :          0 : static int isarray(value_t v)
     326                 :            : {
     327   [ #  #  #  # ]:          0 :     return iscvalue(v) && cv_class((cvalue_t*)ptr(v))->eltype != NULL;
     328                 :            : }
     329                 :            : 
     330                 :          0 : static size_t predict_arraylen(fl_context_t *fl_ctx, value_t arg)
     331                 :            : {
     332         [ #  # ]:          0 :     if (isvector(arg))
     333                 :          0 :         return vector_size(arg);
     334         [ #  # ]:          0 :     else if (iscons(arg))
     335                 :          0 :         return llength(arg);
     336         [ #  # ]:          0 :     else if (arg == fl_ctx->NIL)
     337                 :          0 :         return 0;
     338         [ #  # ]:          0 :     if (isarray(arg))
     339                 :          0 :         return cvalue_arraylen(arg);
     340                 :          0 :     return 1;
     341                 :            : }
     342                 :            : 
     343                 :          0 : static int cvalue_array_init(fl_context_t *fl_ctx, fltype_t *ft, value_t arg, void *dest)
     344                 :            : {
     345                 :          0 :     value_t type = ft->type;
     346                 :            :     size_t elsize, i, cnt, sz;
     347                 :          0 :     fltype_t *eltype = ft->eltype;
     348                 :            : 
     349                 :          0 :     elsize = ft->elsz;
     350                 :          0 :     cnt = predict_arraylen(fl_ctx, arg);
     351                 :            : 
     352         [ #  # ]:          0 :     if (iscons(cdr_(cdr_(type)))) {
     353                 :          0 :         size_t tc = tosize(fl_ctx, car_(cdr_(cdr_(type))), "array");
     354         [ #  # ]:          0 :         if (tc != cnt)
     355                 :          0 :             lerror(fl_ctx, fl_ctx->ArgError, "array: size mismatch");
     356                 :            :     }
     357                 :            : 
     358                 :          0 :     sz = elsize * cnt;
     359                 :            : 
     360         [ #  # ]:          0 :     if (isvector(arg)) {
     361         [ #  # ]:          0 :         for(i=0; i < cnt; i++) {
     362                 :          0 :             cvalue_init(fl_ctx, eltype, vector_elt(arg,i), dest);
     363                 :          0 :             dest = (char *)dest + elsize;
     364                 :            :         }
     365                 :          0 :         return 0;
     366                 :            :     }
     367   [ #  #  #  # ]:          0 :     else if (iscons(arg) || arg==fl_ctx->NIL) {
     368                 :          0 :         i = 0;
     369         [ #  # ]:          0 :         while (iscons(arg)) {
     370         [ #  # ]:          0 :             if (i == cnt) { i++; break; } // trigger error
     371                 :          0 :             cvalue_init(fl_ctx, eltype, car_(arg), dest);
     372                 :          0 :             i++;
     373                 :          0 :             dest = (char *)dest + elsize;
     374                 :          0 :             arg = cdr_(arg);
     375                 :            :         }
     376         [ #  # ]:          0 :         if (i != cnt)
     377                 :          0 :             lerror(fl_ctx, fl_ctx->ArgError, "array: size mismatch");
     378                 :          0 :         return 0;
     379                 :            :     }
     380         [ #  # ]:          0 :     else if (iscvalue(arg)) {
     381                 :          0 :         cvalue_t *cv = (cvalue_t*)ptr(arg);
     382         [ #  # ]:          0 :         if (isarray(arg)) {
     383                 :          0 :             fltype_t *aet = cv_class(cv)->eltype;
     384         [ #  # ]:          0 :             if (aet == eltype) {
     385         [ #  # ]:          0 :                 if (cv_len(cv) == sz)
     386                 :          0 :                     memcpy(dest, cv_data(cv), sz);
     387                 :            :                 else
     388                 :          0 :                     lerror(fl_ctx, fl_ctx->ArgError, "array: size mismatch");
     389                 :          0 :                 return 0;
     390                 :            :             }
     391                 :            :             else {
     392                 :            :                 // TODO: initialize array from different type elements
     393                 :          0 :                 lerror(fl_ctx, fl_ctx->ArgError, "array: element type mismatch");
     394                 :            :             }
     395                 :            :         }
     396                 :            :     }
     397         [ #  # ]:          0 :     if (cnt == 1)
     398                 :          0 :         cvalue_init(fl_ctx, eltype, arg, dest);
     399                 :            :     else
     400                 :          0 :         type_error(fl_ctx, "array", "sequence", arg);
     401                 :          0 :     return 0;
     402                 :            : }
     403                 :            : 
     404                 :          0 : value_t cvalue_array(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
     405                 :            : {
     406                 :            :     size_t elsize, cnt, sz, i;
     407                 :            :     value_t arg;
     408                 :            : 
     409         [ #  # ]:          0 :     if (nargs < 1)
     410                 :          0 :         argcount(fl_ctx, "array", nargs, 1);
     411                 :            : 
     412                 :          0 :     cnt = nargs - 1;
     413                 :          0 :     fltype_t *type = get_array_type(fl_ctx, args[0]);
     414                 :          0 :     elsize = type->elsz;
     415                 :          0 :     sz = elsize * cnt;
     416                 :            : 
     417                 :          0 :     value_t cv = cvalue(fl_ctx, type, sz);
     418                 :          0 :     char *dest = (char*)cv_data((cvalue_t*)ptr(cv));
     419         [ #  # ]:          0 :     FOR_ARGS(i,1,arg,args) {
     420                 :          0 :         cvalue_init(fl_ctx, type->eltype, arg, dest);
     421                 :          0 :         dest += elsize;
     422                 :            :     }
     423                 :          0 :     return cv;
     424                 :            : }
     425                 :            : 
     426                 :            : // NOTE: v must be an array
     427                 :     158040 : size_t cvalue_arraylen(value_t v)
     428                 :            : {
     429                 :     158040 :     cvalue_t *cv = (cvalue_t*)ptr(v);
     430                 :     158040 :     return cv_len(cv)/(cv_class(cv)->elsz);
     431                 :            : }
     432                 :            : 
     433                 :            : // *palign is an output argument giving the alignment required by type
     434                 :     666684 : size_t ctype_sizeof(fl_context_t *fl_ctx, value_t type, int *palign)
     435                 :            : {
     436   [ +  +  +  +  :     666684 :     if (type == fl_ctx->int8sym || type == fl_ctx->uint8sym || type == fl_ctx->bytesym) {
                   +  + ]
     437                 :     666354 :         *palign = 1;
     438                 :     666354 :         return 1;
     439                 :            :     }
     440   [ +  +  +  + ]:        330 :     if (type == fl_ctx->int16sym || type == fl_ctx->uint16sym) {
     441                 :         60 :         *palign = ALIGN2;
     442                 :         60 :         return 2;
     443                 :            :     }
     444   [ +  +  +  +  :        270 :     if (type == fl_ctx->int32sym || type == fl_ctx->uint32sym || type == fl_ctx->wcharsym ||
                   +  + ]
     445         [ +  + ]:        180 :         type == fl_ctx->floatsym) {
     446                 :        120 :         *palign = ALIGN4;
     447                 :        120 :         return 4;
     448                 :            :     }
     449   [ +  +  +  +  :        150 :     if (type == fl_ctx->int64sym || type == fl_ctx->uint64sym || type == fl_ctx->doublesym) {
                   +  + ]
     450                 :         90 :         *palign = ALIGN8;
     451                 :         90 :         return 8;
     452                 :            :     }
     453   [ +  +  +  - ]:         60 :     if (type == fl_ctx->ptrdiffsym || type == fl_ctx->sizesym) {
     454                 :            : #ifdef _P64
     455                 :         60 :         *palign = ALIGN8;
     456                 :         60 :         return 8;
     457                 :            : #else
     458                 :            :         *palign = ALIGN4;
     459                 :            :         return 4;
     460                 :            : #endif
     461                 :            :     }
     462         [ #  # ]:          0 :     if (iscons(type)) {
     463                 :          0 :         value_t hed = car_(type);
     464   [ #  #  #  # ]:          0 :         if (hed == fl_ctx->pointersym || hed == fl_ctx->cfunctionsym) {
     465                 :          0 :             *palign = ALIGNPTR;
     466                 :          0 :             return sizeof(void*);
     467                 :            :         }
     468         [ #  # ]:          0 :         if (hed == fl_ctx->arraysym) {
     469                 :          0 :             value_t t = car(fl_ctx, cdr_(type));
     470         [ #  # ]:          0 :             if (!iscons(cdr_(cdr_(type))))
     471                 :          0 :                 lerror(fl_ctx, fl_ctx->ArgError, "sizeof: incomplete type");
     472                 :          0 :             value_t n = car_(cdr_(cdr_(type)));
     473                 :          0 :             size_t sz = tosize(fl_ctx, n, "sizeof");
     474                 :          0 :             return sz * ctype_sizeof(fl_ctx, t, palign);
     475                 :            :         }
     476                 :            :     }
     477                 :          0 :     lerror(fl_ctx, fl_ctx->ArgError, "sizeof: invalid c type");
     478                 :            :     return 0;
     479                 :            : }
     480                 :            : 
     481                 :            : // get pointer and size for any plain-old-data value
     482                 :     257948 : void to_sized_ptr(fl_context_t *fl_ctx, value_t v, const char *fname, char **pdata, size_t *psz)
     483                 :            : {
     484         [ +  - ]:     257948 :     if (iscvalue(v)) {
     485                 :     257948 :         cvalue_t *pcv = (cvalue_t*)ptr(v);
     486                 :     257948 :         ios_t *x = value2c(ios_t*,v);
     487   [ -  +  -  - ]:     257948 :         if (cv_class(pcv) == fl_ctx->iostreamtype && (x->bm == bm_mem)) {
     488                 :          0 :             *pdata = x->buf;
     489                 :          0 :             *psz = (size_t)x->size;
     490                 :          0 :             return;
     491                 :            :         }
     492         [ +  - ]:     257948 :         else if (cv_isPOD(pcv)) {
     493                 :     257948 :             *pdata = (char*)cv_data(pcv);
     494                 :     257948 :             *psz = cv_len(pcv);
     495                 :     257948 :             return;
     496                 :            :         }
     497                 :            :     }
     498         [ #  # ]:          0 :     else if (iscprim(v)) {
     499                 :          0 :         cprim_t *pcp = (cprim_t*)ptr(v);
     500                 :          0 :         *pdata = cp_data(pcp);
     501                 :          0 :         *psz = cp_class(pcp)->size;
     502                 :          0 :         return;
     503                 :            :     }
     504                 :          0 :     type_error(fl_ctx, fname, "plain-old-data", v);
     505                 :            : }
     506                 :            : 
     507                 :      17994 : value_t cvalue_sizeof(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
     508                 :            : {
     509                 :      17994 :     argcount(fl_ctx, "sizeof", nargs, 1);
     510   [ +  -  -  + ]:      17994 :     if (issymbol(args[0]) || iscons(args[0])) {
     511                 :            :         int a;
     512                 :          0 :         return size_wrap(fl_ctx, ctype_sizeof(fl_ctx, args[0], &a));
     513                 :            :     }
     514                 :            :     size_t n; char *data;
     515                 :      17994 :     to_sized_ptr(fl_ctx, args[0], "sizeof", &data, &n);
     516                 :      17994 :     return size_wrap(fl_ctx, n);
     517                 :            : }
     518                 :            : 
     519                 :   23089800 : value_t cvalue_typeof(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
     520                 :            : {
     521                 :   23089800 :     argcount(fl_ctx, "typeof", nargs, 1);
     522   [ +  -  +  -  :   23089800 :     switch(tag(args[0])) {
                   +  + ]
     523                 :   19638520 :     case TAG_CONS: return fl_ctx->pairsym;
     524                 :          0 :     case TAG_NUM1:
     525                 :          0 :     case TAG_NUM:  return fl_ctx->fixnumsym;
     526                 :    2501820 :     case TAG_SYM:  return fl_ctx->symbolsym;
     527                 :          0 :     case TAG_VECTOR: return fl_ctx->vectorsym;
     528                 :         64 :     case TAG_FUNCTION:
     529   [ +  -  +  + ]:         64 :         if (args[0] == fl_ctx->T || args[0] == fl_ctx->F)
     530                 :         48 :             return fl_ctx->booleansym;
     531         [ -  + ]:         16 :         if (args[0] == fl_ctx->NIL)
     532                 :          0 :             return fl_ctx->nullsym;
     533         [ +  - ]:         16 :         if (args[0] == fl_ctx->FL_EOF)
     534                 :         16 :             return symbol(fl_ctx, "eof-object");
     535   [ #  #  #  # ]:          0 :         if (isbuiltin(args[0]))
     536                 :          0 :             return fl_ctx->builtinsym;
     537                 :          0 :         return fl_ctx->FUNCTION;
     538                 :            :     }
     539                 :     949442 :     return cv_type((cvalue_t*)ptr(args[0]));
     540                 :            : }
     541                 :            : 
     542                 :    9920320 : static value_t cvalue_relocate(fl_context_t *fl_ctx, value_t v)
     543                 :            : {
     544                 :            :     size_t nw;
     545                 :    9920320 :     cvalue_t *cv = (cvalue_t*)ptr(v);
     546                 :            :     cvalue_t *nv;
     547                 :            :     value_t ncv;
     548                 :            : 
     549                 :    9920320 :     nw = cv_nwords(fl_ctx, cv);
     550                 :    9920320 :     nv = (cvalue_t*)alloc_words(fl_ctx, nw);
     551                 :    9920320 :     memcpy(nv, cv, nw*sizeof(value_t));
     552         [ +  + ]:    9920320 :     if (isinlined(cv))
     553                 :    2586240 :         nv->data = &nv->_space[0];
     554                 :    9920320 :     ncv = tagptr(nv, TAG_CVALUE);
     555                 :    9920320 :     fltype_t *t = cv_class(cv);
     556   [ +  +  +  - ]:    9920320 :     if (t->vtable != NULL && t->vtable->relocate != NULL)
     557                 :     174032 :         t->vtable->relocate(fl_ctx, v, ncv);
     558                 :    9920320 :     forward(v, ncv);
     559                 :    9920320 :     return ncv;
     560                 :            : }
     561                 :            : 
     562                 :          0 : value_t cvalue_copy(fl_context_t *fl_ctx, value_t v)
     563                 :            : {
     564         [ #  # ]:          0 :     assert(iscvalue(v));
     565                 :          0 :     PUSH(fl_ctx, v);
     566                 :          0 :     cvalue_t *cv = (cvalue_t*)ptr(v);
     567                 :          0 :     size_t nw = cv_nwords(fl_ctx, cv);
     568                 :          0 :     cvalue_t *ncv = (cvalue_t*)alloc_words(fl_ctx, nw);
     569                 :          0 :     v = POP(fl_ctx); cv = (cvalue_t*)ptr(v);
     570                 :          0 :     memcpy(ncv, cv, nw * sizeof(value_t));
     571         [ #  # ]:          0 :     if (!isinlined(cv)) {
     572                 :          0 :         size_t len = cv_len(cv);
     573         [ #  # ]:          0 :         if (cv_isstr(fl_ctx, cv)) len++;
     574                 :          0 :         ncv->data = malloc(len);
     575                 :            :         // TODO: if ncv->data == NULL
     576                 :          0 :         memcpy(ncv->data, cv_data(cv), len);
     577                 :          0 :         autorelease(fl_ctx, ncv);
     578         [ #  # ]:          0 :         if (hasparent(cv)) {
     579                 :          0 :             ncv->type = (fltype_t*)(((uintptr_t)ncv->type) & ~CV_PARENT_BIT);
     580                 :          0 :             ncv->parent = fl_ctx->NIL;
     581                 :            :         }
     582                 :            :     }
     583                 :            :     else {
     584                 :          0 :         ncv->data = &ncv->_space[0];
     585                 :            :     }
     586                 :            : 
     587                 :          0 :     return tagptr(ncv, TAG_CVALUE);
     588                 :            : }
     589                 :            : 
     590                 :          0 : value_t fl_copy(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
     591                 :            : {
     592                 :          0 :     argcount(fl_ctx, "copy", nargs, 1);
     593   [ #  #  #  # ]:          0 :     if (iscons(args[0]) || isvector(args[0]))
     594                 :          0 :         lerror(fl_ctx, fl_ctx->ArgError, "copy: argument must be a leaf atom");
     595         [ #  # ]:          0 :     if (!iscvalue(args[0]))
     596                 :          0 :         return args[0];
     597         [ #  # ]:          0 :     if (!cv_isPOD((cvalue_t*)ptr(args[0])))
     598                 :          0 :         lerror(fl_ctx, fl_ctx->ArgError, "copy: argument must be a plain-old-data type");
     599                 :          0 :     return cvalue_copy(fl_ctx, args[0]);
     600                 :            : }
     601                 :            : 
     602                 :          0 : value_t fl_podp(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
     603                 :            : {
     604                 :          0 :     argcount(fl_ctx, "plain-old-data?", nargs, 1);
     605                 :          0 :     return (iscprim(args[0]) ||
     606   [ #  #  #  # ]:          0 :             (iscvalue(args[0]) && cv_isPOD((cvalue_t*)ptr(args[0])))) ?
     607         [ #  # ]:          0 :         fl_ctx->T : fl_ctx->F;
     608                 :            : }
     609                 :            : 
     610                 :          0 : static void cvalue_init(fl_context_t *fl_ctx, fltype_t *type, value_t v, void *dest)
     611                 :            : {
     612                 :          0 :     cvinitfunc_t f=type->init;
     613                 :            : 
     614         [ #  # ]:          0 :     if (f == NULL)
     615                 :          0 :         lerror(fl_ctx, fl_ctx->ArgError, "c-value: invalid c type");
     616                 :            : 
     617                 :          0 :     f(fl_ctx, type, v, dest);
     618                 :          0 : }
     619                 :            : 
     620                 :        444 : static numerictype_t sym_to_numtype(fl_context_t *fl_ctx, value_t type)
     621                 :            : {
     622         [ +  + ]:        444 :     if (type == fl_ctx->int8sym)
     623                 :         30 :         return T_INT8;
     624   [ +  +  +  + ]:        414 :     else if (type == fl_ctx->uint8sym || type == fl_ctx->bytesym)
     625                 :         60 :         return T_UINT8;
     626         [ +  + ]:        354 :     else if (type == fl_ctx->int16sym)
     627                 :         30 :         return T_INT16;
     628         [ +  + ]:        324 :     else if (type == fl_ctx->uint16sym)
     629                 :         30 :         return T_UINT16;
     630                 :            : #ifdef _P64
     631   [ +  +  +  + ]:        294 :     else if (type == fl_ctx->int32sym || type == fl_ctx->wcharsym)
     632                 :            : #else
     633                 :            :     else if (type == fl_ctx->int32sym || type == fl_ctx->wcharsym || type == fl_ctx->ptrdiffsym)
     634                 :            : #endif
     635                 :         60 :         return T_INT32;
     636                 :            : #ifdef _P64
     637         [ +  + ]:        234 :     else if (type == fl_ctx->uint32sym)
     638                 :            : #else
     639                 :            :     else if (type == fl_ctx->uint32sym || type == fl_ctx->sizesym)
     640                 :            : #endif
     641                 :         30 :         return T_UINT32;
     642                 :            : #ifdef _P64
     643   [ +  +  +  + ]:        204 :     else if (type == fl_ctx->int64sym || type == fl_ctx->ptrdiffsym)
     644                 :            : #else
     645                 :            :     else if (type == fl_ctx->int64sym)
     646                 :            : #endif
     647                 :         60 :         return T_INT64;
     648                 :            : #ifdef _P64
     649   [ +  +  +  + ]:        144 :     else if (type == fl_ctx->uint64sym || type == fl_ctx->sizesym)
     650                 :            : #else
     651                 :            :     else if (type == fl_ctx->uint64sym)
     652                 :            : #endif
     653                 :         60 :         return T_UINT64;
     654         [ +  + ]:         84 :     else if (type == fl_ctx->floatsym)
     655                 :         30 :         return T_FLOAT;
     656         [ +  + ]:         54 :     else if (type == fl_ctx->doublesym)
     657                 :         30 :         return T_DOUBLE;
     658                 :         24 :     return (numerictype_t)N_NUMTYPES;
     659                 :            : }
     660                 :            : 
     661                 :            : // (new type . args)
     662                 :            : // this provides (1) a way to allocate values with a shared type for
     663                 :            : // efficiency, (2) a uniform interface for allocating cvalues of any
     664                 :            : // type, including user-defined.
     665                 :          0 : value_t cvalue_new(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
     666                 :            : {
     667   [ #  #  #  # ]:          0 :     if (nargs < 1 || nargs > 2)
     668                 :          0 :         argcount(fl_ctx, "c-value", nargs, 2);
     669                 :          0 :     value_t type = args[0];
     670                 :          0 :     fltype_t *ft = get_type(fl_ctx, type);
     671                 :            :     value_t cv;
     672         [ #  # ]:          0 :     if (ft->eltype != NULL) {
     673                 :            :         // special case to handle incomplete array types bla[]
     674                 :          0 :         size_t elsz = ft->elsz;
     675                 :            :         size_t cnt;
     676                 :            : 
     677         [ #  # ]:          0 :         if (iscons(cdr_(cdr_(type))))
     678                 :          0 :             cnt = tosize(fl_ctx, car_(cdr_(cdr_(type))), "array");
     679         [ #  # ]:          0 :         else if (nargs == 2)
     680                 :          0 :             cnt = predict_arraylen(fl_ctx, args[1]);
     681                 :            :         else
     682                 :          0 :             cnt = 0;
     683                 :          0 :         cv = cvalue(fl_ctx, ft, elsz * cnt);
     684         [ #  # ]:          0 :         if (nargs == 2)
     685                 :          0 :             cvalue_array_init(fl_ctx, ft, args[1], cv_data((cvalue_t*)ptr(cv)));
     686                 :            :     }
     687                 :            :     else {
     688                 :          0 :         cv = cvalue(fl_ctx, ft, ft->size);
     689         [ #  # ]:          0 :         if (nargs == 2)
     690         [ #  # ]:          0 :             cvalue_init(fl_ctx, ft, args[1], cptr(cv));
     691                 :            :     }
     692                 :          0 :     return cv;
     693                 :            : }
     694                 :            : 
     695                 :            : // NOTE: this only compares lexicographically; it ignores numeric formats
     696                 :     235660 : value_t cvalue_compare(value_t a, value_t b)
     697                 :            : {
     698                 :     235660 :     cvalue_t *ca = (cvalue_t*)ptr(a);
     699                 :     235660 :     cvalue_t *cb = (cvalue_t*)ptr(b);
     700                 :     235660 :     char *adata = (char*)cv_data(ca);
     701                 :     235660 :     char *bdata = (char*)cv_data(cb);
     702                 :     235660 :     size_t asz = cv_len(ca);
     703                 :     235660 :     size_t bsz = cv_len(cb);
     704                 :     235660 :     size_t minsz = asz < bsz ? asz : bsz;
     705                 :     235660 :     int diff = memcmp(adata, bdata, minsz);
     706         [ +  + ]:     235660 :     if (diff == 0) {
     707         [ +  + ]:     235640 :         if (asz > bsz)
     708                 :     235632 :             return fixnum(1);
     709         [ -  + ]:          8 :         else if (asz < bsz)
     710                 :          0 :             return fixnum(-1);
     711                 :            :     }
     712                 :         28 :     return fixnum(diff);
     713                 :            : }
     714                 :            : 
     715                 :          0 : static void check_addr_args(fl_context_t *fl_ctx, const char *fname, value_t arr,
     716                 :            :                             value_t ind, char **data, size_t *index)
     717                 :            : {
     718                 :            :     size_t numel;
     719                 :          0 :     cvalue_t *cv = (cvalue_t*)ptr(arr);
     720                 :          0 :     *data = (char*)cv_data(cv);
     721                 :          0 :     numel = cv_len(cv)/(cv_class(cv)->elsz);
     722                 :          0 :     *index = tosize(fl_ctx, ind, fname);
     723         [ #  # ]:          0 :     if (*index >= numel)
     724                 :          0 :         bounds_error(fl_ctx, fname, arr, ind);
     725                 :          0 : }
     726                 :            : 
     727                 :          0 : static value_t cvalue_array_aref(fl_context_t *fl_ctx, value_t *args)
     728                 :            : {
     729                 :            :     char *data; size_t index;
     730                 :          0 :     fltype_t *eltype = cv_class((cvalue_t*)ptr(args[0]))->eltype;
     731                 :          0 :     value_t el = 0;
     732                 :          0 :     numerictype_t nt = eltype->numtype;
     733         [ #  # ]:          0 :     if (nt >= T_INT32)
     734                 :          0 :         el = cvalue(fl_ctx, eltype, eltype->size);
     735                 :          0 :     check_addr_args(fl_ctx, "aref", args[0], args[1], &data, &index);
     736         [ #  # ]:          0 :     if (nt < T_INT32) {
     737         [ #  # ]:          0 :         if (nt == T_INT8)
     738                 :          0 :             return fixnum((int8_t)data[index]);
     739         [ #  # ]:          0 :         else if (nt == T_UINT8)
     740                 :          0 :             return fixnum((uint8_t)data[index]);
     741         [ #  # ]:          0 :         else if (nt == T_INT16)
     742                 :          0 :             return fixnum(((int16_t*)data)[index]);
     743                 :          0 :         return fixnum(((uint16_t*)data)[index]);
     744                 :            :     }
     745         [ #  # ]:          0 :     char *dest = (char*)cptr(el);
     746                 :          0 :     size_t sz = eltype->size;
     747         [ #  # ]:          0 :     if (sz == 1)
     748                 :          0 :         *dest = data[index];
     749         [ #  # ]:          0 :     else if (sz == 2)
     750                 :          0 :         *(int16_t*)dest = ((int16_t*)data)[index];
     751         [ #  # ]:          0 :     else if (sz == 4)
     752                 :          0 :         *(int32_t*)dest = ((int32_t*)data)[index];
     753         [ #  # ]:          0 :     else if (sz == 8)
     754                 :          0 :         *(int64_t*)dest = ((int64_t*)data)[index];
     755                 :            :     else
     756                 :          0 :         memcpy(dest, data + index*sz, sz);
     757                 :          0 :     return el;
     758                 :            : }
     759                 :            : 
     760                 :          0 : static value_t cvalue_array_aset(fl_context_t *fl_ctx, value_t *args)
     761                 :            : {
     762                 :            :     char *data; size_t index;
     763                 :          0 :     fltype_t *eltype = cv_class((cvalue_t*)ptr(args[0]))->eltype;
     764                 :          0 :     check_addr_args(fl_ctx, "aset!", args[0], args[1], &data, &index);
     765                 :          0 :     char *dest = data + index*eltype->size;
     766                 :          0 :     cvalue_init(fl_ctx, eltype, args[2], dest);
     767                 :          0 :     return args[2];
     768                 :            : }
     769                 :            : 
     770                 :      37500 : value_t fl_builtin(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
     771                 :            : {
     772                 :      37500 :     argcount(fl_ctx, "builtin", nargs, 1);
     773                 :      37500 :     symbol_t *name = tosymbol(fl_ctx, args[0], "builtin");
     774                 :            :     cvalue_t *cv;
     775   [ -  +  -  -  :      37500 :     if (ismanaged(fl_ctx, args[0]) || (cv=(cvalue_t*)name->dlcache) == NULL) {
                   -  + ]
     776                 :          0 :         lerrorf(fl_ctx, fl_ctx->ArgError, "builtin: function %s not found", name->name);
     777                 :            :     }
     778                 :      37500 :     return tagptr(cv, TAG_CVALUE);
     779                 :            : }
     780                 :            : 
     781                 :       3660 : value_t cbuiltin(fl_context_t *fl_ctx, const char *name, builtin_t f)
     782                 :            : {
     783                 :       3660 :     cvalue_t *cv = (cvalue_t*)malloc(CVALUE_NWORDS * sizeof(value_t));
     784                 :            :     // TODO: if cv->data == NULL
     785                 :       3660 :     cv->type = fl_ctx->builtintype;
     786                 :       3660 :     cv->data = &cv->_space[0];
     787                 :       3660 :     cv->len = sizeof(value_t);
     788                 :       3660 :     *(void**)cv->data = (void*)(uintptr_t)f;
     789                 :            : 
     790                 :       3660 :     value_t sym = symbol(fl_ctx, name);
     791                 :       3660 :     ((symbol_t*)ptr(sym))->dlcache = cv;
     792                 :       3660 :     ptrhash_put(&fl_ctx->reverse_dlsym_lookup_table, cv, (void*)sym);
     793                 :            : 
     794                 :       3660 :     return tagptr(cv, TAG_CVALUE);
     795                 :            : }
     796                 :            : 
     797                 :            : static value_t fl_logand(fl_context_t *fl_ctx, value_t *args, uint32_t nargs);
     798                 :            : static value_t fl_logior(fl_context_t *fl_ctx, value_t *args, uint32_t nargs);
     799                 :            : static value_t fl_logxor(fl_context_t *fl_ctx, value_t *args, uint32_t nargs);
     800                 :            : static value_t fl_lognot(fl_context_t *fl_ctx, value_t *args, uint32_t nargs);
     801                 :            : static value_t fl_ash(fl_context_t *fl_ctx, value_t *args, uint32_t nargs);
     802                 :            : 
     803                 :            : static const builtinspec_t cvalues_builtin_info[] = {
     804                 :            :     { "c-value", cvalue_new },
     805                 :            :     { "typeof", cvalue_typeof },
     806                 :            :     { "sizeof", cvalue_sizeof },
     807                 :            :     { "builtin", fl_builtin },
     808                 :            :     { "copy", fl_copy },
     809                 :            :     { "plain-old-data?", fl_podp },
     810                 :            : 
     811                 :            :     { "logand", fl_logand },
     812                 :            :     { "logior", fl_logior },
     813                 :            :     { "logxor", fl_logxor },
     814                 :            :     { "lognot", fl_lognot },
     815                 :            :     { "ash", fl_ash },
     816                 :            :     // todo: autorelease
     817                 :            :     { NULL, NULL }
     818                 :            : };
     819                 :            : 
     820                 :            : #define cv_intern(fl_ctx, tok) fl_ctx->tok##sym = symbol(fl_ctx, #tok)
     821                 :            : #define ctor_cv_intern(fl_ctx, tok)                             \
     822                 :            :     cv_intern(fl_ctx, tok);                                     \
     823                 :            :     set(fl_ctx->tok##sym, cbuiltin(fl_ctx, #tok, cvalue_##tok))
     824                 :            : 
     825                 :            : #define mk_primtype(fl_ctx, name)                               \
     826                 :            :     fl_ctx->name##type = get_type(fl_ctx, fl_ctx->name##sym);   \
     827                 :            :     fl_ctx->name##type->init = &cvalue_##name##_init
     828                 :            : 
     829                 :            : #define mk_primtype_(fl_ctx, name, ctype)                       \
     830                 :            :     fl_ctx->name##type = get_type(fl_ctx, fl_ctx->name##sym);   \
     831                 :            :     fl_ctx->name##type->init = &cvalue_##ctype##_init
     832                 :            : 
     833                 :         30 : static void cvalues_init(fl_context_t *fl_ctx)
     834                 :            : {
     835                 :         30 :     fl_ctx->malloc_pressure = 0;
     836                 :         30 :     fl_ctx->Finalizers = NULL;
     837                 :         30 :     fl_ctx->nfinalizers = 0;
     838                 :         30 :     fl_ctx->maxfinalizers = 0;
     839                 :            : 
     840                 :         30 :     htable_new(&fl_ctx->TypeTable, 256);
     841                 :         30 :     htable_new(&fl_ctx->reverse_dlsym_lookup_table, 256);
     842                 :            : 
     843                 :         30 :     fl_ctx->builtintype = define_opaque_type(fl_ctx->builtinsym, sizeof(builtin_t), NULL, NULL);
     844                 :            : 
     845                 :         30 :     ctor_cv_intern(fl_ctx, int8);
     846                 :         30 :     ctor_cv_intern(fl_ctx, uint8);
     847                 :         30 :     ctor_cv_intern(fl_ctx, int16);
     848                 :         30 :     ctor_cv_intern(fl_ctx, uint16);
     849                 :         30 :     ctor_cv_intern(fl_ctx, int32);
     850                 :         30 :     ctor_cv_intern(fl_ctx, uint32);
     851                 :         30 :     ctor_cv_intern(fl_ctx, int64);
     852                 :         30 :     ctor_cv_intern(fl_ctx, uint64);
     853                 :         30 :     ctor_cv_intern(fl_ctx, byte);
     854                 :         30 :     ctor_cv_intern(fl_ctx, wchar);
     855                 :         30 :     ctor_cv_intern(fl_ctx, ptrdiff);
     856                 :         30 :     ctor_cv_intern(fl_ctx, size);
     857                 :         30 :     ctor_cv_intern(fl_ctx, float);
     858                 :         30 :     ctor_cv_intern(fl_ctx, double);
     859                 :            : 
     860                 :         30 :     ctor_cv_intern(fl_ctx, array);
     861                 :         30 :     cv_intern(fl_ctx, pointer);
     862                 :         30 :     cv_intern(fl_ctx, void);
     863                 :         30 :     fl_ctx->cfunctionsym = symbol(fl_ctx, "c-function");
     864                 :            : 
     865                 :         30 :     assign_global_builtins(fl_ctx, cvalues_builtin_info);
     866                 :            : 
     867                 :         30 :     fl_ctx->stringtypesym = symbol(fl_ctx, "*string-type*");
     868                 :         30 :     setc(fl_ctx->stringtypesym, fl_list2(fl_ctx, fl_ctx->arraysym, fl_ctx->bytesym));
     869                 :            : 
     870                 :         30 :     fl_ctx->wcstringtypesym = symbol(fl_ctx, "*wcstring-type*");
     871                 :         30 :     setc(fl_ctx->wcstringtypesym, fl_list2(fl_ctx, fl_ctx->arraysym, fl_ctx->wcharsym));
     872                 :            : 
     873                 :         30 :     mk_primtype(fl_ctx, int8);
     874                 :         30 :     mk_primtype(fl_ctx, uint8);
     875                 :         30 :     mk_primtype(fl_ctx, int16);
     876                 :         30 :     mk_primtype(fl_ctx, uint16);
     877                 :         30 :     mk_primtype(fl_ctx, int32);
     878                 :         30 :     mk_primtype(fl_ctx, uint32);
     879                 :         30 :     mk_primtype(fl_ctx, int64);
     880                 :         30 :     mk_primtype(fl_ctx, uint64);
     881                 :            : #ifdef _P64
     882                 :         30 :     mk_primtype_(fl_ctx, ptrdiff, int64);
     883                 :         30 :     mk_primtype_(fl_ctx, size, uint64);
     884                 :            : #else
     885                 :            :     mk_primtype_(fl_ctx, ptrdiff, int32);
     886                 :            :     mk_primtype_(fl_ctx, size, uint32);
     887                 :            : #endif
     888                 :         30 :     mk_primtype_(fl_ctx, byte, uint8);
     889                 :         30 :     mk_primtype_(fl_ctx, wchar, int32);
     890                 :         30 :     mk_primtype(fl_ctx, float);
     891                 :         30 :     mk_primtype(fl_ctx, double);
     892                 :            : 
     893                 :         30 :     fl_ctx->stringtype = get_type(fl_ctx, symbol_value(fl_ctx->stringtypesym));
     894                 :         30 :     fl_ctx->wcstringtype = get_type(fl_ctx, symbol_value(fl_ctx->wcstringtypesym));
     895                 :            : 
     896                 :         30 :     fl_ctx->emptystringsym = symbol(fl_ctx, "*empty-string*");
     897                 :         30 :     setc(fl_ctx->emptystringsym, cvalue_static_cstring(fl_ctx, ""));
     898                 :         30 : }
     899                 :            : 
     900                 :            : #define RETURN_NUM_AS(fl_ctx, var, type) return(mk_##type(fl_ctx, (fl_##type##_t)var))
     901                 :            : 
     902                 :     753424 : value_t return_from_uint64(fl_context_t *fl_ctx, uint64_t Uaccum)
     903                 :            : {
     904   [ +  +  -  + ]:     753424 :     if (fits_fixnum(Uaccum)) {
     905                 :     751056 :         return fixnum((fixnum_t)Uaccum);
     906                 :            :     }
     907         [ +  + ]:       2368 :     if (Uaccum > (uint64_t)S64_MAX) {
     908                 :       1646 :         RETURN_NUM_AS(fl_ctx, Uaccum, uint64);
     909                 :            :     }
     910         [ +  - ]:        722 :     else if (Uaccum > (uint64_t)INT_MAX) {
     911                 :        722 :         RETURN_NUM_AS(fl_ctx, Uaccum, int64);
     912                 :            :     }
     913                 :          0 :     RETURN_NUM_AS(fl_ctx, Uaccum, int32);
     914                 :            : }
     915                 :            : 
     916                 :       5916 : value_t return_from_int64(fl_context_t *fl_ctx, int64_t Saccum)
     917                 :            : {
     918   [ +  +  +  + ]:       5916 :     if (fits_fixnum(Saccum)) {
     919                 :       5880 :         return fixnum((fixnum_t)Saccum);
     920                 :            :     }
     921   [ +  -  +  - ]:         36 :     if (Saccum > (int64_t)INT_MAX || Saccum < (int64_t)INT_MIN) {
     922                 :         36 :         RETURN_NUM_AS(fl_ctx, Saccum, int64);
     923                 :            :     }
     924                 :          0 :     RETURN_NUM_AS(fl_ctx, Saccum, int32);
     925                 :            : }
     926                 :            : 
     927                 :          0 : static value_t fl_add_any(fl_context_t *fl_ctx, value_t *args, uint32_t nargs, fixnum_t carryIn)
     928                 :            : {
     929                 :          0 :     uint64_t Uaccum=0;
     930                 :          0 :     int64_t Saccum = carryIn;
     931                 :          0 :     double Faccum=0;
     932                 :            :     uint32_t i;
     933                 :          0 :     value_t arg=fl_ctx->NIL;
     934                 :            : 
     935         [ #  # ]:          0 :     FOR_ARGS(i,0,arg,args) {
     936         [ #  # ]:          0 :         if (isfixnum(arg)) {
     937                 :          0 :             Saccum += numval(arg);
     938                 :          0 :             continue;
     939                 :            :         }
     940         [ #  # ]:          0 :         else if (iscprim(arg)) {
     941                 :          0 :             cprim_t *cp = (cprim_t*)ptr(arg);
     942                 :          0 :             void *a = cp_data(cp);
     943                 :            :             int64_t i64;
     944   [ #  #  #  #  :          0 :             switch(cp_numtype(cp)) {
          #  #  #  #  #  
                   #  # ]
     945                 :          0 :             case T_INT8:   Saccum += *(int8_t*)a; break;
     946                 :          0 :             case T_UINT8:  Saccum += *(uint8_t*)a; break;
     947                 :          0 :             case T_INT16:  Saccum += *(int16_t*)a; break;
     948                 :          0 :             case T_UINT16: Saccum += *(uint16_t*)a; break;
     949                 :          0 :             case T_INT32:  Saccum += *(int32_t*)a; break;
     950                 :          0 :             case T_UINT32: Saccum += *(uint32_t*)a; break;
     951                 :          0 :             case T_INT64:
     952                 :          0 :                 i64 = *(int64_t*)a;
     953         [ #  # ]:          0 :                 if (i64 > 0)
     954                 :          0 :                     Uaccum += (uint64_t)i64;
     955                 :            :                 else
     956                 :          0 :                     Saccum += i64;
     957                 :          0 :                 break;
     958                 :          0 :             case T_UINT64: Uaccum += *(uint64_t*)a; break;
     959                 :          0 :             case T_FLOAT:  Faccum += *(float*)a; break;
     960                 :          0 :             case T_DOUBLE: Faccum += *(double*)a; break;
     961                 :          0 :             default:
     962                 :          0 :                 goto add_type_error;
     963                 :            :             }
     964                 :          0 :             continue;
     965                 :            :         }
     966                 :          0 :     add_type_error:
     967                 :          0 :         type_error(fl_ctx, "+", "number", arg);
     968                 :            :     }
     969         [ #  # ]:          0 :     if (Faccum != 0) {
     970                 :          0 :         Faccum += Uaccum;
     971                 :          0 :         Faccum += Saccum;
     972                 :          0 :         return mk_double(fl_ctx, Faccum);
     973                 :            :     }
     974         [ #  # ]:          0 :     else if (Saccum < 0) {
     975                 :          0 :         uint64_t negpart = (uint64_t)(-Saccum);
     976         [ #  # ]:          0 :         if (negpart > Uaccum) {
     977                 :          0 :             Saccum += (int64_t)Uaccum;
     978                 :            :             // return value in Saccum
     979         [ #  # ]:          0 :             if (Saccum >= INT_MIN) {
     980   [ #  #  #  # ]:          0 :                 if (fits_fixnum(Saccum)) {
     981                 :          0 :                     return fixnum((fixnum_t)Saccum);
     982                 :            :                 }
     983                 :          0 :                 RETURN_NUM_AS(fl_ctx, Saccum, int32);
     984                 :            :             }
     985                 :          0 :             RETURN_NUM_AS(fl_ctx, Saccum, int64);
     986                 :            :         }
     987                 :          0 :         Uaccum -= negpart;
     988                 :            :     }
     989                 :            :     else {
     990                 :          0 :         Uaccum += (uint64_t)Saccum;
     991                 :            :     }
     992                 :            :     // return value in Uaccum
     993                 :          0 :     return return_from_uint64(fl_ctx, Uaccum);
     994                 :            : }
     995                 :            : 
     996                 :          0 : static value_t fl_neg(fl_context_t *fl_ctx, value_t n)
     997                 :            : {
     998         [ #  # ]:          0 :     if (isfixnum(n)) {
     999                 :          0 :         return fixnum(-numval(n));
    1000                 :            :     }
    1001         [ #  # ]:          0 :     else if (iscprim(n)) {
    1002                 :          0 :         cprim_t *cp = (cprim_t*)ptr(n);
    1003                 :          0 :         void *a = cp_data(cp);
    1004                 :            :         uint32_t ui32;
    1005                 :            :         int32_t i32;
    1006                 :            :         int64_t i64;
    1007   [ #  #  #  #  :          0 :         switch(cp_numtype(cp)) {
          #  #  #  #  #  
                   #  # ]
    1008                 :          0 :         case T_INT8:   return fixnum(-(int32_t)*(int8_t*)a);
    1009                 :          0 :         case T_UINT8:  return fixnum(-(int32_t)*(uint8_t*)a);
    1010                 :          0 :         case T_INT16:  return fixnum(-(int32_t)*(int16_t*)a);
    1011                 :          0 :         case T_UINT16: return fixnum(-(int32_t)*(uint16_t*)a);
    1012                 :          0 :         case T_INT32:
    1013                 :          0 :             i32 = *(int32_t*)a;
    1014         [ #  # ]:          0 :             if (i32 == (int32_t)BIT31)
    1015                 :          0 :                 return mk_uint32(fl_ctx, (uint32_t)BIT31);
    1016                 :          0 :             return mk_int32(fl_ctx, -i32);
    1017                 :          0 :         case T_UINT32:
    1018                 :          0 :             ui32 = *(uint32_t*)a;
    1019         [ #  # ]:          0 :             if (ui32 <= ((uint32_t)INT_MAX)+1) return mk_int32(fl_ctx, -(int32_t)ui32);
    1020                 :          0 :             return mk_int64(fl_ctx, -(int64_t)ui32);
    1021                 :          0 :         case T_INT64:
    1022                 :          0 :             i64 = *(int64_t*)a;
    1023         [ #  # ]:          0 :             if (i64 == (int64_t)BIT63)
    1024                 :          0 :                 return mk_uint64(fl_ctx, (uint64_t)BIT63);
    1025                 :          0 :             return mk_int64(fl_ctx, -i64);
    1026                 :          0 :         case T_UINT64: return mk_int64(fl_ctx, -(int64_t)*(uint64_t*)a);
    1027                 :          0 :         case T_FLOAT:  return mk_float(fl_ctx, -*(float*)a);
    1028                 :          0 :         case T_DOUBLE: return mk_double(fl_ctx, -*(double*)a);
    1029                 :            :             break;
    1030                 :            :         }
    1031                 :            :     }
    1032                 :          0 :     type_error(fl_ctx, "-", "number", n);
    1033                 :            : }
    1034                 :            : 
    1035                 :          0 : static value_t fl_mul_any(fl_context_t *fl_ctx, value_t *args, uint32_t nargs, int64_t Saccum)
    1036                 :            : {
    1037                 :          0 :     uint64_t Uaccum=1;
    1038                 :          0 :     double Faccum=1;
    1039                 :            :     uint32_t i;
    1040                 :          0 :     value_t arg=fl_ctx->NIL;
    1041                 :            : 
    1042         [ #  # ]:          0 :     FOR_ARGS(i,0,arg,args) {
    1043         [ #  # ]:          0 :         if (isfixnum(arg)) {
    1044                 :          0 :             Saccum *= numval(arg);
    1045                 :          0 :             continue;
    1046                 :            :         }
    1047         [ #  # ]:          0 :         else if (iscprim(arg)) {
    1048                 :          0 :             cprim_t *cp = (cprim_t*)ptr(arg);
    1049                 :          0 :             void *a = cp_data(cp);
    1050                 :            :             int64_t i64;
    1051   [ #  #  #  #  :          0 :             switch(cp_numtype(cp)) {
          #  #  #  #  #  
                   #  # ]
    1052                 :          0 :             case T_INT8:   Saccum *= *(int8_t*)a; break;
    1053                 :          0 :             case T_UINT8:  Saccum *= *(uint8_t*)a; break;
    1054                 :          0 :             case T_INT16:  Saccum *= *(int16_t*)a; break;
    1055                 :          0 :             case T_UINT16: Saccum *= *(uint16_t*)a; break;
    1056                 :          0 :             case T_INT32:  Saccum *= *(int32_t*)a; break;
    1057                 :          0 :             case T_UINT32: Saccum *= *(uint32_t*)a; break;
    1058                 :          0 :             case T_INT64:
    1059                 :          0 :                 i64 = *(int64_t*)a;
    1060         [ #  # ]:          0 :                 if (i64 > 0)
    1061                 :          0 :                     Uaccum *= (uint64_t)i64;
    1062                 :            :                 else
    1063                 :          0 :                     Saccum *= i64;
    1064                 :          0 :                 break;
    1065                 :          0 :             case T_UINT64: Uaccum *= *(uint64_t*)a; break;
    1066                 :          0 :             case T_FLOAT:  Faccum *= *(float*)a; break;
    1067                 :          0 :             case T_DOUBLE: Faccum *= *(double*)a; break;
    1068                 :          0 :             default:
    1069                 :          0 :                 goto mul_type_error;
    1070                 :            :             }
    1071                 :          0 :             continue;
    1072                 :            :         }
    1073                 :          0 :     mul_type_error:
    1074                 :          0 :         type_error(fl_ctx, "*", "number", arg);
    1075                 :            :     }
    1076         [ #  # ]:          0 :     if (Faccum != 1) {
    1077                 :          0 :         Faccum *= Uaccum;
    1078                 :          0 :         Faccum *= Saccum;
    1079                 :          0 :         return mk_double(fl_ctx, Faccum);
    1080                 :            :     }
    1081         [ #  # ]:          0 :     else if (Saccum < 0) {
    1082                 :          0 :         Saccum *= (int64_t)Uaccum;
    1083         [ #  # ]:          0 :         if (Saccum >= INT_MIN) {
    1084   [ #  #  #  # ]:          0 :             if (fits_fixnum(Saccum)) {
    1085                 :          0 :                 return fixnum((fixnum_t)Saccum);
    1086                 :            :             }
    1087                 :          0 :             RETURN_NUM_AS(fl_ctx, Saccum, int32);
    1088                 :            :         }
    1089                 :          0 :         RETURN_NUM_AS(fl_ctx, Saccum, int64);
    1090                 :            :     }
    1091                 :            :     else {
    1092                 :          0 :         Uaccum *= (uint64_t)Saccum;
    1093                 :            :     }
    1094                 :          0 :     return return_from_uint64(fl_ctx, Uaccum);
    1095                 :            : }
    1096                 :            : 
    1097                 :  299310000 : static int num_to_ptr(value_t a, fixnum_t *pi, numerictype_t *pt, void **pp)
    1098                 :            : {
    1099                 :            :     cprim_t *cp;
    1100         [ +  + ]:  299310000 :     if (isfixnum(a)) {
    1101                 :     318504 :         *pi = numval(a);
    1102                 :     318504 :         *pp = pi;
    1103                 :     318504 :         *pt = T_FIXNUM;
    1104                 :            :     }
    1105         [ +  + ]:  298992000 :     else if (iscprim(a)) {
    1106                 :  298984000 :         cp = (cprim_t*)ptr(a);
    1107                 :  298984000 :         *pp = cp_data(cp);
    1108                 :  298984000 :         *pt = cp_numtype(cp);
    1109                 :            :     }
    1110                 :            :     else {
    1111                 :       6566 :         return 0;
    1112                 :            :     }
    1113                 :  299304000 :     return 1;
    1114                 :            : }
    1115                 :            : 
    1116                 :            : /*
    1117                 :            :   returns -1, 0, or 1 based on ordering of a and b
    1118                 :            :   eq: consider equality only, returning 0 or nonzero
    1119                 :            :   eqnans: NaNs considered equal to each other
    1120                 :            :           -0.0 not considered equal to 0.0
    1121                 :            :           inexact not considered equal to exact
    1122                 :            :   fname: if not NULL, throws type errors, else returns 2 for type errors
    1123                 :            : */
    1124                 :  149655000 : int numeric_compare(fl_context_t *fl_ctx, value_t a, value_t b, int eq, int eqnans, char *fname)
    1125                 :            : {
    1126                 :            :     int_t ai, bi;
    1127                 :            :     numerictype_t ta, tb;
    1128                 :            :     void *aptr, *bptr;
    1129                 :            : 
    1130         [ -  + ]:  149655000 :     if (bothfixnums(a,b)) {
    1131         [ #  # ]:          0 :         if (a==b) return 0;
    1132         [ #  # ]:          0 :         if (numval(a) < numval(b)) return -1;
    1133                 :          0 :         return 1;
    1134                 :            :     }
    1135         [ -  + ]:  149655000 :     if (!num_to_ptr(a, &ai, &ta, &aptr)) {
    1136         [ #  # ]:          0 :         if (fname) type_error(fl_ctx, fname, "number", a); else return 2;
    1137                 :            :     }
    1138         [ +  + ]:  149655000 :     if (!num_to_ptr(b, &bi, &tb, &bptr)) {
    1139         [ -  + ]:       6566 :         if (fname) type_error(fl_ctx, fname, "number", b); else return 2;
    1140                 :            :     }
    1141   [ +  +  +  +  :  149648400 :     if (eq && eqnans && ((ta >= T_FLOAT) != (tb >= T_FLOAT)))
                   -  + ]
    1142                 :          0 :         return 1;
    1143         [ +  + ]:  149648400 :     if (cmp_eq(aptr, ta, bptr, tb, eqnans))
    1144                 :    8015320 :         return 0;
    1145         [ +  + ]:  141633200 :     if (eq) return 1;
    1146         [ +  + ]:     172158 :     if (cmp_lt(aptr, ta, bptr, tb))
    1147                 :      52124 :         return -1;
    1148                 :     120034 :     return 1;
    1149                 :            : }
    1150                 :            : 
    1151                 :            : #if defined(_OS_WINDOWS_)
    1152                 :            : __declspec(noreturn) static void DivideByZeroError(fl_context_t *fl_ctx);
    1153                 :            : #else
    1154                 :            : static void DivideByZeroError(fl_context_t *fl_ctx) __attribute__ ((__noreturn__));
    1155                 :            : #endif
    1156                 :            : 
    1157                 :          0 : static void DivideByZeroError(fl_context_t *fl_ctx)
    1158                 :            : {
    1159                 :          0 :     lerror(fl_ctx, fl_ctx->DivideError, "/: division by zero");
    1160                 :            : }
    1161                 :            : 
    1162                 :         12 : static value_t fl_div2(fl_context_t *fl_ctx, value_t a, value_t b)
    1163                 :            : {
    1164                 :            :     double da, db;
    1165                 :            :     int_t ai, bi;
    1166                 :            :     numerictype_t ta, tb;
    1167                 :            :     void *aptr, *bptr;
    1168                 :            : 
    1169         [ -  + ]:         12 :     if (!num_to_ptr(a, &ai, &ta, &aptr))
    1170                 :          0 :         type_error(fl_ctx, "/", "number", a);
    1171         [ -  + ]:         12 :     if (!num_to_ptr(b, &bi, &tb, &bptr))
    1172                 :          0 :         type_error(fl_ctx, "/", "number", b);
    1173                 :            : 
    1174                 :         12 :     da = conv_to_double(aptr, ta);
    1175                 :         12 :     db = conv_to_double(bptr, tb);
    1176                 :            : 
    1177   [ -  +  -  - ]:         12 :     if (db == 0 && tb < T_FLOAT)  // exact 0
    1178                 :          0 :         DivideByZeroError(fl_ctx);
    1179                 :            : 
    1180                 :         12 :     da = da/db;
    1181                 :            : 
    1182   [ +  -  +  -  :         12 :     if (ta < T_FLOAT && tb < T_FLOAT && (double)(int64_t)da == da)
                   +  - ]
    1183                 :         12 :         return return_from_int64(fl_ctx, (int64_t)da);
    1184                 :          0 :     return mk_double(fl_ctx, da);
    1185                 :            : }
    1186                 :            : 
    1187                 :          0 : static value_t fl_idiv2(fl_context_t *fl_ctx, value_t a, value_t b)
    1188                 :            : {
    1189                 :            :     int_t ai, bi;
    1190                 :            :     numerictype_t ta, tb;
    1191                 :            :     void *aptr, *bptr;
    1192                 :            :     int64_t a64, b64;
    1193                 :            : 
    1194         [ #  # ]:          0 :     if (!num_to_ptr(a, &ai, &ta, &aptr))
    1195                 :          0 :         type_error(fl_ctx, "div0", "number", a);
    1196         [ #  # ]:          0 :     if (!num_to_ptr(b, &bi, &tb, &bptr))
    1197                 :          0 :         type_error(fl_ctx, "div0", "number", b);
    1198                 :            : 
    1199         [ #  # ]:          0 :     if (ta == T_UINT64) {
    1200         [ #  # ]:          0 :         if (tb == T_UINT64) {
    1201         [ #  # ]:          0 :             if (*(uint64_t*)bptr == 0) goto div_error;
    1202                 :          0 :             return return_from_uint64(fl_ctx, *(uint64_t*)aptr / *(uint64_t*)bptr);
    1203                 :            :         }
    1204                 :          0 :         b64 = conv_to_int64(bptr, tb);
    1205         [ #  # ]:          0 :         if (b64 < 0) {
    1206                 :          0 :             return return_from_int64(fl_ctx, -(int64_t)(*(uint64_t*)aptr /
    1207                 :          0 :                                                         (uint64_t)(-b64)));
    1208                 :            :         }
    1209         [ #  # ]:          0 :         if (b64 == 0)
    1210                 :          0 :             goto div_error;
    1211                 :          0 :         return return_from_uint64(fl_ctx, *(uint64_t*)aptr / (uint64_t)b64);
    1212                 :            :     }
    1213         [ #  # ]:          0 :     if (tb == T_UINT64) {
    1214         [ #  # ]:          0 :         if (*(uint64_t*)bptr == 0) goto div_error;
    1215                 :          0 :         a64 = conv_to_int64(aptr, ta);
    1216         [ #  # ]:          0 :         if (a64 < 0) {
    1217                 :          0 :             return return_from_int64(fl_ctx, -((int64_t)((uint64_t)(-a64) /
    1218                 :          0 :                                                          *(uint64_t*)bptr)));
    1219                 :            :         }
    1220                 :          0 :         return return_from_uint64(fl_ctx, (uint64_t)a64 / *(uint64_t*)bptr);
    1221                 :            :     }
    1222                 :            : 
    1223                 :          0 :     b64 = conv_to_int64(bptr, tb);
    1224         [ #  # ]:          0 :     if (b64 == 0) goto div_error;
    1225                 :            : 
    1226                 :          0 :     return return_from_int64(fl_ctx, conv_to_int64(aptr, ta) / b64);
    1227                 :          0 :  div_error:
    1228                 :          0 :     DivideByZeroError(fl_ctx);
    1229                 :            : }
    1230                 :            : 
    1231                 :          0 : static value_t fl_bitwise_op(fl_context_t *fl_ctx, value_t a, value_t b, int opcode, char *fname)
    1232                 :            : {
    1233                 :            :     int_t ai, bi;
    1234                 :            :     numerictype_t ta, tb, itmp;
    1235                 :          0 :     void *aptr=NULL, *bptr=NULL, *ptmp;
    1236                 :            :     int64_t b64;
    1237                 :            : 
    1238   [ #  #  #  # ]:          0 :     if (!num_to_ptr(a, &ai, &ta, &aptr) || ta >= T_FLOAT)
    1239                 :          0 :         type_error(fl_ctx, fname, "integer", a);
    1240   [ #  #  #  # ]:          0 :     if (!num_to_ptr(b, &bi, &tb, &bptr) || tb >= T_FLOAT)
    1241                 :          0 :         type_error(fl_ctx, fname, "integer", b);
    1242                 :            : 
    1243         [ #  # ]:          0 :     if (ta < tb) {
    1244                 :          0 :         itmp = ta; ta = tb; tb = itmp;
    1245                 :          0 :         ptmp = aptr; aptr = bptr; bptr = ptmp;
    1246                 :            :     }
    1247                 :            :     // now a's type is larger than or same as b's
    1248                 :          0 :     b64 = conv_to_int64(bptr, tb);
    1249   [ #  #  #  # ]:          0 :     switch (opcode) {
    1250                 :          0 :     case 0:
    1251   [ #  #  #  #  :          0 :     switch (ta) {
          #  #  #  #  #  
                      # ]
    1252                 :          0 :     case T_INT8:   return fixnum(   *(int8_t *)aptr  & (int8_t  )b64);
    1253                 :          0 :     case T_UINT8:  return fixnum(   *(uint8_t *)aptr & (uint8_t )b64);
    1254                 :          0 :     case T_INT16:  return fixnum(   *(int16_t*)aptr  & (int16_t )b64);
    1255                 :          0 :     case T_UINT16: return fixnum(   *(uint16_t*)aptr & (uint16_t)b64);
    1256                 :          0 :     case T_INT32:  return mk_int32(fl_ctx,  *(int32_t*)aptr  & (int32_t )b64);
    1257                 :          0 :     case T_UINT32: return mk_uint32(fl_ctx, *(uint32_t*)aptr & (uint32_t)b64);
    1258                 :          0 :     case T_INT64:  return mk_int64(fl_ctx,  *(int64_t*)aptr  & (int64_t )b64);
    1259                 :          0 :     case T_UINT64: return mk_uint64(fl_ctx, *(uint64_t*)aptr & (uint64_t)b64);
    1260                 :          0 :     case T_FLOAT:
    1261                 :          0 :     case T_DOUBLE: assert(0);
    1262                 :            :     }
    1263                 :          0 :     break;
    1264                 :          0 :     case 1:
    1265   [ #  #  #  #  :          0 :     switch (ta) {
          #  #  #  #  #  
                      # ]
    1266                 :          0 :     case T_INT8:   return fixnum(   *(int8_t *)aptr  | (int8_t  )b64);
    1267                 :          0 :     case T_UINT8:  return fixnum(   *(uint8_t *)aptr | (uint8_t )b64);
    1268                 :          0 :     case T_INT16:  return fixnum(   *(int16_t*)aptr  | (int16_t )b64);
    1269                 :          0 :     case T_UINT16: return fixnum(   *(uint16_t*)aptr | (uint16_t)b64);
    1270                 :          0 :     case T_INT32:  return mk_int32(fl_ctx,  *(int32_t*)aptr  | (int32_t )b64);
    1271                 :          0 :     case T_UINT32: return mk_uint32(fl_ctx, *(uint32_t*)aptr | (uint32_t)b64);
    1272                 :          0 :     case T_INT64:  return mk_int64(fl_ctx,  *(int64_t*)aptr  | (int64_t )b64);
    1273                 :          0 :     case T_UINT64: return mk_uint64(fl_ctx, *(uint64_t*)aptr | (uint64_t)b64);
    1274                 :          0 :     case T_FLOAT:
    1275                 :          0 :     case T_DOUBLE: assert(0);
    1276                 :            :     }
    1277                 :          0 :     break;
    1278                 :          0 :     case 2:
    1279   [ #  #  #  #  :          0 :     switch (ta) {
          #  #  #  #  #  
                      # ]
    1280                 :          0 :     case T_INT8:   return fixnum(   *(int8_t *)aptr  ^ (int8_t  )b64);
    1281                 :          0 :     case T_UINT8:  return fixnum(   *(uint8_t *)aptr ^ (uint8_t )b64);
    1282                 :          0 :     case T_INT16:  return fixnum(   *(int16_t*)aptr  ^ (int16_t )b64);
    1283                 :          0 :     case T_UINT16: return fixnum(   *(uint16_t*)aptr ^ (uint16_t)b64);
    1284                 :          0 :     case T_INT32:  return mk_int32(fl_ctx,  *(int32_t*)aptr  ^ (int32_t )b64);
    1285                 :          0 :     case T_UINT32: return mk_uint32(fl_ctx, *(uint32_t*)aptr ^ (uint32_t)b64);
    1286                 :          0 :     case T_INT64:  return mk_int64(fl_ctx,  *(int64_t*)aptr  ^ (int64_t )b64);
    1287                 :          0 :     case T_UINT64: return mk_uint64(fl_ctx, *(uint64_t*)aptr ^ (uint64_t)b64);
    1288                 :          0 :     case T_FLOAT:
    1289                 :          0 :     case T_DOUBLE: assert(0);
    1290                 :            :     }
    1291                 :            :     }
    1292                 :          0 :     assert(0);
    1293                 :            :     return fl_ctx->NIL;
    1294                 :            : }
    1295                 :            : 
    1296                 :    5518740 : static value_t fl_logand(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
    1297                 :            : {
    1298                 :            :     value_t v, e;
    1299                 :            :     int i;
    1300         [ -  + ]:    5518740 :     if (nargs == 0)
    1301                 :          0 :         return fixnum(-1);
    1302                 :    5518740 :     v = args[0];
    1303         [ +  + ]:   11037500 :     FOR_ARGS(i,1,e,args) {
    1304         [ +  - ]:    5518740 :         if (bothfixnums(v, e))
    1305                 :    5518740 :             v = v & e;
    1306                 :            :         else
    1307                 :          0 :             v = fl_bitwise_op(fl_ctx, v, e, 0, "logand");
    1308                 :            :     }
    1309                 :    5518740 :     return v;
    1310                 :            : }
    1311                 :            : 
    1312                 :    1710144 : static value_t fl_logior(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
    1313                 :            : {
    1314                 :            :     value_t v, e;
    1315                 :            :     int i;
    1316         [ -  + ]:    1710144 :     if (nargs == 0)
    1317                 :          0 :         return fixnum(0);
    1318                 :    1710144 :     v = args[0];
    1319         [ +  + ]:    3420280 :     FOR_ARGS(i,1,e,args) {
    1320         [ +  - ]:    1710144 :         if (bothfixnums(v, e))
    1321                 :    1710144 :             v = v | e;
    1322                 :            :         else
    1323                 :          0 :             v = fl_bitwise_op(fl_ctx, v, e, 1, "logior");
    1324                 :            :     }
    1325                 :    1710144 :     return v;
    1326                 :            : }
    1327                 :            : 
    1328                 :          0 : static value_t fl_logxor(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
    1329                 :            : {
    1330                 :            :     value_t v, e;
    1331                 :            :     int i;
    1332         [ #  # ]:          0 :     if (nargs == 0)
    1333                 :          0 :         return fixnum(0);
    1334                 :          0 :     v = args[0];
    1335         [ #  # ]:          0 :     FOR_ARGS(i,1,e,args) {
    1336         [ #  # ]:          0 :         if (bothfixnums(v, e))
    1337                 :          0 :             v = fixnum(numval(v) ^ numval(e));
    1338                 :            :         else
    1339                 :          0 :             v = fl_bitwise_op(fl_ctx, v, e, 2, "logxor");
    1340                 :            :     }
    1341                 :          0 :     return v;
    1342                 :            : }
    1343                 :            : 
    1344                 :     622230 : static value_t fl_lognot(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
    1345                 :            : {
    1346                 :     622230 :     argcount(fl_ctx, "lognot", nargs, 1);
    1347                 :     622230 :     value_t a = args[0];
    1348         [ +  - ]:     622230 :     if (isfixnum(a))
    1349                 :     622230 :         return fixnum(~numval(a));
    1350                 :            :     cprim_t *cp;
    1351                 :            :     int ta;
    1352                 :            :     void *aptr;
    1353                 :            : 
    1354         [ #  # ]:          0 :     if (iscprim(a)) {
    1355                 :          0 :         cp = (cprim_t*)ptr(a);
    1356                 :          0 :         ta = cp_numtype(cp);
    1357                 :          0 :         aptr = cp_data(cp);
    1358   [ #  #  #  #  :          0 :         switch (ta) {
             #  #  #  #  
                      # ]
    1359                 :          0 :         case T_INT8:   return fixnum(~*(int8_t *)aptr);
    1360                 :          0 :         case T_UINT8:  return fixnum(~*(uint8_t *)aptr);
    1361                 :          0 :         case T_INT16:  return fixnum(~*(int16_t *)aptr);
    1362                 :          0 :         case T_UINT16: return fixnum(~*(uint16_t*)aptr);
    1363                 :          0 :         case T_INT32:  return mk_int32(fl_ctx, ~*(int32_t *)aptr);
    1364                 :          0 :         case T_UINT32: return mk_uint32(fl_ctx, ~*(uint32_t*)aptr);
    1365                 :          0 :         case T_INT64:  return mk_int64(fl_ctx, ~*(int64_t *)aptr);
    1366                 :          0 :         case T_UINT64: return mk_uint64(fl_ctx, ~*(uint64_t*)aptr);
    1367                 :            :         }
    1368                 :            :     }
    1369                 :          0 :     type_error(fl_ctx, "lognot", "integer", a);
    1370                 :            : }
    1371                 :            : 
    1372                 :          0 : static value_t fl_ash(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
    1373                 :            : {
    1374                 :            :     fixnum_t n;
    1375                 :            :     int64_t accum;
    1376                 :          0 :     argcount(fl_ctx, "ash", nargs, 2);
    1377                 :          0 :     value_t a = args[0];
    1378                 :          0 :     n = tofixnum(fl_ctx, args[1], "ash");
    1379         [ #  # ]:          0 :     if (isfixnum(a)) {
    1380         [ #  # ]:          0 :         if (n <= 0)
    1381                 :          0 :             return fixnum(numval(a)>>(-n));
    1382                 :          0 :         accum = ((int64_t)numval(a))<<n;
    1383   [ #  #  #  # ]:          0 :         if (fits_fixnum(accum))
    1384                 :          0 :             return fixnum(accum);
    1385                 :            :         else
    1386                 :          0 :             return return_from_int64(fl_ctx, accum);
    1387                 :            :     }
    1388                 :            :     cprim_t *cp;
    1389                 :            :     int ta;
    1390                 :            :     void *aptr;
    1391         [ #  # ]:          0 :     if (iscprim(a)) {
    1392         [ #  # ]:          0 :         if (n == 0) return a;
    1393                 :          0 :         cp = (cprim_t*)ptr(a);
    1394                 :          0 :         ta = cp_numtype(cp);
    1395                 :          0 :         aptr = cp_data(cp);
    1396         [ #  # ]:          0 :         if (n < 0) {
    1397                 :          0 :             n = -n;
    1398   [ #  #  #  #  :          0 :             switch (ta) {
             #  #  #  #  
                      # ]
    1399                 :          0 :             case T_INT8:   return fixnum((*(int8_t *)aptr) >> n);
    1400                 :          0 :             case T_UINT8:  return fixnum((*(uint8_t *)aptr) >> n);
    1401                 :          0 :             case T_INT16:  return fixnum((*(int16_t *)aptr) >> n);
    1402                 :          0 :             case T_UINT16: return fixnum((*(uint16_t*)aptr) >> n);
    1403                 :          0 :             case T_INT32:  return mk_int32(fl_ctx, (*(int32_t *)aptr) >> n);
    1404                 :          0 :             case T_UINT32: return mk_uint32(fl_ctx, (*(uint32_t*)aptr) >> n);
    1405                 :          0 :             case T_INT64:  return mk_int64(fl_ctx, (*(int64_t *)aptr) >> n);
    1406                 :          0 :             case T_UINT64: return mk_uint64(fl_ctx, (*(uint64_t*)aptr) >> n);
    1407                 :            :             }
    1408                 :            :         }
    1409                 :            :         else {
    1410         [ #  # ]:          0 :             if (ta == T_UINT64)
    1411                 :          0 :                 return return_from_uint64(fl_ctx, (*(uint64_t*)aptr)<<n);
    1412         [ #  # ]:          0 :             else if (ta < T_FLOAT) {
    1413                 :          0 :                 int64_t i64 = conv_to_int64(aptr, (numerictype_t)ta);
    1414                 :          0 :                 return return_from_int64(fl_ctx, i64<<n);
    1415                 :            :             }
    1416                 :            :         }
    1417                 :            :     }
    1418                 :          0 :     type_error(fl_ctx, "ash", "integer", a);
    1419                 :            :     return fl_ctx->NIL;
    1420                 :            : }

Generated by: LCOV version 1.14