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
|