• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

krakjoe / parallel / 20272758286

16 Dec 2025 03:11PM UTC coverage: 96.815%. Remained the same
20272758286

Pull #357

github

web-flow
Merge 771053661 into 14042a874
Pull Request #357: Cleanup code formatting and docs

44 of 48 new or added lines in 6 files covered. (91.67%)

30 existing lines in 11 files now uncovered.

3009 of 3108 relevant lines covered (96.81%)

6860.26 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.47
/src/cache.c
1
/*
2
  +----------------------------------------------------------------------+
3
  | parallel                                                             |
4
  +----------------------------------------------------------------------+
5
  | Copyright (c) Joe Watkins 2019-2024                                  |
6
  +----------------------------------------------------------------------+
7
  | This source file is subject to version 3.01 of the PHP license,      |
8
  | that is bundled with this package in the file LICENSE, and is        |
9
  | available through the world-wide-web at the following url:           |
10
  | http://www.php.net/license/3_01.txt                                  |
11
  | If you did not receive a copy of the PHP license and are unable to   |
12
  | obtain it through the world-wide-web, please send a note to          |
13
  | license@php.net so we can mail you a copy immediately.               |
14
  +----------------------------------------------------------------------+
15
  | Author: krakjoe                                                      |
16
  +----------------------------------------------------------------------+
17
 */
18
#ifndef HAVE_PARALLEL_CACHE
19
#define HAVE_PARALLEL_CACHE
20

21
#include "parallel.h"
22

23
static struct {
24
    pthread_mutex_t mutex;
25
    HashTable       table;
26
    struct {
27
        size_t      size;
28
        size_t      used;
29
        void       *mem;
30
        void       *block;
31
    } memory;
32
} php_parallel_cache_globals = {PTHREAD_MUTEX_INITIALIZER};
33

34
#define PCG(e) php_parallel_cache_globals.e
35
#define PCM(e) PCG(memory).e
36

37
#define PARALLEL_CACHE_CHUNK \
38
    PARALLEL_PLATFORM_ALIGNED((1024 * 1024) * 8)
39

40
/* {{{ */
41
static zend_always_inline void* php_parallel_cache_alloc(size_t size) {
5,284✔
42
    void *mem;
5,284✔
43
    size_t aligned =
5,284✔
44
        PARALLEL_PLATFORM_ALIGNED(size);
2,833✔
45

46
    ZEND_ASSERT(size < PARALLEL_CACHE_CHUNK);
5,284✔
47

48
    if ((PCM(used) + aligned) >= PCM(size)) {
5,284✔
49
        PCM(size) = PARALLEL_PLATFORM_ALIGNED(
×
50
            PCM(size) + PARALLEL_CACHE_CHUNK);
NEW
51
        PCM(mem) = realloc(PCM(mem), PCM(size));
×
52

53
        if (!PCM(mem)) {
×
54
            /* out of memory */
55
            return NULL;
56
        }
57

UNCOV
58
        PCM(block) = (void*)(((char*)PCM(mem)) + PCM(used));
×
59
    }
60

61
    mem = PCM(block);
5,284✔
62
    PCM(block) =
5,284✔
63
        (void*)(((char*)PCM(block)) + aligned);
5,284✔
64
    PCM(used) += aligned;
5,284✔
65

66
    return mem;
5,284✔
67
}
68

69
static zend_always_inline void* php_parallel_cache_copy_mem(void *source, zend_long size) {
4,768✔
70
    void *destination =
4,768✔
71
        php_parallel_cache_alloc(size);
120✔
72

73
    memcpy(destination, source, size);
4,648✔
74

75
    return destination;
4,768✔
76
} /* }}} */
77

78
static zend_always_inline HashTable* php_parallel_cache_statics(HashTable *statics) { /* {{{ */
21✔
79
    HashTable *cached = zend_hash_index_find_ptr(&PCG(table), (zend_ulong) statics);
42✔
80

81
    if (cached) {
×
82
        return cached;
83
    }
84

85
    cached = php_parallel_copy_hash_persistent(
21✔
86
                statics,
87
                php_parallel_copy_string_interned,
88
                php_parallel_cache_copy_mem);
89

90
    return zend_hash_index_update_ptr(&PCG(table), (zend_ulong) statics, cached);
21✔
91
} /* }}} */
92

93
static zend_always_inline void php_parallel_cache_type(zend_type *type) { /* {{{ */
266✔
94
    zend_type *single;
266✔
95

96
    if (!ZEND_TYPE_IS_SET(*type)) {
266✔
97
        return;
98
    }
99

100
    if (ZEND_TYPE_HAS_LIST(*type)) {
150✔
101
        zend_type_list *list = ZEND_TYPE_LIST(*type);
6✔
102

103
        list = php_parallel_cache_copy_mem(
12✔
104
                list, ZEND_TYPE_LIST_SIZE(list->num_types));
6✔
105

106
        if (ZEND_TYPE_USES_ARENA(*type)) {
6✔
107
            ZEND_TYPE_FULL_MASK(*type) &= ~_ZEND_TYPE_ARENA_BIT;
5✔
108
        }
109

110
        ZEND_TYPE_SET_PTR(*type, list);
6✔
111
    }
112

113
    ZEND_TYPE_FOREACH(*type, single) {
150✔
114
        if (ZEND_TYPE_HAS_NAME(*single)) {
156✔
115
            zend_string *name = ZEND_TYPE_NAME(*single);
90✔
116

117
            ZEND_TYPE_SET_PTR(
90✔
118
                *single,
119
                php_parallel_copy_string_interned(name));
120
        }
121
    } ZEND_TYPE_FOREACH_END();
156✔
122
} /* }}} */
123

124

125
/* {{{ */
126
static zend_op_array* php_parallel_cache_create(const zend_function *source, bool statics) {
2,451✔
127
    zend_op_array *cached = php_parallel_cache_copy_mem((void*) source, sizeof(zend_op_array));
2,451✔
128

129
    cached->fn_flags |= ZEND_ACC_IMMUTABLE;
2,451✔
130

131
    if (statics && cached->static_variables) {
2,451✔
132
        cached->static_variables =
42✔
133
            php_parallel_cache_statics(cached->static_variables);
42✔
134
    }
135

136
#if PHP_VERSION_ID >= 80200
137
    ZEND_MAP_PTR_INIT(cached->static_variables_ptr, cached->static_variables);
1,668✔
138
#else
139
    ZEND_MAP_PTR_INIT(cached->static_variables_ptr, &cached->static_variables);
783✔
140
#endif
141

142
    ZEND_MAP_PTR_INIT(cached->run_time_cache, NULL);
2,451✔
143

144
#if PHP_VERSION_ID >= 80100
145
    if (cached->num_dynamic_func_defs) {
2,085✔
146
        uint32_t it = 0;
180✔
147

148
        cached->dynamic_func_defs = php_parallel_cache_copy_mem(
360✔
149
                                        cached->dynamic_func_defs,
180✔
150
                                        sizeof(zend_op_array*) * cached->num_dynamic_func_defs);
180✔
151

152
        while (it < cached->num_dynamic_func_defs) {
390✔
153
            cached->dynamic_func_defs[it] =
420✔
154
                php_parallel_cache_create(
210✔
155
                    (zend_function*) cached->dynamic_func_defs[it], statics);
210✔
156
            it++;
210✔
157
        }
158
    }
159
#endif
160

161
    // This path is taken when OPcache is enabled and active, and the `source`
162
    // zend_function's opcodes are already handled and stored in OPcache's
163
    // Shared Memory (SHM). OPcache sets `op_array->refcount`to `NULL` for such
164
    // persistent `op_array`'s.
165
    if (!cached->refcount) {
2,451✔
166
        goto _php_parallel_cached_function_return;
1,616✔
167
    }
168

169
    cached->refcount  = NULL;
835✔
170

171
    if (cached->last_literal) {
835✔
172
        zval     *literal = cached->literals;
835✔
173
        zval     *end     = literal + cached->last_literal;
835✔
174
        zval     *slot    = php_parallel_cache_copy_mem(
1,670✔
175
                                    cached->literals,
835✔
176
                                        sizeof(zval) * cached->last_literal);
177

178
        cached->literals = slot;
835✔
179

180
        while (literal < end) {
4,127✔
181
            if (Z_TYPE_P(literal) == IS_ARRAY) {
3,292✔
182
                ZVAL_ARR(slot,
42✔
183
                    php_parallel_copy_hash_persistent(
184
                        Z_ARRVAL_P(literal),
185
                        php_parallel_copy_string_interned,
186
                        php_parallel_cache_copy_mem));
187
            } else if (Z_TYPE_P(literal) == IS_STRING) {
3,250✔
188
                ZVAL_STR(slot,
1,848✔
189
                    php_parallel_copy_string_interned(Z_STR_P(literal)));
190
            }
191

192
            Z_TYPE_FLAGS_P(slot) &= ~(IS_TYPE_REFCOUNTED|IS_TYPE_COLLECTABLE);
3,292✔
193
            literal++;
3,292✔
194
            slot++;
3,292✔
195
        }
196
    }
197

198
    if (cached->last_var) {
835✔
199
        zend_string **vars = cached->vars;
516✔
200
        uint32_t      it = 0;
516✔
201
        uint32_t      end = cached->last_var;
516✔
202
        zend_string **heap = php_parallel_cache_alloc(cached->last_var * sizeof(zend_string*));
516✔
203

204
        while (it < end) {
1,227✔
205
            heap[it] =
1,422✔
206
                php_parallel_copy_string_interned(vars[it]);
711✔
207
            it++;
711✔
208
        }
209
        cached->vars = heap;
516✔
210
    }
211

212
    if (cached->last) {
835✔
213
        zend_op *opcodes = php_parallel_cache_copy_mem(cached->opcodes, sizeof(zend_op) * cached->last);
835✔
214
        zend_op *opline  = opcodes;
835✔
215
        zend_op *end     = opline + cached->last;
835✔
216

217
        while (opline < end) {
6,327✔
218
            if (opline->op1_type == IS_CONST) {
5,492✔
219
#if ZEND_USE_ABS_CONST_ADDR
220
                opline->op1.zv = (zval*)((char*)opline->op1.zv + ((char*)cached->literals - (char*)source->op_array.literals));
221
#else
222
                opline->op1.constant =
1,755✔
223
                    (char*)(cached->literals +
1,755✔
224
                            ((zval*)((char*)(source->op_array.opcodes + (opline - opcodes)) +
1,755✔
225
                            (int32_t)opline->op1.constant) - source->op_array.literals)) -
1,755✔
226
                            (char*)opline;
227
#endif
228
                if (opline->opcode == ZEND_SEND_VAL
1,755✔
229
                 || opline->opcode == ZEND_SEND_VAL_EX
1,755✔
230
                 || opline->opcode == ZEND_QM_ASSIGN) {
1,500✔
231
                    zend_vm_set_opcode_handler_ex(opline, 0, 0, 0);
255✔
232
                }
233
            }
234
            if (opline->op2_type == IS_CONST) {
5,492✔
235
#if ZEND_USE_ABS_CONST_ADDR
236
                opline->op2.zv = (zval*)((char*)opline->op2.zv + ((char*)cached->literals - (char*)source->op_array.literals));
237
#else
238
                opline->op2.constant =
966✔
239
                    (char*)(cached->literals +
966✔
240
                            ((zval*)((char*)(source->op_array.opcodes + (opline - opcodes)) +
966✔
241
                            (int32_t)opline->op2.constant) - source->op_array.literals)) -
966✔
242
                            (char*)opline;
243
#endif
244
            }
245
#if ZEND_USE_ABS_JMP_ADDR
246
            switch (opline->opcode) {
247
                case ZEND_JMP:
248
                case ZEND_FAST_CALL:
249
                    opline->op1.jmp_addr = &opcodes[opline->op1.jmp_addr - source->op_array.opcodes];
250
                break;
251
#if PHP_VERSION_ID < 80200
252
                case ZEND_JMPZNZ:
253
#endif
254
                case ZEND_JMPZ:
255
                case ZEND_JMPNZ:
256
                case ZEND_JMPZ_EX:
257
                case ZEND_JMPNZ_EX:
258
                case ZEND_JMP_SET:
259
                case ZEND_COALESCE:
260
                case ZEND_FE_RESET_R:
261
                case ZEND_FE_RESET_RW:
262
                case ZEND_ASSERT_CHECK:
263
                    opline->op2.jmp_addr = &opcodes[opline->op2.jmp_addr - source->op_array.opcodes];
264
                    break;
265

266
                case ZEND_CATCH:
267
                    if (!(opline->extended_value & ZEND_LAST_CATCH)) {
268
                        opline->op2.jmp_addr = &opcodes[opline->op2.jmp_addr - source->op_array.opcodes];
269
                    }
270
                    break;
271
            }
272
#endif
273

274
            opline++;
5,492✔
275
        }
276
        cached->opcodes = opcodes;
835✔
277
    }
278

279
    if (cached->arg_info) {
835✔
280
        zend_arg_info *it    = cached->arg_info;
218✔
281
        zend_arg_info *end   = it + cached->num_args;
218✔
282
        zend_arg_info *info;
218✔
283

284
        if (cached->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
218✔
285
            it--;
36✔
286
        }
287
        if (cached->fn_flags & ZEND_ACC_VARIADIC) {
218✔
288
            end++;
12✔
289
        }
290

291
        cached->arg_info = info = php_parallel_cache_copy_mem(it, (end - it) * sizeof(zend_arg_info));
218✔
292

293
         while (it < end) {
484✔
294
            if (info->name) {
266✔
295
                info->name =
230✔
296
                    php_parallel_copy_string_interned(it->name);
230✔
297
            }
298

299
            php_parallel_cache_type(&info->type);
266✔
300

301
            info++;
266✔
302
            it++;
266✔
303
        }
304
        if (cached->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
218✔
305
            cached->arg_info++;
36✔
306
        }
307
    }
308

309
    if (cached->try_catch_array) {
835✔
310
        cached->try_catch_array =
36✔
311
            php_parallel_cache_copy_mem(
18✔
312
                cached->try_catch_array,
18✔
313
                    sizeof(zend_try_catch_element) * cached->last_try_catch);
18✔
314
    }
315

316
    if (cached->live_range) {
835✔
317
        cached->live_range =
210✔
318
            php_parallel_cache_copy_mem(
105✔
319
                cached->live_range,
105✔
320
                sizeof(zend_live_range) * cached->last_live_range);
105✔
321
    }
322

323
    if (cached->function_name) {
835✔
324
        cached->function_name =
835✔
325
            php_parallel_copy_string_interned(cached->function_name);
835✔
326
    }
327

328
    if (cached->filename) {
835✔
329
        cached->filename =
835✔
330
            php_parallel_copy_string_interned(cached->filename);
835✔
331
    }
332

333
    if (cached->doc_comment) {
835✔
334
        cached->doc_comment =
6✔
335
            php_parallel_copy_string_interned(cached->doc_comment);
6✔
336
    }
337

338
_php_parallel_cached_function_return:
829✔
339
    return cached;
2,451✔
340
} /* }}} */
341

342
/* {{{ */
343
static zend_always_inline zend_function* php_parallel_cache_function_ex(const zend_function *source, bool statics) {
2,925✔
344
    zend_op_array *cached;
2,925✔
345

346
    pthread_mutex_lock(&PCG(mutex));
2,925✔
347

348
    if ((cached = zend_hash_index_find_ptr(&PCG(table), (zend_ulong) source->op_array.opcodes))) {
3,609✔
349
        goto _php_parallel_cached_function_return;
684✔
350
    }
351

352
    cached = php_parallel_cache_create(source, statics);
2,241✔
353

354
    zend_hash_index_add_ptr(
5,166✔
355
        &PCG(table),
356
        (zend_ulong) source->op_array.opcodes,
2,241✔
357
        cached);
358

359
_php_parallel_cached_function_return:
2,925✔
360
    pthread_mutex_unlock(&PCG(mutex));
2,925✔
361

362
    return (zend_function*) cached;
2,925✔
363
} /* }}} */
364

365
zend_function* php_parallel_cache_closure(const zend_function *source, zend_function *closure) { /* {{{ */
2,889✔
366
    zend_op_array *cache;
2,889✔
367

368
    cache =
2,889✔
369
        (zend_op_array*)
370
            php_parallel_cache_function_ex(
2,889✔
371
                (zend_function*) source, 0);
372

373
    if (!closure) {
2,889✔
374
        closure = php_parallel_copy_mem(
2,217✔
375
            cache, sizeof(zend_op_array), 1);
376
    } else {
377
        memcpy(closure, cache, sizeof(zend_op_array));
672✔
378
    }
379

380
    if (source->op_array.static_variables) {
2,889✔
381
        HashTable *statics =
1,386✔
382
            ZEND_MAP_PTR_GET(
693✔
383
                source->op_array.static_variables_ptr);
384

385
        if (statics) {
693✔
386
        closure->op_array.static_variables =
1,116✔
387
            php_parallel_copy_hash_ctor(statics, 1);
558✔
388

389
#if PHP_VERSION_ID >= 80200
390
        ZEND_MAP_PTR_INIT(
372✔
391
            closure->op_array.static_variables_ptr,
392
            closure->op_array.static_variables);
393
#else
394
        ZEND_MAP_PTR_INIT(
186✔
395
            closure->op_array.static_variables_ptr,
396
            &closure->op_array.static_variables);
397
#endif
398
        }
399
    }
400

401
#if PHP_VERSION_ID >= 80100
402
    if (source->op_array.num_dynamic_func_defs) {
2,455✔
403
        uint32_t it = 0;
195✔
404
        /* Use regular persistent memory for dynamic_func_defs array, not cache pool */
405
        closure->op_array.dynamic_func_defs = pemalloc(
195✔
406
            sizeof(zend_op_array*) * source->op_array.num_dynamic_func_defs, 1);
407
        memcpy(closure->op_array.dynamic_func_defs,
615✔
408
            source->op_array.dynamic_func_defs,
195✔
409
            sizeof(zend_op_array*) * source->op_array.num_dynamic_func_defs);
195✔
410
        while (it < source->op_array.num_dynamic_func_defs) {
420✔
411
            closure->op_array.dynamic_func_defs[it] = (zend_op_array*) php_parallel_cache_closure((zend_function*) source->op_array.dynamic_func_defs[it], NULL);
225✔
412
            it++;
225✔
413
        }
414
    }
415
#endif
416

417
    return closure;
2,889✔
418
} /* }}} */
419

420
zend_function* php_parallel_cache_function(const zend_function *source) { /* {{{ */
36✔
421
    return php_parallel_cache_function_ex(source, 1);
36✔
422
} /* }}} */
423

424
/* {{{ */
425
PHP_MINIT_FUNCTION(PARALLEL_CACHE)
3,168✔
426
{
427
    zend_hash_init(&PCG(table), 32, NULL, NULL, 1);
3,168✔
428

429
    PCM(size) = PARALLEL_CACHE_CHUNK;
3,168✔
430
    PCM(mem) =
3,168✔
431
        PCM(block) =
3,168✔
432
            malloc(PCM(size));
3,168✔
433

434
    if (!PCM(mem)) {
3,168✔
435
        /* out of memory */
436
    }
3,168✔
437

438
    return SUCCESS;
3,168✔
439
}
440

441
PHP_MSHUTDOWN_FUNCTION(PARALLEL_CACHE)
3,168✔
442
{
443
    zend_hash_destroy(&PCG(table));
3,168✔
444

445
    if (PCM(mem)) {
3,168✔
446
        free(PCM(mem));
3,168✔
447
    }
448

449
    return SUCCESS;
3,168✔
450
} /* }}} */
451
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc