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

krakjoe / parallel / 20315085803

17 Dec 2025 07:39PM UTC coverage: 96.75% (-0.07%) from 96.815%
20315085803

push

github

web-flow
Cleanup code formatting and docs (#357)

* add comment about OPcache

* cleanup code formatting

2672 of 2765 new or added lines in 27 files covered. (96.64%)

1 existing line in 1 file now uncovered.

2798 of 2892 relevant lines covered (96.75%)

6639.73 hits per line

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

97.13
/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 PARALLEL_PLATFORM_ALIGNED((1024 * 1024) * 8)
38

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

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

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

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

NEW
56
                PCM(block) = (void *)(((char *)PCM(mem)) + PCM(used));
×
57
        }
58

59
        mem = PCM(block);
5,284✔
60
        PCM(block) = (void *)(((char *)PCM(block)) + aligned);
5,284✔
61
        PCM(used) += aligned;
5,284✔
62

63
        return mem;
5,284✔
64
}
65

66
static zend_always_inline void *php_parallel_cache_copy_mem(void *source, zend_long size)
4,768✔
67
{
68
        void *destination = php_parallel_cache_alloc(size);
120✔
69

70
        memcpy(destination, source, size);
4,648✔
71

72
        return destination;
4,768✔
73
} /* }}} */
74

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

NEW
79
        if (cached) {
×
80
                return cached;
81
        }
82

83
        cached = php_parallel_copy_hash_persistent(statics, php_parallel_copy_string_interned, php_parallel_cache_copy_mem);
21✔
84

85
        return zend_hash_index_update_ptr(&PCG(table), (zend_ulong)statics, cached);
21✔
86
} /* }}} */
87

88
static zend_always_inline void php_parallel_cache_type(zend_type *type)
266✔
89
{ /* {{{ */
90
        zend_type *single;
266✔
91

92
        if (!ZEND_TYPE_IS_SET(*type)) {
266✔
93
                return;
94
        }
95

96
        if (ZEND_TYPE_HAS_LIST(*type)) {
150✔
97
                zend_type_list *list = ZEND_TYPE_LIST(*type);
6✔
98

99
                list = php_parallel_cache_copy_mem(list, ZEND_TYPE_LIST_SIZE(list->num_types));
6✔
100

101
                if (ZEND_TYPE_USES_ARENA(*type)) {
6✔
102
                        ZEND_TYPE_FULL_MASK(*type) &= ~_ZEND_TYPE_ARENA_BIT;
5✔
103
                }
104

105
                ZEND_TYPE_SET_PTR(*type, list);
6✔
106
        }
107

108
        ZEND_TYPE_FOREACH(*type, single)
150✔
109
        {
110
                if (ZEND_TYPE_HAS_NAME(*single)) {
156✔
111
                        zend_string *name = ZEND_TYPE_NAME(*single);
90✔
112

113
                        ZEND_TYPE_SET_PTR(*single, php_parallel_copy_string_interned(name));
90✔
114
                }
115
        }
116
        ZEND_TYPE_FOREACH_END();
156✔
117
} /* }}} */
118

119
/* {{{ */
120
static zend_op_array *php_parallel_cache_create(const zend_function *source, bool statics)
2,451✔
121
{
122
        zend_op_array *cached = php_parallel_cache_copy_mem((void *)source, sizeof(zend_op_array));
2,451✔
123

124
        cached->fn_flags |= ZEND_ACC_IMMUTABLE;
2,451✔
125

126
        if (statics && cached->static_variables) {
2,451✔
127
                cached->static_variables = php_parallel_cache_statics(cached->static_variables);
42✔
128
        }
129

130
#if PHP_VERSION_ID >= 80200
131
        ZEND_MAP_PTR_INIT(cached->static_variables_ptr, cached->static_variables);
1,668✔
132
#else
133
        ZEND_MAP_PTR_INIT(cached->static_variables_ptr, &cached->static_variables);
783✔
134
#endif
135

136
        ZEND_MAP_PTR_INIT(cached->run_time_cache, NULL);
2,451✔
137

138
#if PHP_VERSION_ID >= 80100
139
        if (cached->num_dynamic_func_defs) {
2,085✔
140
                uint32_t it = 0;
180✔
141

142
                cached->dynamic_func_defs = php_parallel_cache_copy_mem(
360✔
143
                    cached->dynamic_func_defs, sizeof(zend_op_array *) * cached->num_dynamic_func_defs);
180✔
144

145
                while (it < cached->num_dynamic_func_defs) {
390✔
146
                        cached->dynamic_func_defs[it] =
420✔
147
                            php_parallel_cache_create((zend_function *)cached->dynamic_func_defs[it], statics);
210✔
148
                        it++;
210✔
149
                }
150
        }
151
#endif
152

153
        // This path is taken when OPcache is enabled and active, and the `source`
154
        // zend_function's opcodes are already handled and stored in OPcache's
155
        // Shared Memory (SHM). OPcache sets `op_array->refcount`to `NULL` for such
156
        // persistent `op_array`'s.
157
        if (!cached->refcount) {
2,451✔
158
                goto _php_parallel_cached_function_return;
1,616✔
159
        }
160

161
        cached->refcount = NULL;
835✔
162

163
        if (cached->last_literal) {
835✔
164
                zval *literal = cached->literals;
835✔
165
                zval *end = literal + cached->last_literal;
835✔
166
                zval *slot = php_parallel_cache_copy_mem(cached->literals, sizeof(zval) * cached->last_literal);
835✔
167

168
                cached->literals = slot;
835✔
169

170
                while (literal < end) {
4,127✔
171
                        if (Z_TYPE_P(literal) == IS_ARRAY) {
3,292✔
172
                                ZVAL_ARR(slot, php_parallel_copy_hash_persistent(Z_ARRVAL_P(literal), php_parallel_copy_string_interned,
42✔
173
                                                                                 php_parallel_cache_copy_mem));
174
                        } else if (Z_TYPE_P(literal) == IS_STRING) {
3,250✔
175
                                ZVAL_STR(slot, php_parallel_copy_string_interned(Z_STR_P(literal)));
1,848✔
176
                        }
177

178
                        Z_TYPE_FLAGS_P(slot) &= ~(IS_TYPE_REFCOUNTED | IS_TYPE_COLLECTABLE);
3,292✔
179
                        literal++;
3,292✔
180
                        slot++;
3,292✔
181
                }
182
        }
183

184
        if (cached->last_var) {
835✔
185
                zend_string **vars = cached->vars;
516✔
186
                uint32_t      it = 0;
516✔
187
                uint32_t      end = cached->last_var;
516✔
188
                zend_string **heap = php_parallel_cache_alloc(cached->last_var * sizeof(zend_string *));
516✔
189

190
                while (it < end) {
1,227✔
191
                        heap[it] = php_parallel_copy_string_interned(vars[it]);
711✔
192
                        it++;
711✔
193
                }
194
                cached->vars = heap;
516✔
195
        }
196

197
        if (cached->last) {
835✔
198
                zend_op *opcodes = php_parallel_cache_copy_mem(cached->opcodes, sizeof(zend_op) * cached->last);
835✔
199
                zend_op *opline = opcodes;
835✔
200
                zend_op *end = opline + cached->last;
835✔
201

202
                while (opline < end) {
6,327✔
203
                        if (opline->op1_type == IS_CONST) {
5,492✔
204
#if ZEND_USE_ABS_CONST_ADDR
205
                                opline->op1.zv =
206
                                    (zval *)((char *)opline->op1.zv + ((char *)cached->literals - (char *)source->op_array.literals));
207
#else
208
                                opline->op1.constant =
1,755✔
209
                                    (char *)(cached->literals + ((zval *)((char *)(source->op_array.opcodes + (opline - opcodes)) +
1,755✔
210
                                                                          (int32_t)opline->op1.constant) -
1,755✔
211
                                                                 source->op_array.literals)) -
1,755✔
212
                                    (char *)opline;
213
#endif
214
                                if (opline->opcode == ZEND_SEND_VAL || opline->opcode == ZEND_SEND_VAL_EX ||
1,755✔
215
                                    opline->opcode == ZEND_QM_ASSIGN) {
216
                                        zend_vm_set_opcode_handler_ex(opline, 0, 0, 0);
255✔
217
                                }
218
                        }
219
                        if (opline->op2_type == IS_CONST) {
5,492✔
220
#if ZEND_USE_ABS_CONST_ADDR
221
                                opline->op2.zv =
222
                                    (zval *)((char *)opline->op2.zv + ((char *)cached->literals - (char *)source->op_array.literals));
223
#else
224
                                opline->op2.constant =
966✔
225
                                    (char *)(cached->literals + ((zval *)((char *)(source->op_array.opcodes + (opline - opcodes)) +
966✔
226
                                                                          (int32_t)opline->op2.constant) -
966✔
227
                                                                 source->op_array.literals)) -
966✔
228
                                    (char *)opline;
229
#endif
230
                        }
231
#if ZEND_USE_ABS_JMP_ADDR
232
                        switch (opline->opcode) {
233
                        case ZEND_JMP:
234
                        case ZEND_FAST_CALL:
235
                                opline->op1.jmp_addr = &opcodes[opline->op1.jmp_addr - source->op_array.opcodes];
236
                                break;
237
#if PHP_VERSION_ID < 80200
238
                        case ZEND_JMPZNZ:
239
#endif
240
                        case ZEND_JMPZ:
241
                        case ZEND_JMPNZ:
242
                        case ZEND_JMPZ_EX:
243
                        case ZEND_JMPNZ_EX:
244
                        case ZEND_JMP_SET:
245
                        case ZEND_COALESCE:
246
                        case ZEND_FE_RESET_R:
247
                        case ZEND_FE_RESET_RW:
248
                        case ZEND_ASSERT_CHECK:
249
                                opline->op2.jmp_addr = &opcodes[opline->op2.jmp_addr - source->op_array.opcodes];
250
                                break;
251

252
                        case ZEND_CATCH:
253
                                if (!(opline->extended_value & ZEND_LAST_CATCH)) {
254
                                        opline->op2.jmp_addr = &opcodes[opline->op2.jmp_addr - source->op_array.opcodes];
255
                                }
256
                                break;
257
                        }
258
#endif
259

260
                        opline++;
5,492✔
261
                }
262
                cached->opcodes = opcodes;
835✔
263
        }
264

265
        if (cached->arg_info) {
835✔
266
                zend_arg_info *it = cached->arg_info;
218✔
267
                zend_arg_info *end = it + cached->num_args;
218✔
268
                zend_arg_info *info;
218✔
269

270
                if (cached->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
218✔
271
                        it--;
36✔
272
                }
273
                if (cached->fn_flags & ZEND_ACC_VARIADIC) {
218✔
274
                        end++;
12✔
275
                }
276

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

279
                while (it < end) {
484✔
280
                        if (info->name) {
266✔
281
                                info->name = php_parallel_copy_string_interned(it->name);
230✔
282
                        }
283

284
                        php_parallel_cache_type(&info->type);
266✔
285

286
                        info++;
266✔
287
                        it++;
266✔
288
                }
289
                if (cached->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
218✔
290
                        cached->arg_info++;
36✔
291
                }
292
        }
293

294
        if (cached->try_catch_array) {
835✔
295
                cached->try_catch_array = php_parallel_cache_copy_mem(cached->try_catch_array,
18✔
296
                                                                      sizeof(zend_try_catch_element) * cached->last_try_catch);
18✔
297
        }
298

299
        if (cached->live_range) {
835✔
300
                cached->live_range =
210✔
301
                    php_parallel_cache_copy_mem(cached->live_range, sizeof(zend_live_range) * cached->last_live_range);
210✔
302
        }
303

304
        if (cached->function_name) {
835✔
305
                cached->function_name = php_parallel_copy_string_interned(cached->function_name);
835✔
306
        }
307

308
        if (cached->filename) {
835✔
309
                cached->filename = php_parallel_copy_string_interned(cached->filename);
835✔
310
        }
311

312
        if (cached->doc_comment) {
835✔
313
                cached->doc_comment = php_parallel_copy_string_interned(cached->doc_comment);
6✔
314
        }
315

316
_php_parallel_cached_function_return:
829✔
317
        return cached;
2,451✔
318
} /* }}} */
319

320
/* {{{ */
321
static zend_always_inline zend_function *php_parallel_cache_function_ex(const zend_function *source, bool statics)
2,925✔
322
{
323
        zend_op_array *cached;
2,925✔
324

325
        pthread_mutex_lock(&PCG(mutex));
2,925✔
326

327
        if ((cached = zend_hash_index_find_ptr(&PCG(table), (zend_ulong)source->op_array.opcodes))) {
3,609✔
328
                goto _php_parallel_cached_function_return;
684✔
329
        }
330

331
        cached = php_parallel_cache_create(source, statics);
2,241✔
332

333
        zend_hash_index_add_ptr(&PCG(table), (zend_ulong)source->op_array.opcodes, cached);
2,241✔
334

335
_php_parallel_cached_function_return:
2,925✔
336
        pthread_mutex_unlock(&PCG(mutex));
2,925✔
337

338
        return (zend_function *)cached;
2,925✔
339
} /* }}} */
340

341
zend_function *php_parallel_cache_closure(const zend_function *source, zend_function *closure)
2,889✔
342
{ /* {{{ */
343
        zend_op_array *cache;
2,889✔
344

345
        cache = (zend_op_array *)php_parallel_cache_function_ex((zend_function *)source, 0);
2,889✔
346

347
        if (!closure) {
2,889✔
348
                closure = php_parallel_copy_mem(cache, sizeof(zend_op_array), 1);
2,217✔
349
        } else {
350
                memcpy(closure, cache, sizeof(zend_op_array));
672✔
351
        }
352

353
        if (source->op_array.static_variables) {
2,889✔
354
                HashTable *statics = ZEND_MAP_PTR_GET(source->op_array.static_variables_ptr);
693✔
355

356
                if (statics) {
693✔
357
                        closure->op_array.static_variables = php_parallel_copy_hash_ctor(statics, 1);
558✔
358

359
#if PHP_VERSION_ID >= 80200
360
                        ZEND_MAP_PTR_INIT(closure->op_array.static_variables_ptr, closure->op_array.static_variables);
372✔
361
#else
362
                        ZEND_MAP_PTR_INIT(closure->op_array.static_variables_ptr, &closure->op_array.static_variables);
186✔
363
#endif
364
                }
365
        }
366

367
#if PHP_VERSION_ID >= 80100
368
        if (source->op_array.num_dynamic_func_defs) {
2,455✔
369
                uint32_t it = 0;
195✔
370
                /* Use regular persistent memory for dynamic_func_defs array, not cache pool */
371
                closure->op_array.dynamic_func_defs =
390✔
372
                    pemalloc(sizeof(zend_op_array *) * source->op_array.num_dynamic_func_defs, 1);
195✔
373
                memcpy(closure->op_array.dynamic_func_defs, source->op_array.dynamic_func_defs,
615✔
374
                       sizeof(zend_op_array *) * source->op_array.num_dynamic_func_defs);
195✔
375
                while (it < source->op_array.num_dynamic_func_defs) {
420✔
376
                        closure->op_array.dynamic_func_defs[it] = (zend_op_array *)php_parallel_cache_closure(
450✔
377
                            (zend_function *)source->op_array.dynamic_func_defs[it], NULL);
225✔
378
                        it++;
225✔
379
                }
380
        }
381
#endif
382

383
        return closure;
2,889✔
384
} /* }}} */
385

386
zend_function *php_parallel_cache_function(const zend_function *source)
36✔
387
{ /* {{{ */
388
        return php_parallel_cache_function_ex(source, 1);
36✔
389
} /* }}} */
390

391
/* {{{ */
392
PHP_MINIT_FUNCTION(PARALLEL_CACHE)
3,168✔
393
{
394
        zend_hash_init(&PCG(table), 32, NULL, NULL, 1);
3,168✔
395

396
        PCM(size) = PARALLEL_CACHE_CHUNK;
3,168✔
397
        PCM(mem) = PCM(block) = malloc(PCM(size));
3,168✔
398

399
        if (!PCM(mem)) {
3,168✔
400
                /* out of memory */
401
        }
3,168✔
402

403
        return SUCCESS;
3,168✔
404
}
405

406
PHP_MSHUTDOWN_FUNCTION(PARALLEL_CACHE)
3,168✔
407
{
408
        zend_hash_destroy(&PCG(table));
3,168✔
409

410
        if (PCM(mem)) {
3,168✔
411
                free(PCM(mem));
3,168✔
412
        }
413

414
        return SUCCESS;
3,168✔
415
} /* }}} */
416
#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

© 2025 Coveralls, Inc