LCOV - code coverage report
Current view: top level - src - array.c (source / functions) Hit Total Coverage
Test: [test only] commit 0f242327d2cc9bd130497f44b6350c924185606a Lines: 754 816 92.4 %
Date: 2022-07-16 23:42:53 Functions: 53 55 96.4 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 421 525 80.2 %

           Branch data     Line data    Source code
       1                 :            : // This file is a part of Julia. License is MIT: https://julialang.org/license
       2                 :            : 
       3                 :            : /*
       4                 :            :   array constructors and primitives
       5                 :            : */
       6                 :            : #include <stdlib.h>
       7                 :            : #include <string.h>
       8                 :            : #ifdef _OS_WINDOWS_
       9                 :            : #include <malloc.h>
      10                 :            : #endif
      11                 :            : #include "julia.h"
      12                 :            : #include "julia_internal.h"
      13                 :            : #include "julia_assert.h"
      14                 :            : 
      15                 :            : #ifdef __cplusplus
      16                 :            : extern "C" {
      17                 :            : #endif
      18                 :            : 
      19                 :            : #define JL_ARRAY_IMPL_NUL 1
      20                 :            : 
      21                 :            : #define JL_ARRAY_ALIGN(jl_value, nbytes) LLT_ALIGN(jl_value, nbytes)
      22                 :            : 
      23                 :   11353900 : static inline void arrayassign_safe(int hasptr, jl_value_t *parent, char *dst, const jl_value_t *src, size_t nb) JL_NOTSAFEPOINT
      24                 :            : {
      25                 :            :     // array can assume more alignment than a field would normally have
      26         [ -  + ]:   11353900 :     assert(nb >= jl_datatype_size(jl_typeof(src))); // nb might move some undefined bits, but we should be okay with that
      27         [ +  + ]:   11353900 :     if (hasptr) {
      28                 :    1268860 :         size_t nptr = nb / sizeof(void*);
      29                 :    1268860 :         memmove_refs((void**)dst, (void* const*)src, nptr);
      30                 :    1268860 :         jl_gc_multi_wb(parent, src);
      31                 :            :     }
      32                 :            :     else {
      33   [ -  +  -  +  :   10085000 :         switch (nb) {
                +  +  + ]
      34                 :          0 :         case  0: break;
      35                 :    3831490 :         case  1: *(uint8_t*)dst  = *(uint8_t*)src;  break;
      36                 :          0 :         case  2: *(uint16_t*)dst = *(uint16_t*)src; break;
      37                 :    4740740 :         case  4: *(uint32_t*)dst = *(uint32_t*)src; break;
      38                 :    1434680 :         case  8: *(uint64_t*)dst = *(uint64_t*)src; break;
      39                 :      37873 :         case 16:
      40                 :      37873 :             memcpy(jl_assume_aligned(dst, 16), jl_assume_aligned(src, 16), 16);
      41                 :      37873 :             break;
      42                 :      40234 :         default: memcpy(dst, src, nb);
      43                 :            :         }
      44                 :            :     }
      45                 :   11353900 : }
      46                 :            : 
      47                 :    2705080 : static inline void memmove_safe(int hasptr, char *dst, const char *src, size_t nb) JL_NOTSAFEPOINT
      48                 :            : {
      49         [ +  + ]:    2705080 :     if (hasptr)
      50                 :     328854 :         memmove_refs((void**)dst, (void**)src, nb / sizeof(void*));
      51                 :            :     else
      52                 :    2376230 :         memmove(dst, src, nb);
      53                 :    2705080 : }
      54                 :            : 
      55                 :            : // array constructors ---------------------------------------------------------
      56                 :   23341000 : JL_DLLEXPORT char *jl_array_typetagdata(jl_array_t *a) JL_NOTSAFEPOINT
      57                 :            : {
      58   [ +  -  +  - ]:   23341000 :     assert(jl_array_isbitsunion(a));
      59         [ +  + ]:   23341000 :     return ((char*)jl_array_data(a)) + ((jl_array_ndims(a) == 1 ? (a->maxsize - a->offset) : jl_array_len(a)) * a->elsize) + a->offset;
      60                 :            : }
      61                 :            : 
      62                 :   69136300 : STATIC_INLINE jl_value_t *jl_array_owner(jl_array_t *a JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT
      63                 :            : {
      64         [ +  + ]:   69136300 :     if (a->flags.how == 3) {
      65                 :        262 :         a = (jl_array_t*)jl_array_data_owner(a);
      66   [ +  -  -  + ]:        262 :         assert(jl_is_string(a) || a->flags.how != 3);
      67                 :            :     }
      68                 :   69136300 :     return (jl_value_t*)a;
      69                 :            : }
      70                 :            : 
      71                 :            : #if defined(_P64) && defined(UINT128MAX)
      72                 :            : typedef __uint128_t wideint_t;
      73                 :            : #else
      74                 :            : typedef uint64_t wideint_t;
      75                 :            : #endif
      76                 :            : 
      77                 :            : #define MAXINTVAL (((size_t)-1)>>1)
      78                 :            : 
      79                 : 3765390000 : JL_DLLEXPORT int jl_array_validate_dims(size_t *nel, size_t *tot, uint32_t ndims, size_t *dims, size_t elsz)
      80                 :            : {
      81                 :            :     size_t i;
      82                 : 3765390000 :     size_t _nel = 1;
      83         [ +  + ]: 7531340000 :     for(i=0; i < ndims; i++) {
      84                 : 3765950000 :         size_t di = dims[i];
      85                 : 3765950000 :         wideint_t prod = (wideint_t)_nel * (wideint_t)di;
      86   [ +  +  #  + ]: 3765950000 :         if (prod >= (wideint_t) MAXINTVAL || di >= MAXINTVAL)
      87                 :         52 :             return 1;
      88                 : 3765950000 :         _nel = prod;
      89                 :            :     }
      90                 : 3765390000 :     wideint_t prod = (wideint_t)elsz * (wideint_t)_nel;
      91         [ -  + ]: 3765390000 :     if (prod >= (wideint_t) MAXINTVAL)
      92                 :          0 :         return 2;
      93                 : 3765390000 :     *nel = _nel;
      94                 : 3765390000 :     *tot = (size_t)prod;
      95                 : 3765390000 :     return 0;
      96                 :            : }
      97                 :            : 
      98                 : 3765380000 : static jl_array_t *_new_array_(jl_value_t *atype, uint32_t ndims, size_t *dims,
      99                 :            :                                int8_t isunboxed, int8_t hasptr, int8_t isunion, int8_t zeroinit, size_t elsz)
     100                 :            : {
     101                 : 3765380000 :     jl_task_t *ct = jl_current_task;
     102                 :            :     size_t i, tot, nel;
     103                 :            :     void *data;
     104                 :            :     jl_array_t *a;
     105   [ +  +  -  + ]: 3765380000 :     assert(isunboxed || elsz == sizeof(void*));
     106   [ +  +  -  + ]: 3765380000 :     assert(atype == NULL || isunion == jl_is_uniontype(jl_tparam0(atype)));
     107                 : 3765380000 :     int validated = jl_array_validate_dims(&nel, &tot, ndims, dims, elsz);
     108         [ #  + ]: 3765380000 :     if (validated == 1)
     109                 :          0 :         jl_exceptionf(jl_argumenterror_type, "invalid Array dimensions");
     110         [ -  + ]: 3765380000 :     else if (validated == 2)
     111                 :          0 :         jl_error("invalid Array size");
     112         [ +  + ]: 3765380000 :     if (isunboxed) {
     113   [ +  +  +  + ]: 2163270000 :         if (elsz == 1 && !isunion) {
     114                 :            :             // extra byte for all julia allocated byte arrays
     115                 :  216855000 :             tot++;
     116                 :            :         }
     117         [ +  + ]: 2163270000 :         if (isunion) {
     118                 :            :             // an extra byte for each isbits union array element, stored after a->maxsize
     119                 :   26405800 :             tot += nel;
     120                 :            :         }
     121                 :            :     }
     122                 :            : 
     123                 : 3765380000 :     int ndimwords = jl_array_ndimwords(ndims);
     124                 : 3765380000 :     int tsz = sizeof(jl_array_t) + ndimwords*sizeof(size_t);
     125         [ +  + ]: 3765380000 :     if (tot <= ARRAY_INLINE_NBYTES) {
     126                 :            :         // align data area
     127         [ +  + ]: 3765220000 :         if (tot >= ARRAY_CACHE_ALIGN_THRESHOLD)
     128                 :    3884380 :             tsz = JL_ARRAY_ALIGN(tsz, JL_CACHE_BYTE_ALIGNMENT);
     129   [ +  +  +  + ]: 3761340000 :         else if (isunboxed && elsz >= 4)
     130                 : 1941970000 :             tsz = JL_ARRAY_ALIGN(tsz, JL_SMALL_BYTE_ALIGNMENT);
     131                 : 3765220000 :         size_t doffs = tsz;
     132                 : 3765220000 :         tsz += tot;
     133                 :            :         // jl_array_t is large enough that objects will always be aligned 16
     134                 : 3765220000 :         a = (jl_array_t*)jl_gc_alloc(ct->ptls, tsz, atype);
     135         [ #  + ]: 3765230000 :         assert(((size_t)a & 15) == 0);
     136                 :            :         // No allocation or safepoint allowed after this
     137                 : 3765230000 :         a->flags.how = 0;
     138                 : 3765230000 :         data = (char*)a + doffs;
     139                 :            :     }
     140                 :            :     else {
     141                 :     156694 :         data = jl_gc_managed_malloc(tot);
     142                 :            :         // Allocate the Array **after** allocating the data
     143                 :            :         // to make sure the array is still young
     144                 :     156713 :         a = (jl_array_t*)jl_gc_alloc(ct->ptls, tsz, atype);
     145                 :            :         // No allocation or safepoint allowed after this
     146                 :     156713 :         a->flags.how = 2;
     147                 :     156713 :         jl_gc_track_malloced_array(ct->ptls, a);
     148                 :            :     }
     149                 : 3765390000 :     a->flags.pooled = tsz <= GC_MAX_SZCLASS;
     150                 :            : 
     151         [ +  + ]: 3765390000 :     if (zeroinit)
     152                 : 1728270000 :         memset(data, 0, tot);
     153                 : 3765390000 :     a->data = data;
     154         [ +  + ]: 3765390000 :     if (JL_ARRAY_IMPL_NUL && elsz == 1)
     155                 :  216855000 :         ((char*)data)[tot - 1] = '\0';
     156                 : 3765390000 :     a->length = nel;
     157                 : 3765390000 :     a->flags.ndims = ndims;
     158                 : 3765390000 :     a->flags.ptrarray = !isunboxed;
     159                 : 3765390000 :     a->flags.hasptr = hasptr;
     160                 : 3765390000 :     a->elsize = elsz;
     161                 : 3765390000 :     a->flags.isshared = 0;
     162                 : 3765390000 :     a->flags.isaligned = 1;
     163                 : 3765390000 :     a->offset = 0;
     164         [ +  + ]: 3765390000 :     if (ndims == 1) {
     165                 : 3764850000 :         a->nrows = nel;
     166                 : 3764850000 :         a->maxsize = nel;
     167                 :            :     }
     168         [ -  + ]:     536335 :     else if (a->flags.ndims != ndims) {
     169                 :          0 :         jl_exceptionf(jl_argumenterror_type, "invalid Array dimensions");
     170                 :            :     }
     171                 :            :     else {
     172                 :     536335 :         size_t *adims = &a->nrows;
     173         [ +  + ]:    1628240 :         for (i = 0; i < ndims; i++)
     174                 :    1091900 :             adims[i] = dims[i];
     175                 :            :     }
     176                 :            : 
     177                 : 3765390000 :     return a;
     178                 :            : }
     179                 :            : 
     180                 : 3606050000 : static inline jl_array_t *_new_array(jl_value_t *atype, uint32_t ndims, size_t *dims)
     181                 :            : {
     182                 : 3606050000 :     jl_value_t *eltype = jl_tparam0(atype);
     183                 : 3606050000 :     size_t elsz = 0, al = 0;
     184         [ +  + ]: 3606050000 :     if (!jl_is_kind(jl_typeof(eltype)))
     185                 :          1 :         jl_type_error_rt("Array", "element type", (jl_value_t*)jl_type_type, eltype);
     186                 : 3606050000 :     int isunboxed = jl_islayout_inline(eltype, &elsz, &al);
     187                 : 3606050000 :     int isunion = jl_is_uniontype(eltype);
     188   [ +  +  +  +  : 3606050000 :     int hasptr = isunboxed && (jl_is_datatype(eltype) && ((jl_datatype_t*)eltype)->layout->npointers > 0);
                   +  + ]
     189         [ +  + ]: 3606050000 :     if (!isunboxed) {
     190                 : 1524620000 :         elsz = sizeof(void*);
     191                 : 1524620000 :         al = elsz;
     192                 :            :     }
     193                 :            :     else {
     194                 : 2081420000 :         elsz = LLT_ALIGN(elsz, al);
     195                 :            :     }
     196   [ +  +  +  +  : 3606050000 :     int zi = !isunboxed || hasptr || isunion || (jl_is_datatype(eltype) && ((jl_datatype_t*)eltype)->zeroinit);
          +  +  +  -  +  
                      + ]
     197                 :            : 
     198                 : 3606050000 :     return _new_array_(atype, ndims, dims, isunboxed, hasptr, isunion, zi, elsz);
     199                 :            : }
     200                 :            : 
     201                 :   51267100 : jl_array_t *jl_new_array_for_deserialization(jl_value_t *atype, uint32_t ndims, size_t *dims,
     202                 :            :                                              int isunboxed, int hasptr, int isunion, int elsz)
     203                 :            : {
     204                 :   51267100 :     return _new_array_(atype, ndims, dims, isunboxed, hasptr, isunion, 0, (size_t)elsz);
     205                 :            : }
     206                 :            : 
     207                 :            : #ifndef JL_NDEBUG
     208                 :      22124 : static inline int is_ntuple_long(jl_value_t *v)
     209                 :            : {
     210         [ -  + ]:      22124 :     if (!jl_is_tuple(v))
     211                 :          0 :         return 0;
     212                 :      22124 :     jl_value_t *tt = jl_typeof(v);
     213                 :      22124 :     size_t i, nfields = jl_nparams(tt);
     214         [ +  + ]:      73063 :     for (i = 0; i < nfields; i++) {
     215         [ -  + ]:      50939 :         if (jl_tparam(tt, i) != (jl_value_t*)jl_long_type) {
     216                 :          0 :             return 0;
     217                 :            :         }
     218                 :            :     }
     219                 :      22124 :     return 1;
     220                 :            : }
     221                 :            : #endif
     222                 :            : 
     223                 :      11711 : JL_DLLEXPORT jl_array_t *jl_reshape_array(jl_value_t *atype, jl_array_t *data,
     224                 :            :                                           jl_value_t *_dims)
     225                 :            : {
     226                 :      11711 :     jl_task_t *ct = jl_current_task;
     227         [ -  + ]:      11711 :     assert(jl_types_equal(jl_tparam0(jl_typeof(data)), jl_tparam0(atype)));
     228                 :            : 
     229                 :      11711 :     size_t ndims = jl_nfields(_dims);
     230         [ -  + ]:      11711 :     assert(is_ntuple_long(_dims));
     231                 :      11711 :     size_t *dims = (size_t*)_dims;
     232                 :      11711 :     int ndimwords = jl_array_ndimwords(ndims);
     233                 :      11711 :     int tsz = sizeof(jl_array_t) + ndimwords * sizeof(size_t) + sizeof(void*);
     234                 :      11711 :     jl_array_t *a = (jl_array_t*)jl_gc_alloc(ct->ptls, tsz, atype);
     235                 :            :     // No allocation or safepoint allowed after this
     236                 :            :     // copy data (except dims) from the old object
     237                 :      11711 :     a->flags.pooled = tsz <= GC_MAX_SZCLASS;
     238                 :      11711 :     a->flags.ndims = ndims;
     239                 :      11711 :     a->offset = 0;
     240                 :      11711 :     a->data = NULL;
     241                 :      11711 :     a->flags.isaligned = data->flags.isaligned;
     242                 :      11711 :     a->elsize = data->elsize;
     243                 :      11711 :     a->flags.ptrarray = data->flags.ptrarray;
     244                 :      11711 :     a->flags.hasptr = data->flags.hasptr;
     245                 :            : 
     246                 :            :     // if data is itself a shared wrapper,
     247                 :            :     // owner should point back to the original array
     248                 :      11711 :     jl_array_t *owner = (jl_array_t*)jl_array_owner(data);
     249                 :      11711 :     jl_array_data_owner(a) = (jl_value_t*)owner;
     250                 :            : 
     251                 :      11711 :     a->flags.how = 3;
     252                 :      11711 :     a->data = data->data;
     253                 :      11711 :     a->flags.isshared = 1;
     254                 :      11711 :     data->flags.isshared = 1;
     255                 :            : 
     256         [ +  + ]:      11711 :     if (ndims == 1) {
     257                 :       2893 :         size_t l = dims[0];
     258                 :       2893 :         a->length = l;
     259                 :       2893 :         a->nrows = l;
     260                 :       2893 :         a->maxsize = l;
     261                 :            :     }
     262         [ -  + ]:       8818 :     else if (a->flags.ndims != ndims) {
     263                 :          0 :         jl_exceptionf(jl_argumenterror_type, "invalid Array dimensions");
     264                 :            :     }
     265                 :            :     else {
     266                 :       8818 :         size_t *adims = &a->nrows;
     267                 :       8818 :         size_t l = 1;
     268                 :            :         wideint_t prod;
     269         [ +  + ]:      27016 :         for (size_t i = 0; i < ndims; i++) {
     270                 :      18198 :             adims[i] = dims[i];
     271                 :      18198 :             prod = (wideint_t)l * (wideint_t)adims[i];
     272         [ -  + ]:      18198 :             if (prod > (wideint_t) MAXINTVAL)
     273                 :          0 :                 jl_exceptionf(jl_argumenterror_type, "invalid Array dimensions");
     274                 :      18198 :             l = prod;
     275                 :            :         }
     276                 :       8818 :         a->length = l;
     277                 :            :     }
     278                 :            : 
     279                 :      11711 :     return a;
     280                 :            : }
     281                 :            : 
     282                 :    6608970 : JL_DLLEXPORT jl_array_t *jl_string_to_array(jl_value_t *str)
     283                 :            : {
     284                 :    6608970 :     jl_task_t *ct = jl_current_task;
     285                 :            :     jl_array_t *a;
     286                 :            : 
     287                 :    6608970 :     int ndimwords = jl_array_ndimwords(1);
     288                 :    6608970 :     int tsz = sizeof(jl_array_t) + ndimwords*sizeof(size_t) + sizeof(void*);
     289                 :    6608970 :     a = (jl_array_t*)jl_gc_alloc(ct->ptls, tsz, jl_array_uint8_type);
     290                 :    6608970 :     a->flags.pooled = tsz <= GC_MAX_SZCLASS;
     291                 :    6608970 :     a->flags.ndims = 1;
     292                 :    6608970 :     a->offset = 0;
     293                 :    6608970 :     a->data = jl_string_data(str);
     294                 :    6608970 :     a->flags.isaligned = 0;
     295                 :    6608970 :     a->elsize = 1;
     296                 :    6608970 :     a->flags.ptrarray = 0;
     297                 :    6608970 :     a->flags.hasptr = 0;
     298                 :    6608970 :     jl_array_data_owner(a) = str;
     299                 :    6608970 :     a->flags.how = 3;
     300                 :    6608970 :     a->flags.isshared = 1;
     301                 :    6608970 :     size_t l = jl_string_len(str);
     302                 :    6608970 :     a->length = l;
     303                 :    6608970 :     a->nrows = a->maxsize = l;
     304                 :    6608970 :     return a;
     305                 :            : }
     306                 :            : 
     307                 :            : // own_buffer != 0 iff GC should call free() on this pointer eventually
     308                 :    2037110 : JL_DLLEXPORT jl_array_t *jl_ptr_to_array_1d(jl_value_t *atype, void *data,
     309                 :            :                                             size_t nel, int own_buffer)
     310                 :            : {
     311                 :    2037110 :     jl_task_t *ct = jl_current_task;
     312                 :            :     jl_array_t *a;
     313                 :    2037110 :     jl_value_t *eltype = jl_tparam0(atype);
     314                 :            : 
     315                 :    2037110 :     int isunboxed = jl_stored_inline(eltype);
     316   [ +  -  +  + ]:    2037110 :     if (isunboxed && jl_is_uniontype(eltype))
     317                 :          2 :         jl_exceptionf(jl_argumenterror_type,
     318                 :            :                       "unsafe_wrap: unspecified layout for union element type");
     319                 :            :     size_t elsz;
     320                 :            :     unsigned align;
     321         [ +  - ]:    2037110 :     if (isunboxed) {
     322                 :    2037110 :         elsz = jl_datatype_size(eltype);
     323                 :    2037110 :         align = jl_datatype_align(eltype);
     324                 :            :     }
     325                 :            :     else {
     326                 :          0 :         align = elsz = sizeof(void*);
     327                 :            :     }
     328         [ +  + ]:    2037110 :     if (((uintptr_t)data) & ((align > JL_HEAP_ALIGNMENT ? JL_HEAP_ALIGNMENT : align) - 1))
     329                 :          1 :         jl_exceptionf(jl_argumenterror_type,
     330                 :            :                       "unsafe_wrap: pointer %p is not properly aligned to %u bytes", data, align);
     331                 :            : 
     332                 :    2037110 :     int ndimwords = jl_array_ndimwords(1);
     333                 :    2037110 :     int tsz = sizeof(jl_array_t) + ndimwords*sizeof(size_t);
     334                 :    2037110 :     a = (jl_array_t*)jl_gc_alloc(ct->ptls, tsz, atype);
     335                 :            :     // No allocation or safepoint allowed after this
     336                 :    2037110 :     a->flags.pooled = tsz <= GC_MAX_SZCLASS;
     337                 :    2037110 :     a->data = data;
     338                 :    2037110 :     a->length = nel;
     339                 :    2037110 :     a->elsize = LLT_ALIGN(elsz, align);
     340                 :    2037110 :     a->flags.ptrarray = !isunboxed;
     341   [ +  -  +  -  :    2037110 :     a->flags.hasptr = isunboxed && (jl_is_datatype(eltype) && ((jl_datatype_t*)eltype)->layout->npointers > 0);
                   -  + ]
     342                 :    2037110 :     a->flags.ndims = 1;
     343                 :    2037110 :     a->flags.isshared = 1;
     344                 :    2037110 :     a->flags.isaligned = 0;  // TODO: allow passing memalign'd buffers
     345         [ +  + ]:    2037110 :     if (own_buffer) {
     346                 :    2032370 :         a->flags.how = 2;
     347                 :    2032370 :         jl_gc_track_malloced_array(ct->ptls, a);
     348         [ +  - ]:    2032370 :         jl_gc_count_allocd(nel*elsz + (elsz == 1 ? 1 : 0));
     349                 :            :     }
     350                 :            :     else {
     351                 :       4741 :         a->flags.how = 0;
     352                 :            :     }
     353                 :            : 
     354                 :    2037110 :     a->nrows = nel;
     355                 :    2037110 :     a->maxsize = nel;
     356                 :    2037110 :     a->offset = 0;
     357                 :    2037110 :     return a;
     358                 :            : }
     359                 :            : 
     360                 :       4077 : JL_DLLEXPORT jl_array_t *jl_ptr_to_array(jl_value_t *atype, void *data,
     361                 :            :                                          jl_value_t *_dims, int own_buffer)
     362                 :            : {
     363                 :       4077 :     jl_task_t *ct = jl_current_task;
     364                 :       4077 :     size_t nel = 1;
     365                 :            :     jl_array_t *a;
     366                 :       4077 :     size_t ndims = jl_nfields(_dims);
     367                 :            :     wideint_t prod;
     368         [ -  + ]:       4077 :     assert(is_ntuple_long(_dims));
     369                 :       4077 :     size_t *dims = (size_t*)_dims;
     370         [ +  + ]:       8419 :     for (size_t i = 0; i < ndims; i++) {
     371                 :       4342 :         prod = (wideint_t)nel * (wideint_t)dims[i];
     372         [ -  + ]:       4342 :         if (prod > (wideint_t) MAXINTVAL)
     373                 :          0 :             jl_exceptionf(jl_argumenterror_type, "invalid Array dimensions");
     374                 :       4342 :         nel = prod;
     375                 :            :     }
     376         [ +  + ]:       4077 :     if (__unlikely(ndims == 1))
     377                 :       3913 :         return jl_ptr_to_array_1d(atype, data, nel, own_buffer);
     378                 :        164 :     jl_value_t *eltype = jl_tparam0(atype);
     379                 :            : 
     380                 :        164 :     int isunboxed = jl_stored_inline(eltype);
     381   [ +  -  -  + ]:        164 :     if (isunboxed && jl_is_uniontype(eltype))
     382                 :          0 :         jl_exceptionf(jl_argumenterror_type,
     383                 :            :                       "unsafe_wrap: unspecified layout for union element type");
     384                 :            :     size_t elsz;
     385                 :            :     unsigned align;
     386         [ +  - ]:        164 :     if (isunboxed) {
     387                 :        164 :         elsz = jl_datatype_size(eltype);
     388                 :        164 :         align = jl_datatype_align(eltype);
     389                 :            :     }
     390                 :            :     else {
     391                 :          0 :         align = elsz = sizeof(void*);
     392                 :            :     }
     393         [ +  + ]:        164 :     if (((uintptr_t)data) & ((align > JL_HEAP_ALIGNMENT ? JL_HEAP_ALIGNMENT : align) - 1))
     394                 :          1 :         jl_exceptionf(jl_argumenterror_type,
     395                 :            :                       "unsafe_wrap: pointer %p is not properly aligned to %u bytes", data, align);
     396                 :            : 
     397                 :        163 :     int ndimwords = jl_array_ndimwords(ndims);
     398                 :        163 :     int tsz = sizeof(jl_array_t) + ndimwords*sizeof(size_t);
     399                 :        163 :     a = (jl_array_t*)jl_gc_alloc(ct->ptls, tsz, atype);
     400                 :            :     // No allocation or safepoint allowed after this
     401                 :        163 :     a->flags.pooled = tsz <= GC_MAX_SZCLASS;
     402                 :        163 :     a->data = data;
     403                 :        163 :     a->length = nel;
     404                 :        163 :     a->elsize = LLT_ALIGN(elsz, align);
     405                 :        163 :     a->flags.ptrarray = !isunboxed;
     406   [ +  -  +  -  :        163 :     a->flags.hasptr = isunboxed && (jl_is_datatype(eltype) && ((jl_datatype_t*)eltype)->layout->npointers > 0);
                   -  + ]
     407                 :        163 :     a->flags.ndims = ndims;
     408                 :        163 :     a->offset = 0;
     409                 :        163 :     a->flags.isshared = 1;
     410                 :        163 :     a->flags.isaligned = 0;
     411         [ -  + ]:        163 :     if (own_buffer) {
     412                 :          0 :         a->flags.how = 2;
     413                 :          0 :         jl_gc_track_malloced_array(ct->ptls, a);
     414         [ #  # ]:          0 :         jl_gc_count_allocd(nel*elsz + (elsz == 1 ? 1 : 0));
     415                 :            :     }
     416                 :            :     else {
     417                 :        163 :         a->flags.how = 0;
     418                 :            :     }
     419                 :            : 
     420         [ -  + ]:        163 :     assert(ndims != 1); // handled above
     421         [ -  + ]:        163 :     if (a->flags.ndims != ndims)
     422                 :          0 :         jl_exceptionf(jl_argumenterror_type, "invalid Array dimensions");
     423                 :        163 :     memcpy(&a->nrows, dims, ndims * sizeof(size_t));
     424                 :        163 :     return a;
     425                 :            : }
     426                 :            : 
     427                 :       6336 : JL_DLLEXPORT jl_array_t *jl_new_array(jl_value_t *atype, jl_value_t *_dims)
     428                 :            : {
     429                 :       6336 :     size_t ndims = jl_nfields(_dims);
     430         [ -  + ]:       6336 :     assert(is_ntuple_long(_dims));
     431                 :       6336 :     return _new_array(atype, ndims, (size_t*)_dims);
     432                 :            : }
     433                 :            : 
     434                 : 3605530000 : JL_DLLEXPORT jl_array_t *jl_alloc_array_1d(jl_value_t *atype, size_t nr)
     435                 :            : {
     436                 : 3605530000 :     return _new_array(atype, 1, &nr);
     437                 :            : }
     438                 :            : 
     439                 :     502427 : JL_DLLEXPORT jl_array_t *jl_alloc_array_2d(jl_value_t *atype, size_t nr,
     440                 :            :                                            size_t nc)
     441                 :            : {
     442                 :     502427 :     size_t d[2] = {nr, nc};
     443                 :     502427 :     return _new_array(atype, 2, &d[0]);
     444                 :            : }
     445                 :            : 
     446                 :       6382 : JL_DLLEXPORT jl_array_t *jl_alloc_array_3d(jl_value_t *atype, size_t nr,
     447                 :            :                                            size_t nc, size_t z)
     448                 :            : {
     449                 :       6382 :     size_t d[3] = {nr, nc, z};
     450                 :       6382 :     return _new_array(atype, 3, &d[0]);
     451                 :            : }
     452                 :            : 
     453                 :     173285 : JL_DLLEXPORT jl_array_t *jl_pchar_to_array(const char *str, size_t len)
     454                 :            : {
     455                 :     173285 :     jl_array_t *a = jl_alloc_array_1d(jl_array_uint8_type, len);
     456                 :     173285 :     memcpy(a->data, str, len);
     457                 :     173285 :     return a;
     458                 :            : }
     459                 :            : 
     460                 :    6269360 : JL_DLLEXPORT jl_value_t *jl_array_to_string(jl_array_t *a)
     461                 :            : {
     462                 :    6269360 :     size_t len = jl_array_len(a);
     463         [ +  + ]:    6269360 :     if (len == 0) {
     464                 :            :         // this may seem like purely an optimization (which it also is), but it
     465                 :            :         // also ensures that calling `String(a)` doesn't corrupt a previous
     466                 :            :         // string also created the same way, where `a = StringVector(_)`.
     467                 :     487015 :         return jl_an_empty_string;
     468                 :            :     }
     469   [ +  +  +  +  :    5782350 :     if (a->flags.how == 3 && a->offset == 0 && a->elsize == 1 &&
                   +  - ]
     470         [ +  - ]:    5583740 :         (jl_array_ndims(a) != 1 ||
     471         [ +  + ]:    5583740 :          ((a->maxsize + sizeof(void*) + 1 <= GC_MAX_SZCLASS) == (len + sizeof(void*) + 1 <= GC_MAX_SZCLASS)))) {
     472                 :    5582680 :         jl_value_t *o = jl_array_data_owner(a);
     473         [ +  - ]:    5582680 :         if (jl_is_string(o)) {
     474                 :    5582680 :             a->flags.isshared = 1;
     475                 :    5582680 :             *(size_t*)o = len;
     476                 :    5582680 :             a->nrows = 0;
     477                 :    5582680 :             a->length = 0;
     478                 :    5582680 :             a->maxsize = 0;
     479                 :    5582680 :             return o;
     480                 :            :         }
     481                 :            :     }
     482                 :     199667 :     a->nrows = 0;
     483                 :     199667 :     a->length = 0;
     484                 :     199667 :     a->maxsize = 0;
     485                 :     199667 :     return jl_pchar_to_string((const char*)jl_array_data(a), len);
     486                 :            : }
     487                 :            : 
     488                 :  146743000 : JL_DLLEXPORT jl_value_t *jl_alloc_string(size_t len)
     489                 :            : {
     490         [ +  + ]:  146743000 :     if (len == 0)
     491                 :    1733270 :         return jl_an_empty_string;
     492                 :  145010000 :     size_t sz = sizeof(size_t) + len + 1; // add space for trailing \nul protector and size
     493         [ +  + ]:  145010000 :     if (sz < len) // overflow
     494                 :          1 :         jl_throw(jl_memory_exception);
     495                 :  145010000 :     jl_task_t *ct = jl_current_task;
     496                 :            :     jl_value_t *s;
     497                 :  145010000 :     jl_ptls_t ptls = ct->ptls;
     498                 :  145010000 :     const size_t allocsz = sz + sizeof(jl_taggedvalue_t);
     499         [ +  + ]:  145010000 :     if (sz <= GC_MAX_SZCLASS) {
     500                 :  144692000 :         int pool_id = jl_gc_szclass_align8(allocsz);
     501                 :  144692000 :         jl_gc_pool_t *p = &ptls->heap.norm_pools[pool_id];
     502                 :  144692000 :         int osize = jl_gc_sizeclasses[pool_id];
     503                 :            :         // We call `jl_gc_pool_alloc_noinline` instead of `jl_gc_pool_alloc` to avoid double-counting in
     504                 :            :         // the Allocations Profiler. (See https://github.com/JuliaLang/julia/pull/43868 for more details.)
     505                 :  144692000 :         s = jl_gc_pool_alloc_noinline(ptls, (char*)p - (char*)ptls, osize);
     506                 :            :     }
     507                 :            :     else {
     508         [ -  + ]:     317823 :         if (allocsz < sz) // overflow in adding offs, size was "negative"
     509                 :          0 :             jl_throw(jl_memory_exception);
     510                 :     317823 :         s = jl_gc_big_alloc_noinline(ptls, allocsz);
     511                 :            :     }
     512                 :  145010000 :     jl_set_typeof(s, jl_string_type);
     513                 :  145010000 :     maybe_record_alloc_to_profile(s, len, jl_string_type);
     514                 :  145010000 :     *(size_t*)s = len;
     515                 :  145010000 :     jl_string_data(s)[len] = 0;
     516                 :  145010000 :     return s;
     517                 :            : }
     518                 :            : 
     519                 :    4692870 : JL_DLLEXPORT jl_value_t *jl_pchar_to_string(const char *str, size_t len)
     520                 :            : {
     521                 :    4692870 :     jl_value_t *s = jl_alloc_string(len);
     522         [ +  + ]:    4692870 :     if (len > 0)
     523                 :    4671330 :         memcpy(jl_string_data(s), str, len);
     524                 :    4692870 :     return s;
     525                 :            : }
     526                 :            : 
     527                 :    3660660 : JL_DLLEXPORT jl_value_t *jl_cstr_to_string(const char *str)
     528                 :            : {
     529                 :    3660660 :     return jl_pchar_to_string(str, strlen(str));
     530                 :            : }
     531                 :            : 
     532                 :  239124000 : JL_DLLEXPORT jl_array_t *jl_alloc_vec_any(size_t n)
     533                 :            : {
     534                 :  239124000 :     return jl_alloc_array_1d(jl_array_any_type, n);
     535                 :            : }
     536                 :            : 
     537                 :         51 : JL_DLLEXPORT jl_value_t *jl_apply_array_type(jl_value_t *type, size_t dim)
     538                 :            : {
     539                 :         51 :     jl_value_t *boxed_dim = jl_box_long(dim);
     540                 :         51 :     JL_GC_PUSH1(&boxed_dim);
     541                 :         51 :     jl_value_t *ret = jl_apply_type2((jl_value_t*)jl_array_type, type, boxed_dim);
     542                 :         51 :     JL_GC_POP();
     543                 :         51 :     return ret;
     544                 :            : }
     545                 :            : 
     546                 :            : // array primitives -----------------------------------------------------------
     547                 :            : 
     548                 :   10464300 : JL_DLLEXPORT jl_value_t *jl_ptrarrayref(jl_array_t *a JL_PROPAGATES_ROOT, size_t i) JL_NOTSAFEPOINT
     549                 :            : {
     550         [ -  + ]:   10464300 :     assert(i < jl_array_len(a));
     551         [ -  + ]:   10464300 :     assert(a->flags.ptrarray);
     552                 :   10464300 :     jl_value_t *elt = jl_atomic_load_relaxed(((_Atomic(jl_value_t*)*)a->data) + i);
     553         [ -  + ]:   10464300 :     if (elt == NULL)
     554                 :          0 :         jl_throw(jl_undefref_exception);
     555                 :   10464300 :     return elt;
     556                 :            : }
     557                 :            : 
     558                 :            : 
     559                 :   67992400 : JL_DLLEXPORT jl_value_t *jl_arrayref(jl_array_t *a, size_t i)
     560                 :            : {
     561         [ +  + ]:   67992400 :     if (a->flags.ptrarray)
     562                 :   10464000 :         return jl_ptrarrayref(a, i);
     563         [ -  + ]:   57528300 :     assert(i < jl_array_len(a));
     564                 :   57528300 :     jl_value_t *eltype = (jl_value_t*)jl_tparam0(jl_typeof(a));
     565         [ +  + ]:   57528300 :     if (jl_is_uniontype(eltype)) {
     566                 :            :         // isbits union selector bytes are always stored directly after the last array element
     567                 :    7362450 :         uint8_t sel = jl_array_typetagdata(a)[i];
     568                 :    7362450 :         eltype = jl_nth_union_component(eltype, sel);
     569         [ +  + ]:    7362450 :         if (jl_is_datatype_singleton((jl_datatype_t*)eltype))
     570                 :    3145800 :             return ((jl_datatype_t*)eltype)->instance;
     571                 :            :     }
     572                 :   54382500 :     jl_value_t *r = undefref_check((jl_datatype_t*)eltype, jl_new_bits(eltype, &((char*)a->data)[i * a->elsize]));
     573         [ -  + ]:   54382500 :     if (__unlikely(r == NULL))
     574                 :          0 :         jl_throw(jl_undefref_exception);
     575                 :   54382500 :     return r;
     576                 :            : }
     577                 :            : 
     578                 :    4327690 : JL_DLLEXPORT int jl_array_isassigned(jl_array_t *a, size_t i)
     579                 :            : {
     580         [ +  + ]:    4327690 :     if (a->flags.ptrarray) {
     581                 :    4176800 :         return jl_atomic_load_relaxed(((_Atomic(jl_value_t*)*)jl_array_data(a)) + i) != NULL;
     582                 :            :     }
     583         [ +  + ]:     150884 :     else if (a->flags.hasptr) {
     584                 :      42053 :          jl_datatype_t *eltype = (jl_datatype_t*)jl_tparam0(jl_typeof(a));
     585         [ -  + ]:      42053 :          assert(eltype->layout->first_ptr >= 0);
     586                 :      42053 :          jl_value_t **elem = (jl_value_t**)((char*)a->data + i * a->elsize);
     587                 :      42053 :          return elem[eltype->layout->first_ptr] != NULL;
     588                 :            :     }
     589                 :     108831 :     return 1;
     590                 :            : }
     591                 :            : 
     592                 :   11945800 : JL_DLLEXPORT void jl_arrayset(jl_array_t *a JL_ROOTING_ARGUMENT, jl_value_t *rhs JL_ROOTED_ARGUMENT JL_MAYBE_UNROOTED, size_t i)
     593                 :            : {
     594         [ -  + ]:   11945800 :     assert(i < jl_array_len(a));
     595                 :   11945800 :     jl_value_t *eltype = jl_tparam0(jl_typeof(a));
     596         [ +  + ]:   11945800 :     if (eltype != (jl_value_t*)jl_any_type) {
     597                 :   11941800 :         JL_GC_PUSH1(&rhs);
     598         [ +  + ]:   11941800 :         if (!jl_isa(rhs, eltype))
     599                 :          7 :             jl_type_error("arrayset", eltype, rhs);
     600                 :   11941800 :         JL_GC_POP();
     601                 :            :     }
     602         [ +  + ]:   11945800 :     if (!a->flags.ptrarray) {
     603                 :            :         int hasptr;
     604         [ +  + ]:   11353900 :         if (jl_is_uniontype(eltype)) {
     605                 :    3162910 :             uint8_t *psel = &((uint8_t*)jl_array_typetagdata(a))[i];
     606                 :    3162910 :             unsigned nth = 0;
     607         [ -  + ]:    3162910 :             if (!jl_find_union_component(eltype, jl_typeof(rhs), &nth))
     608                 :          0 :                 assert(0 && "invalid arrayset to isbits union");
     609                 :    3162910 :             *psel = nth;
     610         [ +  + ]:    3162910 :             if (jl_is_datatype_singleton((jl_datatype_t*)jl_typeof(rhs)))
     611                 :         25 :                 return;
     612                 :    3162890 :             hasptr = 0;
     613                 :            :         }
     614                 :            :         else {
     615                 :    8191000 :             hasptr = a->flags.hasptr;
     616                 :            :         }
     617                 :   11353900 :         arrayassign_safe(hasptr, jl_array_owner(a), &((char*)a->data)[i * a->elsize], rhs, a->elsize);
     618                 :            :     }
     619                 :            :     else {
     620                 :     591862 :         jl_atomic_store_release(((_Atomic(jl_value_t*)*)a->data) + i, rhs);
     621                 :     591862 :         jl_gc_wb(jl_array_owner(a), rhs);
     622                 :            :     }
     623                 :            : }
     624                 :            : 
     625                 :          0 : JL_DLLEXPORT void jl_arrayunset(jl_array_t *a, size_t i)
     626                 :            : {
     627         [ #  # ]:          0 :     if (i >= jl_array_len(a))
     628                 :          0 :         jl_bounds_error_int((jl_value_t*)a, i + 1);
     629         [ #  # ]:          0 :     if (a->flags.ptrarray)
     630                 :          0 :         jl_atomic_store_release(((_Atomic(jl_value_t*)*)a->data) + i, NULL);
     631         [ #  # ]:          0 :     else if (a->flags.hasptr) {
     632                 :          0 :         size_t elsize = a->elsize;
     633   [ #  #  #  # ]:          0 :         jl_assume(elsize >= sizeof(void*) && elsize % sizeof(void*) == 0);
     634                 :          0 :         memset((char*)a->data + elsize * i, 0, elsize);
     635                 :            :     }
     636                 :          0 : }
     637                 :            : 
     638                 :            : // at this size and bigger, allocate resized array data with malloc directly
     639                 :            : // instead of managing them separately as gc objects
     640                 :            : #define MALLOC_THRESH 1048576
     641                 :            : 
     642                 :            : // Resize the buffer to a max size of `newlen`
     643                 :            : // The buffer can either be newly allocated or realloc'd, the return
     644                 :            : // value is 1 if a new buffer is allocated and 0 if it is realloc'd.
     645                 :            : // the caller needs to take care of moving the data from the old buffer
     646                 :            : // to the new one if necessary.
     647                 :            : // When this function returns, the `->data` pointer always points to
     648                 :            : // the **beginning** of the new buffer.
     649                 :  792058000 : static int NOINLINE array_resize_buffer(jl_array_t *a, size_t newlen)
     650                 :            : {
     651                 :  792058000 :     jl_task_t *ct = jl_current_task;
     652   [ +  +  -  + ]:  792058000 :     assert(!a->flags.isshared || a->flags.how == 3);
     653                 :  792058000 :     size_t elsz = a->elsize;
     654                 :  792058000 :     size_t nbytes = newlen * elsz;
     655                 :  792058000 :     size_t oldnbytes = a->maxsize * elsz;
     656                 :  792058000 :     size_t oldoffsnb = a->offset * elsz;
     657                 :  792058000 :     size_t oldlen = a->nrows;
     658   [ +  +  +  + ]:  792058000 :     int isbitsunion = jl_array_isbitsunion(a);
     659         [ -  + ]:  792058000 :     assert(nbytes >= oldnbytes);
     660   [ +  +  +  + ]:  792058000 :     if (elsz == 1 && !isbitsunion) {
     661                 :   10663000 :         nbytes++;
     662                 :   10663000 :         oldnbytes++;
     663                 :            :     }
     664         [ +  + ]:  792058000 :     if (isbitsunion) {
     665                 :    4705560 :         nbytes += newlen;
     666                 :    4705560 :         oldnbytes += a->maxsize;
     667                 :            :     }
     668                 :  792058000 :     int newbuf = 0;
     669         [ +  + ]:  792058000 :     if (a->flags.how == 2) {
     670                 :            :         // already malloc'd - use realloc
     671                 :      22146 :         char *olddata = (char*)a->data - oldoffsnb;
     672                 :      22146 :         a->data = jl_gc_managed_realloc(olddata, nbytes, oldnbytes,
     673                 :      22146 :                                         a->flags.isaligned, (jl_value_t*)a);
     674                 :            :     }
     675   [ +  +  +  +  :  792036000 :     else if (a->flags.how == 3 && jl_is_string(jl_array_data_owner(a)) && !isbitsunion) {
                   +  - ]
     676                 :            :         // if data is in a String, keep it that way
     677                 :            :         jl_value_t *s;
     678         [ +  + ]:    2915960 :         if (a->flags.isshared) {
     679                 :    1703970 :             s = jl_alloc_string(nbytes - (elsz == 1));
     680                 :    1703970 :             newbuf = 1;
     681                 :            :         }
     682                 :            :         else {
     683                 :    1211980 :             s = jl_gc_realloc_string(jl_array_data_owner(a), nbytes - (elsz == 1));
     684                 :            :         }
     685                 :    2915960 :         jl_array_data_owner(a) = s;
     686                 :    2915960 :         jl_gc_wb(a, s);
     687                 :    2915960 :         a->data = jl_string_data(s);
     688                 :            :     }
     689                 :            :     else {
     690                 :  789120000 :         newbuf = 1;
     691         [ +  + ]:  789120000 :         if (nbytes >= MALLOC_THRESH) {
     692                 :        189 :             a->data = jl_gc_managed_malloc(nbytes);
     693                 :        189 :             jl_gc_track_malloced_array(ct->ptls, a);
     694                 :        189 :             a->flags.how = 2;
     695                 :        189 :             a->flags.isaligned = 1;
     696                 :            :         }
     697                 :            :         else {
     698                 :  789120000 :             a->data = jl_gc_alloc_buf(ct->ptls, nbytes);
     699                 :  789120000 :             a->flags.how = 1;
     700                 :  789120000 :             jl_gc_wb_buf(a, a->data, nbytes);
     701                 :            :         }
     702                 :            :     }
     703   [ +  +  +  + ]:  792058000 :     if (JL_ARRAY_IMPL_NUL && elsz == 1 && !isbitsunion)
     704                 :   10663000 :         memset((char*)a->data + oldnbytes - 1, 0, nbytes - oldnbytes + 1);
     705                 :            :     (void)oldlen;
     706         [ -  + ]:  792058000 :     assert(oldlen == a->nrows &&
     707                 :            :            "Race condition detected: recursive resizing on the same array.");
     708                 :  792058000 :     a->flags.isshared = 0;
     709                 :  792058000 :     a->maxsize = newlen;
     710                 :  792058000 :     return newbuf;
     711                 :            : }
     712                 :            : 
     713                 :    1300250 : static void NOINLINE array_try_unshare(jl_array_t *a)
     714                 :            : {
     715         [ +  - ]:    1300250 :     if (a->flags.isshared) {
     716         [ +  + ]:    1300250 :         if (a->flags.how != 3)
     717                 :         12 :             jl_error("cannot resize array with shared data");
     718                 :            :         // allow resizing when data is shared with a String
     719         [ +  + ]:    1300240 :         if (jl_is_string(jl_array_data_owner(a)))
     720                 :    1300220 :             return;
     721         [ -  + ]:         16 :         assert(a->offset == 0);
     722                 :         16 :         size_t len = a->maxsize;
     723                 :         16 :         size_t nbytes = len * a->elsize;
     724   [ +  +  -  + ]:         16 :         if (jl_array_isbitsunion(a)) {
     725                 :          0 :             nbytes += len;
     726                 :            :         }
     727                 :         16 :         char *olddata = (char*)a->data;
     728                 :         16 :         int newbuf = array_resize_buffer(a, len);
     729         [ -  + ]:         16 :         assert(newbuf);
     730                 :            :         (void)newbuf;
     731                 :         16 :         memcpy(a->data, olddata, nbytes);
     732                 :            :     }
     733                 :            : }
     734                 :            : 
     735                 :  792058000 : size_t overallocation(size_t maxsize)
     736                 :            : {
     737         [ +  + ]:  792058000 :     if (maxsize < 8)
     738                 :  758568000 :         return 8;
     739                 :            :     // compute maxsize = maxsize + 4*maxsize^(7/8) + maxsize/8
     740                 :            :     // for small n, we grow faster than O(n)
     741                 :            :     // for large n, we grow at O(n/8)
     742                 :            :     // and as we reach O(memory) for memory>>1MB,
     743                 :            :     // this means we end by adding about 10% of memory each time
     744                 :   33489800 :     int exp2 = sizeof(maxsize) * 8 -
     745                 :            : #ifdef _P64
     746                 :   33489800 :         __builtin_clzll(maxsize);
     747                 :            : #else
     748                 :            :         __builtin_clz(maxsize);
     749                 :            : #endif
     750                 :   33489800 :     maxsize += ((size_t)1 << (exp2 * 7 / 8)) * 4 + maxsize / 8;
     751                 :   33489800 :     return maxsize;
     752                 :            : }
     753                 :            : 
     754                 :    2727420 : STATIC_INLINE void jl_array_grow_at_beg(jl_array_t *a, size_t idx, size_t inc,
     755                 :            :                                         size_t n)
     756                 :            : {
     757                 :            :     // designed to handle the case of growing and shrinking at both ends
     758         [ +  + ]:    2727420 :     if (__unlikely(a->flags.isshared)) {
     759         [ +  + ]:         23 :         if (a->flags.how != 3)
     760                 :          6 :             jl_error("cannot resize array with shared data");
     761         [ +  + ]:         17 :         if (inc == 0) {
     762                 :            :             // If inc > 0, it will always trigger the slow path and unshare the
     763                 :            :             // buffer
     764                 :          2 :             array_try_unshare(a);
     765                 :          2 :             return;
     766                 :            :         }
     767                 :            :     }
     768                 :    2727410 :     size_t newnrows = n + inc;
     769                 :    2727410 :     size_t elsz = a->elsize;
     770                 :    2727410 :     size_t nbinc = inc * elsz;
     771                 :    2727410 :     char *data = (char*)a->data;
     772                 :            :     char *newdata;
     773                 :            :     char *typetagdata;
     774                 :    2727410 :     char *newtypetagdata = NULL;
     775   [ +  +  +  + ]:    2727410 :     int isbitsunion = jl_array_isbitsunion(a);
     776         [ +  + ]:    2727410 :     if (isbitsunion) typetagdata = jl_array_typetagdata(a);
     777         [ +  + ]:    2727410 :     if (a->offset >= inc) {
     778                 :            :         // already have enough space in a->offset
     779                 :    1428400 :         newdata = data - nbinc;
     780                 :    1428400 :         a->offset -= inc;
     781         [ +  + ]:    1428400 :         if (isbitsunion) newtypetagdata = typetagdata - inc;
     782         [ +  + ]:    1428400 :         if (idx > 0) {
     783                 :            :             // inserting new elements after 1st element
     784                 :     122790 :             memmove_safe(a->flags.hasptr, newdata, data, idx * elsz);
     785         [ -  + ]:     122790 :             if (isbitsunion) {
     786                 :          0 :                 memmove(newtypetagdata, typetagdata, idx);
     787                 :          0 :                 memset(newtypetagdata + idx, 0, inc);
     788                 :            :             }
     789                 :            :         }
     790                 :            :     }
     791                 :            :     else {
     792                 :            :         // not enough room for requested growth from existing a->offset
     793                 :    1299010 :         size_t oldoffset = a->offset;
     794                 :    1299010 :         size_t oldoffsnb = oldoffset * elsz;
     795                 :    1299010 :         size_t oldmaxsize = a->maxsize;
     796                 :    1299010 :         size_t nb1 = idx * elsz;
     797         [ +  + ]:    1299010 :         if (inc > (a->maxsize - n) / 2 - (a->maxsize - n) / 20) {
     798                 :            :             // not enough room for requested growth from end of array
     799                 :    1012160 :             size_t newlen = inc * 2;
     800         [ +  + ]:    3717370 :             while (n + 2 * inc > newlen - a->offset)
     801                 :    2705200 :                 newlen *= 2;
     802                 :    1012160 :             size_t newmaxsize = overallocation(a->maxsize);
     803         [ +  + ]:    1012160 :             if (newlen < newmaxsize)
     804                 :     446841 :                 newlen = newmaxsize;
     805                 :    1012160 :             size_t newoffset = (newlen - newnrows) / 2;
     806         [ +  + ]:    1012160 :             if (!array_resize_buffer(a, newlen)) {
     807                 :         73 :                 data = (char*)a->data + oldoffsnb;
     808                 :            :             }
     809                 :    1012160 :             newdata = (char*)a->data + newoffset * elsz;
     810         [ +  + ]:    1012160 :             if (isbitsunion) {
     811                 :         13 :                 typetagdata = data + (oldmaxsize - oldoffset) * elsz + oldoffset;
     812                 :         13 :                 newtypetagdata = newdata + (a->maxsize - newoffset) * elsz + newoffset;
     813                 :         13 :                 memmove(newtypetagdata, typetagdata, idx);
     814                 :         13 :                 memset(newtypetagdata + idx, 0, inc);
     815                 :         13 :                 memmove(newtypetagdata + idx + inc, typetagdata + idx, n - idx);
     816                 :            :             }
     817                 :            :             // We could use memcpy if resizing allocates a new buffer,
     818                 :            :             // hopefully it's not a particularly important optimization.
     819   [ +  +  +  + ]:    1012160 :             if (idx > 0 && newdata < data) {
     820                 :     160537 :                 memmove_safe(a->flags.hasptr, newdata, data, nb1);
     821                 :            :             }
     822                 :    1012160 :             memmove_safe(a->flags.hasptr, newdata + nbinc + nb1, data + nb1, n * elsz - nb1);
     823   [ +  +  +  + ]:    1012160 :             if (idx > 0 && newdata > data) {
     824                 :      85192 :                 memmove_safe(a->flags.hasptr, newdata, data, nb1);
     825                 :            :             }
     826                 :    1012160 :             a->offset = newoffset;
     827                 :            :         }
     828                 :            :         else {
     829                 :            :             // use extra space between a->nrows & a->maxsize
     830                 :     286842 :             a->offset = (a->maxsize - newnrows) / 2;
     831                 :     286842 :             newdata = data - oldoffsnb + a->offset * elsz;
     832         [ +  + ]:     286842 :             if (isbitsunion) newtypetagdata = newdata + (a->maxsize - a->offset) * elsz + a->offset;
     833   [ +  +  -  + ]:     286842 :             if (idx > 0 && newdata < data) {
     834                 :          0 :                 memmove_safe(a->flags.hasptr, newdata, data, nb1);
     835         [ #  # ]:          0 :                 if (isbitsunion) {
     836                 :          0 :                     memmove(newtypetagdata, typetagdata, idx);
     837                 :          0 :                     memset(newtypetagdata + idx, 0, inc);
     838                 :            :                 }
     839                 :            :             }
     840                 :     286842 :             memmove_safe(a->flags.hasptr, newdata + nbinc + nb1, data + nb1, n * elsz - nb1);
     841         [ +  + ]:     286842 :             if (isbitsunion) memmove(newtypetagdata + idx + inc, typetagdata + idx, n - idx);
     842   [ +  +  +  + ]:     286842 :             if (idx > 0 && newdata > data) {
     843                 :      82465 :                 memmove_safe(a->flags.hasptr, newdata, data, nb1);
     844         [ -  + ]:      82465 :                 if (isbitsunion) {
     845                 :          0 :                     memmove(newtypetagdata, typetagdata, idx);
     846                 :          0 :                     memset(newtypetagdata + idx, 0, inc);
     847                 :            :                 }
     848                 :            :             }
     849                 :            :         }
     850                 :            :     }
     851                 :    2727410 :     a->length = newnrows;
     852                 :    2727410 :     a->nrows = newnrows;
     853                 :    2727410 :     a->data = newdata;
     854         [ +  + ]:    2727410 :     if (jl_is_array_zeroinit(a)) {
     855                 :    2338040 :         memset(newdata + idx * elsz, 0, nbinc);
     856                 :            :     }
     857         [ +  + ]:    2727410 :     if (newtypetagdata) {
     858                 :         56 :         memset(newtypetagdata + idx, 0, inc);
     859                 :            :     }
     860                 :            : }
     861                 :            : 
     862                 : 1941310000 : STATIC_INLINE void jl_array_grow_at_end(jl_array_t *a, size_t idx,
     863                 :            :                                         size_t inc, size_t n)
     864                 :            : {
     865                 :            :     // optimized for the case of only growing and shrinking at the end
     866         [ +  + ]: 1941310000 :     if (__unlikely(a->flags.isshared)) {
     867         [ +  + ]:    1703980 :         if (a->flags.how != 3)
     868                 :          6 :             jl_error("cannot resize array with shared data");
     869         [ +  + ]:    1703980 :         if (inc == 0) {
     870                 :            :             // If inc > 0, it will always trigger the slow path and unshare the
     871                 :            :             // buffer
     872                 :          2 :             array_try_unshare(a);
     873                 :          2 :             return;
     874                 :            :         }
     875                 :            :     }
     876                 : 1941310000 :     size_t elsz = a->elsize;
     877                 : 1941310000 :     char *data = (char*)a->data;
     878                 :            :     char *typetagdata;
     879                 :            :     char *newtypetagdata;
     880   [ +  +  +  + ]: 1941310000 :     int isbitsunion = jl_array_isbitsunion(a);
     881         [ +  + ]: 1941310000 :     if (isbitsunion) typetagdata = jl_array_typetagdata(a);
     882                 : 1941310000 :     int has_gap = n > idx;
     883                 : 1941310000 :     size_t reqmaxsize = a->offset + n + inc;
     884         [ +  + ]: 1941310000 :     if (__unlikely(reqmaxsize > a->maxsize)) {
     885                 :  791046000 :         size_t nb1 = idx * elsz;
     886                 :  791046000 :         size_t nbinc = inc * elsz;
     887                 :            :         // grow either by our computed overallocation factor or exactly the requested size,
     888                 :            :         // whichever is larger
     889                 :  791046000 :         size_t newmaxsize = overallocation(a->maxsize);
     890         [ +  + ]:  791046000 :         if (newmaxsize < reqmaxsize)
     891                 :   22624200 :             newmaxsize = reqmaxsize;
     892                 :  791046000 :         size_t oldmaxsize = a->maxsize;
     893                 :  791046000 :         int newbuf = array_resize_buffer(a, newmaxsize);
     894                 :  791046000 :         char *newdata = (char*)a->data + a->offset * elsz;
     895         [ +  + ]:  791046000 :         if (isbitsunion) newtypetagdata = newdata + (a->maxsize - a->offset) * elsz + a->offset;
     896         [ +  + ]:  791046000 :         if (newbuf) {
     897                 :  789812000 :             memcpy(newdata, data, nb1);
     898         [ +  + ]:  789812000 :             if (isbitsunion) {
     899                 :    4705540 :                 memcpy(newtypetagdata, typetagdata, idx);
     900         [ +  + ]:    4705540 :                 if (has_gap) memcpy(newtypetagdata + idx + inc, typetagdata + idx, n - idx);
     901                 :    4705540 :                 memset(newtypetagdata + idx, 0, inc);
     902                 :            :             }
     903         [ +  + ]:  789812000 :             if (has_gap) memcpy(newdata + nb1 + nbinc, data + nb1, n * elsz - nb1);
     904                 :            :         }
     905                 :            :         else {
     906         [ +  + ]:    1234050 :             if (isbitsunion) {
     907                 :          2 :                 typetagdata = newdata + (oldmaxsize - a->offset) * elsz + a->offset;
     908         [ +  + ]:          2 :                 if (has_gap) memmove(newtypetagdata + idx + inc, typetagdata + idx, n - idx);
     909                 :          2 :                 memmove(newtypetagdata, typetagdata, idx);
     910                 :          2 :                 memset(newtypetagdata + idx, 0, inc);
     911                 :            :             }
     912         [ +  + ]:    1234050 :             if (has_gap) memmove_safe(a->flags.hasptr, newdata + nb1 + nbinc, newdata + nb1, n * elsz - nb1);
     913                 :            :         }
     914                 :  791046000 :         a->data = data = newdata;
     915                 :            :     }
     916         [ +  + ]: 1150260000 :     else if (has_gap) {
     917         [ +  + ]:     436295 :         if (isbitsunion) {
     918                 :          3 :             memmove(typetagdata + idx + inc, typetagdata + idx, n - idx);
     919                 :          3 :             memset(typetagdata + idx, 0, inc);
     920                 :            :         }
     921                 :     436295 :         size_t nb1 = idx * elsz;
     922                 :     436295 :         memmove_safe(a->flags.hasptr, data + nb1 + inc * elsz, data + nb1, n * elsz - nb1);
     923                 :            :     }
     924                 :            :     else {
     925                 :            :         // there was enough room for requested growth already in a->maxsize
     926         [ +  + ]: 1149820000 :         if (isbitsunion)
     927                 :    8109940 :             memset(typetagdata + idx, 0, inc);
     928                 :            :     }
     929                 : 1941310000 :     size_t newnrows = n + inc;
     930                 : 1941310000 :     a->length = newnrows;
     931                 : 1941310000 :     a->nrows = newnrows;
     932         [ +  + ]: 1941310000 :     if (jl_is_array_zeroinit(a)) {
     933                 :  670809000 :         memset(data + idx * elsz, 0, inc * elsz);
     934                 :            :     }
     935                 :            : }
     936                 :            : 
     937                 :    1909810 : JL_DLLEXPORT void jl_array_grow_at(jl_array_t *a, ssize_t idx, size_t inc)
     938                 :            : {
     939                 :            :     // No need to explicitly unshare.
     940                 :            :     // Shared arrays are guaranteed to trigger the slow path for growing.
     941                 :    1909810 :     size_t n = jl_array_nrows(a);
     942   [ +  +  +  + ]:    1909810 :     if (idx < 0 || idx > n)
     943                 :          2 :         jl_bounds_error_int((jl_value_t*)a, idx + 1);
     944         [ +  + ]:    1909810 :     if (idx + 1 < n / 2) {
     945                 :     470751 :         jl_array_grow_at_beg(a, idx, inc, n);
     946                 :            :     }
     947                 :            :     else {
     948                 :    1439060 :         jl_array_grow_at_end(a, idx, inc, n);
     949                 :            :     }
     950                 :    1909810 : }
     951                 :            : 
     952                 : 1939870000 : JL_DLLEXPORT void jl_array_grow_end(jl_array_t *a, size_t inc)
     953                 :            : {
     954                 : 1939870000 :     size_t n = jl_array_nrows(a);
     955                 : 1939870000 :     jl_array_grow_at_end(a, n, inc, n);
     956                 : 1939870000 : }
     957                 :            : 
     958                 :    2256660 : JL_DLLEXPORT void jl_array_grow_beg(jl_array_t *a, size_t inc)
     959                 :            : {
     960                 :    2256660 :     size_t n = jl_array_nrows(a);
     961                 :    2256660 :     jl_array_grow_at_beg(a, 0, inc, n);
     962                 :    2256660 : }
     963                 :            : 
     964                 :     427965 : STATIC_INLINE void jl_array_shrink(jl_array_t *a, size_t dec)
     965                 :            : {
     966                 :            :     //if we don't manage this array return
     967         [ +  + ]:     427965 :     if (a->flags.how == 0) return;
     968                 :            : 
     969                 :      52271 :     size_t elsz = a->elsize;
     970                 :      52271 :     size_t newbytes = (a->maxsize - dec) * a->elsize;
     971                 :      52271 :     size_t oldnbytes = (a->maxsize) * a->elsize;
     972   [ +  +  +  + ]:      52271 :     int isbitsunion = jl_array_isbitsunion(a);
     973         [ +  + ]:      52271 :     if (isbitsunion) {
     974                 :          1 :         newbytes += a->maxsize - dec;
     975                 :          1 :         oldnbytes += a->maxsize;
     976                 :            :     }
     977                 :            : 
     978   [ +  +  +  + ]:      52271 :     if (elsz == 1 && !isbitsunion) {
     979                 :      22536 :         newbytes++;
     980                 :      22536 :         oldnbytes++;
     981                 :            :     }
     982                 :      52271 :     char *originalptr = ((char*) a->data) - a->offset * a->elsize;
     983         [ +  + ]:      52271 :     if (a->flags.how == 1) {
     984                 :            :         //this is a julia-allocated buffer that needs to be marked
     985                 :            :         char *typetagdata;
     986                 :            :         char *newtypetagdata;
     987         [ -  + ]:      29724 :         if (isbitsunion) {
     988                 :          0 :             typetagdata = (char*)malloc_s(a->nrows);
     989                 :          0 :             memcpy(typetagdata, jl_array_typetagdata(a), a->nrows);
     990                 :            :         }
     991                 :      29724 :         jl_task_t *ct = jl_current_task;
     992                 :      29724 :         char *originaldata = (char*) a->data - a->offset * a->elsize;
     993                 :      29724 :         char *newdata = (char*)jl_gc_alloc_buf(ct->ptls, newbytes);
     994                 :      29724 :         jl_gc_wb_buf(a, newdata, newbytes);
     995                 :      29724 :         a->maxsize -= dec;
     996         [ -  + ]:      29724 :         if (isbitsunion) {
     997                 :          0 :             newtypetagdata = jl_array_typetagdata(a);
     998                 :          0 :             memcpy(newtypetagdata, typetagdata, a->nrows);
     999                 :          0 :             free(typetagdata);
    1000                 :            :         }
    1001                 :      29724 :         memcpy(newdata, originaldata, newbytes);
    1002                 :      29724 :         a->data = newdata + a->offset * elsz;
    1003                 :            :     }
    1004         [ +  + ]:      22547 :     else if (a->flags.how == 2) {
    1005                 :            :         //malloc-allocated pointer this array object manages
    1006                 :            :         char *typetagdata;
    1007                 :            :         char *newtypetagdata;
    1008         [ +  + ]:         11 :         if (isbitsunion) {
    1009                 :          1 :             typetagdata = (char*)malloc_s(a->nrows);
    1010                 :          1 :             memcpy(typetagdata, jl_array_typetagdata(a), a->nrows);
    1011                 :            :         }
    1012                 :         11 :         size_t oldoffsnb = a->offset * elsz;
    1013                 :         22 :         a->data = ((char*)jl_gc_managed_realloc(originalptr, newbytes, oldnbytes,
    1014                 :         11 :                 a->flags.isaligned, (jl_value_t*) a)) + oldoffsnb;
    1015                 :         11 :         a->maxsize -= dec;
    1016         [ +  + ]:         11 :         if (isbitsunion) {
    1017                 :          1 :             newtypetagdata = jl_array_typetagdata(a);
    1018                 :          1 :             memcpy(newtypetagdata, typetagdata, a->nrows);
    1019                 :          1 :             free(typetagdata);
    1020                 :            :         }
    1021                 :            :     }
    1022                 :      22536 :     else if (a->flags.how == 3) {
    1023                 :            :         //this has has a pointer to the object that owns the data
    1024                 :            :     }
    1025                 :            : }
    1026                 :            : 
    1027                 :   18270900 : static size_t jl_array_limit_offset(jl_array_t *a, size_t offset)
    1028                 :            : {
    1029                 :            :     // make sure offset doesn't grow forever due to deleting at beginning
    1030                 :            :     // and growing at end
    1031         [ +  + ]:   18270900 :     if (offset >= 13 * a->maxsize / 20)
    1032                 :     428672 :         offset = 17 * (a->maxsize - a->nrows) / 100;
    1033                 :            : #ifdef _P64
    1034         [ -  + ]:   18270900 :     while (offset > (size_t)UINT32_MAX) {
    1035                 :          0 :         offset /= 2;
    1036                 :            :     }
    1037                 :            : #endif
    1038                 :   18270900 :     return offset;
    1039                 :            : }
    1040                 :            : 
    1041                 :   18270900 : STATIC_INLINE void jl_array_del_at_beg(jl_array_t *a, size_t idx, size_t dec,
    1042                 :            :                                        size_t n)
    1043                 :            : {
    1044                 :            :     // no error checking
    1045                 :            :     // assume inbounds, assume unshared
    1046                 :   18270900 :     size_t elsz = a->elsize;
    1047                 :   18270900 :     size_t offset = a->offset;
    1048   [ +  +  +  + ]:   18270900 :     int isbitsunion = jl_array_isbitsunion(a);
    1049                 :   18270900 :     offset += dec;
    1050                 :   18270900 :     a->length = n - dec;
    1051                 :   18270900 :     a->nrows = n - dec;
    1052                 :   18270900 :     size_t newoffs = jl_array_limit_offset(a, offset);
    1053         [ -  + ]:   18270900 :     assert(newoffs <= offset);
    1054                 :   18270900 :     size_t nbdec = dec * elsz;
    1055   [ +  +  +  + ]:   18270900 :     if (__unlikely(newoffs != offset) || idx > 0) {
    1056                 :     466261 :         char *olddata = (char*)a->data;
    1057                 :     466261 :         char *newdata = olddata - (a->offset - newoffs) * elsz;
    1058                 :            :         char *typetagdata;
    1059                 :            :         char *newtypetagdata;
    1060         [ +  + ]:     466261 :         if (isbitsunion) {
    1061                 :         15 :             typetagdata = jl_array_typetagdata(a);
    1062                 :         15 :             newtypetagdata = typetagdata - (a->offset - newoffs);
    1063                 :            :         }
    1064                 :            : 
    1065                 :     466261 :         size_t nb1 = idx * elsz; // size in bytes of the first block
    1066                 :     466261 :         size_t nbtotal = a->nrows * elsz; // size in bytes of the new array
    1067                 :            :         // Implicit '\0' for byte arrays
    1068   [ +  +  +  + ]:     466261 :         if (elsz == 1 && !isbitsunion)
    1069                 :      40776 :             nbtotal++;
    1070         [ +  + ]:     466261 :         if (idx > 0) {
    1071                 :      42004 :             memmove_safe(a->flags.hasptr, newdata, olddata, nb1);
    1072         [ +  + ]:      42004 :             if (isbitsunion) memmove(newtypetagdata, typetagdata, idx);
    1073                 :            :         }
    1074                 :            :         // Move the rest of the data if the offset changed
    1075         [ +  + ]:     466261 :         if (newoffs != offset) {
    1076                 :     428672 :             memmove_safe(a->flags.hasptr, newdata + nb1, olddata + nb1 + nbdec, nbtotal - nb1);
    1077         [ +  + ]:     428672 :             if (isbitsunion) memmove(newtypetagdata + idx, typetagdata + idx + dec, a->nrows - idx);
    1078                 :            :         }
    1079                 :     466261 :         a->data = newdata;
    1080                 :            :     }
    1081                 :            :     else {
    1082                 :   17804600 :         char *data = (char*)a->data;
    1083                 :   17804600 :         a->data = data + nbdec;
    1084                 :            :     }
    1085                 :   18270900 :     a->offset = newoffs;
    1086                 :   18270900 : }
    1087                 :            : 
    1088                 :  485654000 : STATIC_INLINE void jl_array_del_at_end(jl_array_t *a, size_t idx, size_t dec,
    1089                 :            :                                        size_t n)
    1090                 :            : {
    1091                 :            :     // no error checking
    1092                 :            :     // assume inbounds, assume unshared
    1093                 :  485654000 :     char *data = (char*)a->data;
    1094                 :  485654000 :     size_t elsz = a->elsize;
    1095   [ +  +  +  + ]:  485654000 :     int isbitsunion = jl_array_isbitsunion(a);
    1096                 :  485654000 :     size_t last = idx + dec;
    1097         [ +  + ]:  485654000 :     if (n > last) {
    1098                 :      48121 :         memmove_safe(a->flags.hasptr, data + idx * elsz, data + last * elsz, (n - last) * elsz);
    1099         [ +  + ]:      48121 :         if (isbitsunion) {
    1100                 :          5 :             char *typetagdata = jl_array_typetagdata(a);
    1101                 :          5 :             memmove(typetagdata + idx, typetagdata + last, n - last);
    1102                 :            :         }
    1103                 :            :     }
    1104                 :  485654000 :     n -= dec;
    1105   [ +  +  +  + ]:  485654000 :     if (elsz == 1 && !isbitsunion)
    1106                 :   13470500 :         data[n] = 0;
    1107                 :  485654000 :     a->nrows = n;
    1108                 :  485654000 :     a->length = n;
    1109                 :  485654000 : }
    1110                 :            : 
    1111                 :     193567 : JL_DLLEXPORT void jl_array_del_at(jl_array_t *a, ssize_t idx, size_t dec)
    1112                 :            : {
    1113                 :     193567 :     size_t n = jl_array_nrows(a);
    1114                 :     193567 :     size_t last = idx + dec;
    1115         [ -  + ]:     193567 :     if (__unlikely(idx < 0))
    1116                 :          0 :         jl_bounds_error_int((jl_value_t*)a, idx + 1);
    1117         [ +  + ]:     193567 :     if (__unlikely(last > n))
    1118                 :          3 :         jl_bounds_error_int((jl_value_t*)a, last);
    1119                 :            :     // The unsharing needs to happen before we modify the buffer
    1120         [ +  + ]:     193564 :     if (__unlikely(a->flags.isshared))
    1121                 :         37 :         array_try_unshare(a);
    1122         [ +  + ]:     193560 :     if (idx < n - last) {
    1123                 :      51548 :         jl_array_del_at_beg(a, idx, dec, n);
    1124                 :            :     }
    1125                 :            :     else {
    1126                 :     142012 :         jl_array_del_at_end(a, idx, dec, n);
    1127                 :            :     }
    1128                 :     193560 : }
    1129                 :            : 
    1130                 :   18219400 : JL_DLLEXPORT void jl_array_del_beg(jl_array_t *a, size_t dec)
    1131                 :            : {
    1132                 :   18219400 :     size_t n = jl_array_nrows(a);
    1133         [ -  + ]:   18219400 :     if (__unlikely(dec > n))
    1134                 :          0 :         jl_bounds_error_int((jl_value_t*)a, dec);
    1135         [ +  + ]:   18219400 :     if (__unlikely(a->flags.isshared))
    1136                 :          8 :         array_try_unshare(a);
    1137         [ +  + ]:   18219300 :     if (dec == 0)
    1138                 :          2 :         return;
    1139                 :   18219300 :     jl_array_del_at_beg(a, 0, dec, n);
    1140                 :            : }
    1141                 :            : 
    1142                 :  538984000 : JL_DLLEXPORT void jl_array_del_end(jl_array_t *a, size_t dec)
    1143                 :            : {
    1144                 :  538984000 :     size_t n = jl_array_nrows(a);
    1145         [ -  + ]:  538984000 :     if (__unlikely(n < dec))
    1146                 :          0 :         jl_bounds_error_int((jl_value_t*)a, 0);
    1147         [ +  + ]:  538984000 :     if (__unlikely(a->flags.isshared))
    1148                 :    1300200 :         array_try_unshare(a);
    1149         [ +  + ]:  538984000 :     if (dec == 0)
    1150                 :   53472700 :         return;
    1151                 :  485512000 :     jl_array_del_at_end(a, n - dec, dec, n);
    1152                 :            : }
    1153                 :            : 
    1154                 :  211814000 : JL_DLLEXPORT void jl_array_sizehint(jl_array_t *a, size_t sz)
    1155                 :            : {
    1156                 :  211814000 :     size_t n = jl_array_nrows(a);
    1157                 :            : 
    1158                 :  211814000 :     size_t min = a->offset + a->length;
    1159                 :  211814000 :     sz = (sz < min) ? min : sz;
    1160                 :            : 
    1161         [ +  + ]:  211814000 :     if (sz <= a->maxsize) {
    1162                 :     428188 :         size_t dec = a->maxsize - sz;
    1163                 :            :         //if we don't save at least an eighth of maxsize then its not worth it to shrink
    1164         [ +  + ]:     428188 :         if (dec < a->maxsize / 8) return;
    1165                 :     427965 :         jl_array_shrink(a, dec);
    1166                 :            :     }
    1167                 :            :     else {
    1168                 :  211385000 :         size_t inc = sz - n;
    1169                 :  211385000 :         jl_array_grow_end(a, inc);
    1170                 :            : 
    1171                 :  211385000 :         a->nrows = n;
    1172                 :  211385000 :         a->length = n;
    1173                 :            :     }
    1174                 :            : }
    1175                 :            : 
    1176                 :  108071000 : JL_DLLEXPORT jl_array_t *jl_array_copy(jl_array_t *ary)
    1177                 :            : {
    1178                 :  108071000 :     size_t elsz = ary->elsize;
    1179                 :  108071000 :     size_t len = jl_array_len(ary);
    1180                 :  108071000 :     int isunion = jl_is_uniontype(jl_tparam0(jl_typeof(ary)));
    1181                 :  108071000 :     jl_array_t *new_ary = _new_array_(jl_typeof(ary), jl_array_ndims(ary),
    1182                 :  108071000 :                                       &ary->nrows, !ary->flags.ptrarray,
    1183                 :  108071000 :                                       ary->flags.hasptr, isunion, 0, elsz);
    1184                 :  108071000 :     memcpy(new_ary->data, ary->data, len * elsz);
    1185                 :            :     // ensure isbits union arrays copy their selector bytes correctly
    1186   [ +  +  +  + ]:  108071000 :     if (jl_array_isbitsunion(ary))
    1187                 :         16 :         memcpy(jl_array_typetagdata(new_ary), jl_array_typetagdata(ary), len);
    1188                 :  108071000 :     return new_ary;
    1189                 :            : }
    1190                 :            : 
    1191                 :            : // Copy element by element until we hit a young object, at which point
    1192                 :            : // we can finish by using `memmove`.
    1193                 :       1811 : static NOINLINE ssize_t jl_array_ptr_copy_forward(jl_value_t *owner,
    1194                 :            :                                                   void **src_p, void **dest_p,
    1195                 :            :                                                   ssize_t n) JL_NOTSAFEPOINT
    1196                 :            : {
    1197                 :       1811 :     _Atomic(void*) *src_pa = (_Atomic(void*)*)src_p;
    1198                 :       1811 :     _Atomic(void*) *dest_pa = (_Atomic(void*)*)dest_p;
    1199         [ +  + ]:       2902 :     for (ssize_t i = 0; i < n; i++) {
    1200                 :       2215 :         void *val = jl_atomic_load_relaxed(src_pa + i);
    1201                 :       2215 :         jl_atomic_store_release(dest_pa + i, val);
    1202                 :            :         // `val` is young or old-unmarked
    1203   [ +  -  +  + ]:       2215 :         if (val && !(jl_astaggedvalue(val)->bits.gc & GC_MARKED)) {
    1204                 :       1124 :             jl_gc_queue_root(owner);
    1205                 :       1124 :             return i;
    1206                 :            :         }
    1207                 :            :     }
    1208                 :        687 :     return n;
    1209                 :            : }
    1210                 :            : 
    1211                 :          0 : static NOINLINE ssize_t jl_array_ptr_copy_backward(jl_value_t *owner,
    1212                 :            :                                                    void **src_p, void **dest_p,
    1213                 :            :                                                    ssize_t n) JL_NOTSAFEPOINT
    1214                 :            : {
    1215                 :          0 :     _Atomic(void*) *src_pa = (_Atomic(void*)*)src_p;
    1216                 :          0 :     _Atomic(void*) *dest_pa = (_Atomic(void*)*)dest_p;
    1217         [ #  # ]:          0 :     for (ssize_t i = 0; i < n; i++) {
    1218                 :          0 :         void *val = jl_atomic_load_relaxed(src_pa + n - i - 1);
    1219                 :          0 :         jl_atomic_store_release(dest_pa + n - i - 1, val);
    1220                 :            :         // `val` is young or old-unmarked
    1221   [ #  #  #  # ]:          0 :         if (val && !(jl_astaggedvalue(val)->bits.gc & GC_MARKED)) {
    1222                 :          0 :             jl_gc_queue_root(owner);
    1223                 :          0 :             return i;
    1224                 :            :         }
    1225                 :            :     }
    1226                 :          0 :     return n;
    1227                 :            : }
    1228                 :            : 
    1229                 :            : // Unsafe, assume inbounds and that dest and src have the same eltype
    1230                 :   57174400 : JL_DLLEXPORT void jl_array_ptr_copy(jl_array_t *dest, void **dest_p,
    1231                 :            :                                     jl_array_t *src, void **src_p, ssize_t n) JL_NOTSAFEPOINT
    1232                 :            : {
    1233   [ +  -  +  - ]:   57174400 :     assert(dest->flags.ptrarray && src->flags.ptrarray);
    1234                 :   57174400 :     jl_value_t *owner = jl_array_owner(dest);
    1235                 :            :     // Destination is old and doesn't refer to any young object
    1236         [ +  + ]:   57174400 :     if (__unlikely(jl_astaggedvalue(owner)->bits.gc == GC_OLD_MARKED)) {
    1237                 :       4454 :         jl_value_t *src_owner = jl_array_owner(src);
    1238                 :            :         // Source is young or being promoted or might refer to young objects
    1239                 :            :         // (i.e. source is not an old object that doesn't have wb triggered)
    1240         [ +  + ]:       4454 :         if (jl_astaggedvalue(src_owner)->bits.gc != GC_OLD_MARKED) {
    1241                 :            :             ssize_t done;
    1242   [ +  +  +  - ]:       1811 :             if (dest_p < src_p || dest_p > src_p + n) {
    1243                 :       1811 :                 done = jl_array_ptr_copy_forward(owner, src_p, dest_p, n);
    1244                 :       1811 :                 dest_p += done;
    1245                 :       1811 :                 src_p += done;
    1246                 :            :             }
    1247                 :            :             else {
    1248                 :          0 :                 done = jl_array_ptr_copy_backward(owner, src_p, dest_p, n);
    1249                 :            :             }
    1250                 :       1811 :             n -= done;
    1251                 :            :         }
    1252                 :            :     }
    1253                 :   57174400 :     memmove_refs(dest_p, src_p, n);
    1254                 :   57174400 : }
    1255                 :            : 
    1256                 :   38817000 : JL_DLLEXPORT void jl_array_ptr_1d_push(jl_array_t *a, jl_value_t *item)
    1257                 :            : {
    1258         [ -  + ]:   38817000 :     assert(jl_typeis(a, jl_array_any_type));
    1259                 :   38817000 :     jl_array_grow_end(a, 1);
    1260                 :   38817000 :     size_t n = jl_array_nrows(a);
    1261                 :   38817000 :     jl_array_ptr_set(a, n - 1, item);
    1262                 :   38817000 : }
    1263                 :            : 
    1264                 :        217 : JL_DLLEXPORT void jl_array_ptr_1d_append(jl_array_t *a, jl_array_t *a2)
    1265                 :            : {
    1266         [ -  + ]:        217 :     assert(jl_typeis(a, jl_array_any_type));
    1267         [ -  + ]:        217 :     assert(jl_typeis(a2, jl_array_any_type));
    1268                 :            :     size_t i;
    1269                 :        217 :     size_t n = jl_array_nrows(a);
    1270                 :        217 :     size_t n2 = jl_array_nrows(a2);
    1271                 :        217 :     jl_array_grow_end(a, n2);
    1272         [ +  + ]:       1584 :     for (i = 0; i < n2; i++) {
    1273                 :       1367 :         jl_array_ptr_set(a, n + i, jl_array_ptr_ref(a2, i));
    1274                 :            :     }
    1275                 :        217 : }
    1276                 :            : 
    1277                 :          2 : JL_DLLEXPORT jl_value_t *(jl_array_data_owner)(jl_array_t *a) JL_NOTSAFEPOINT
    1278                 :            : {
    1279                 :          2 :     return jl_array_data_owner(a);
    1280                 :            : }
    1281                 :            : 
    1282                 :         14 : STATIC_INLINE int jl_has_implicit_byte_owned(jl_array_t *a)
    1283                 :            : {
    1284         [ -  + ]:         14 :     assert(a->flags.how != 3);
    1285         [ +  + ]:         14 :     if (!a->flags.isshared)
    1286                 :         12 :         return 1;
    1287                 :          2 :     return a->flags.how == 1;
    1288                 :            : }
    1289                 :            : 
    1290                 :         15 : STATIC_INLINE int jl_has_implicit_byte(jl_array_t *a)
    1291                 :            : {
    1292                 :            :     // * unshared:
    1293                 :            :     //   * how: 0-2
    1294                 :            :     //     We own and allocated the data.
    1295                 :            :     //     It should have the extra byte.
    1296                 :            :     // * shared:
    1297                 :            :     //   * how: 0, 2
    1298                 :            :     //     The data might come from external source without implicit NUL byte.
    1299                 :            :     //     There could be an entra byte for a `reinterpreted` array
    1300                 :            :     //     but that should be unlikely for strings.
    1301                 :            :     //   * how: 1
    1302                 :            :     //     We allocated the data with the extra byte.
    1303                 :            :     //   * how: 3
    1304                 :            :     //     We should check the owner.
    1305         [ +  + ]:         15 :     if (a->flags.how == 3) {
    1306                 :          1 :         a = (jl_array_t*)jl_array_data_owner(a);
    1307         [ +  - ]:          1 :         if (jl_is_string(a)) return 1;
    1308   [ #  #  #  # ]:          0 :         return a->elsize == 1 && jl_has_implicit_byte_owned(a);
    1309                 :            :     }
    1310                 :         14 :     return jl_has_implicit_byte_owned(a);
    1311                 :            : }
    1312                 :            : 
    1313                 :            : // Create an array with the same content
    1314                 :         15 : JL_DLLEXPORT jl_array_t *jl_array_cconvert_cstring(jl_array_t *a)
    1315                 :            : {
    1316         [ -  + ]:         15 :     assert(jl_typeof(a) == jl_array_uint8_type);
    1317         [ +  + ]:         15 :     if (!jl_has_implicit_byte(a))
    1318                 :          2 :         a = jl_array_copy(a);
    1319                 :         15 :     ((char*)a->data)[a->nrows] = 0;
    1320                 :         15 :     return a;
    1321                 :            : }
    1322                 :            : 
    1323                 :            : #ifdef __cplusplus
    1324                 :            : }
    1325                 :            : #endif

Generated by: LCOV version 1.14