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

krakjoe / parallel / 20132730441

11 Dec 2025 12:14PM UTC coverage: 91.259% (-5.6%) from 96.877%
20132730441

Pull #354

github

web-flow
Merge 7a5687216 into 3955f21f5
Pull Request #354: copy over functions from global function table

2 of 15 new or added lines in 1 file covered. (13.33%)

160 existing lines in 4 files now uncovered.

2819 of 3089 relevant lines covered (91.26%)

749.35 hits per line

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

42.56
/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) {
298✔
42
    void *mem;
298✔
43
    size_t aligned =
298✔
44
        PARALLEL_PLATFORM_ALIGNED(size);
24✔
45

46
    ZEND_ASSERT(size < PARALLEL_CACHE_CHUNK);
298✔
47

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

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

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

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

66
    return mem;
298✔
67
}
68

69
static zend_always_inline void* php_parallel_cache_copy_mem(void *source, zend_long size) {
298✔
70
    void *destination =
298✔
UNCOV
71
        php_parallel_cache_alloc(size);
×
72

73
    memcpy(destination, source, size);
298✔
74

75
    return destination;
298✔
76
} /* }}} */
77

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

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

UNCOV
85
    cached = php_parallel_copy_hash_persistent(
×
86
                statics,
87
                php_parallel_copy_string_interned,
88
                php_parallel_cache_copy_mem);
89

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

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

UNCOV
96
    if (!ZEND_TYPE_IS_SET(*type)) {
×
97
        return;
98
    }
99

UNCOV
100
    if (ZEND_TYPE_HAS_LIST(*type)) {
×
UNCOV
101
        zend_type_list *list = ZEND_TYPE_LIST(*type);
×
102

UNCOV
103
        list = php_parallel_cache_copy_mem(
×
UNCOV
104
                    list, ZEND_TYPE_LIST_SIZE(list->num_types));
×
105

UNCOV
106
        if (ZEND_TYPE_USES_ARENA(*type)) {
×
UNCOV
107
            ZEND_TYPE_FULL_MASK(*type) &= ~_ZEND_TYPE_ARENA_BIT;
×
108
        }
109
 
UNCOV
110
        ZEND_TYPE_SET_PTR(*type, list);
×
111
    }
112

UNCOV
113
    ZEND_TYPE_FOREACH(*type, single) {
×
UNCOV
114
        if (ZEND_TYPE_HAS_NAME(*single)) {
×
UNCOV
115
            zend_string *name = ZEND_TYPE_NAME(*single);
×
116

UNCOV
117
            ZEND_TYPE_SET_PTR(
×
118
                *single,
119
                php_parallel_copy_string_interned(name));
120
        }
UNCOV
121
    } ZEND_TYPE_FOREACH_END();
×
122
} /* }}} */
123

124

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

129
    cached->fn_flags |= ZEND_ACC_IMMUTABLE;
274✔
130

131
    if (statics && cached->static_variables) {
274✔
UNCOV
132
        cached->static_variables =
×
UNCOV
133
            php_parallel_cache_statics(cached->static_variables);
×
134
    }
135

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

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

144
#if PHP_VERSION_ID >= 80100
145
    if (cached->num_dynamic_func_defs) {
274✔
146
            uint32_t it = 0;
24✔
147
            
148
            cached->dynamic_func_defs = php_parallel_cache_copy_mem(
48✔
149
                                            cached->dynamic_func_defs,
24✔
150
                                            sizeof(zend_op_array*) * cached->num_dynamic_func_defs);
24✔
151
            
152
            while (it < cached->num_dynamic_func_defs) {
52✔
153
                cached->dynamic_func_defs[it] = 
56✔
154
                (zend_op_array*) php_parallel_cache_create(
28✔
155
                        (zend_function*) cached->dynamic_func_defs[it], statics);
28✔
156
            it++;
28✔
157
            }
158
    }
159
#endif
160

161
    if (!cached->refcount) {
274✔
162
        goto _php_parallel_cached_function_return;
274✔
163
    }
164

UNCOV
165
    cached->refcount  = NULL;
×
166

UNCOV
167
    if (cached->last_literal) {
×
UNCOV
168
        zval     *literal = cached->literals,
×
UNCOV
169
                 *end     = literal + cached->last_literal;
×
UNCOV
170
        zval     *slot    = php_parallel_cache_copy_mem(
×
UNCOV
171
                                    cached->literals,
×
172
                                        sizeof(zval) * cached->last_literal);
173

UNCOV
174
        cached->literals = slot;
×
175

UNCOV
176
        while (literal < end) {
×
UNCOV
177
            if (Z_TYPE_P(literal) == IS_ARRAY) {
×
UNCOV
178
                ZVAL_ARR(slot,
×
179
                    php_parallel_copy_hash_persistent(
180
                        Z_ARRVAL_P(literal),
181
                        php_parallel_copy_string_interned,
182
                        php_parallel_cache_copy_mem));
UNCOV
183
            } else if (Z_TYPE_P(literal) == IS_STRING) {
×
UNCOV
184
                ZVAL_STR(slot,
×
185
                    php_parallel_copy_string_interned(Z_STR_P(literal)));
186
            }
187

UNCOV
188
                Z_TYPE_FLAGS_P(slot) &= ~(IS_TYPE_REFCOUNTED|IS_TYPE_COLLECTABLE);
×
UNCOV
189
            literal++;
×
UNCOV
190
            slot++;
×
191
        }
192
    }
193

UNCOV
194
    if (cached->last_var) {
×
UNCOV
195
        zend_string **vars = cached->vars;
×
UNCOV
196
        uint32_t      it = 0,
×
UNCOV
197
                      end = cached->last_var;
×
UNCOV
198
        zend_string **heap = php_parallel_cache_alloc(cached->last_var * sizeof(zend_string*));
×
199

UNCOV
200
        while (it < end) {
×
UNCOV
201
            heap[it] =
×
UNCOV
202
                php_parallel_copy_string_interned(vars[it]);
×
UNCOV
203
            it++;
×
204
        }
UNCOV
205
        cached->vars = heap;
×
206
    }
207

UNCOV
208
    if (cached->last) {
×
UNCOV
209
        zend_op *opcodes = php_parallel_cache_copy_mem(cached->opcodes, sizeof(zend_op) * cached->last);
×
UNCOV
210
        zend_op *opline  = opcodes,
×
UNCOV
211
                *end     = opline + cached->last;
×
212

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

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

UNCOV
270
            opline++;
×
271
        }
UNCOV
272
        cached->opcodes = opcodes;
×
273
    }
274

UNCOV
275
    if (cached->arg_info) {
×
UNCOV
276
        zend_arg_info *it    = cached->arg_info,
×
UNCOV
277
                      *end   = it + cached->num_args,
×
278
                      *info;
279

UNCOV
280
        if (cached->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
×
UNCOV
281
            it--;
×
282
        }
UNCOV
283
        if (cached->fn_flags & ZEND_ACC_VARIADIC) {
×
UNCOV
284
            end++;
×
285
        }
286

UNCOV
287
        cached->arg_info = info = php_parallel_cache_copy_mem(it, (end - it) * sizeof(zend_arg_info));
×
288

UNCOV
289
         while (it < end) {
×
UNCOV
290
            if (info->name) {
×
UNCOV
291
                info->name =
×
UNCOV
292
                    php_parallel_copy_string_interned(it->name);
×
293
            }
294
            
UNCOV
295
            php_parallel_cache_type(&info->type);
×
296

UNCOV
297
            info++;
×
UNCOV
298
            it++;
×
299
        }
UNCOV
300
        if (cached->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
×
UNCOV
301
            cached->arg_info++;
×
302
        }
303
    }
304

UNCOV
305
    if (cached->try_catch_array) {
×
UNCOV
306
        cached->try_catch_array =
×
UNCOV
307
            php_parallel_cache_copy_mem(
×
UNCOV
308
                cached->try_catch_array,
×
UNCOV
309
                    sizeof(zend_try_catch_element) * cached->last_try_catch);
×
310
    }
311

UNCOV
312
    if (cached->live_range) {
×
UNCOV
313
        cached->live_range =
×
UNCOV
314
            php_parallel_cache_copy_mem(
×
UNCOV
315
                cached->live_range,
×
UNCOV
316
                sizeof(zend_live_range) * cached->last_live_range);
×
317
    }
318

UNCOV
319
    if (cached->function_name)
×
UNCOV
320
        cached->function_name =
×
UNCOV
321
            php_parallel_copy_string_interned(cached->function_name);
×
322

UNCOV
323
    if (cached->filename)
×
UNCOV
324
        cached->filename =
×
UNCOV
325
            php_parallel_copy_string_interned(cached->filename);
×
326

UNCOV
327
    if (cached->doc_comment)
×
UNCOV
328
        cached->doc_comment =
×
UNCOV
329
            php_parallel_copy_string_interned(cached->doc_comment);
×
330

UNCOV
331
_php_parallel_cached_function_return:
×
332
    return cached;
274✔
333
} /* }}} */
334

335
/* {{{ */
336
static zend_always_inline zend_function* php_parallel_cache_function_ex(const zend_function *source, zend_bool statics) {
322✔
337
    zend_op_array *cached;
322✔
338
    
339
    pthread_mutex_lock(&PCG(mutex));
322✔
340

341
    if ((cached = zend_hash_index_find_ptr(&PCG(table), (zend_ulong) source->op_array.opcodes))) {
398✔
342
        goto _php_parallel_cached_function_return;
76✔
343
    }
344

345
    cached = php_parallel_cache_create(source, statics);
246✔
346

347
    zend_hash_index_add_ptr(
568✔
348
        &PCG(table),
349
        (zend_ulong) source->op_array.opcodes, 
246✔
350
        cached);
351

352
_php_parallel_cached_function_return:
322✔
353
    pthread_mutex_unlock(&PCG(mutex));
322✔
354

355
    return (zend_function*) cached;
322✔
356
} /* }}} */
357

358
zend_function* php_parallel_cache_closure(const zend_function *source, zend_function *closure) { /* {{{ */
322✔
359
    zend_op_array *cache;
322✔
360

361
    cache =
322✔
362
        (zend_op_array*)
363
            php_parallel_cache_function_ex(
322✔
364
                (zend_function*) source, 0);
365

366
    if (!closure) {
322✔
367
        closure = php_parallel_copy_mem(
248✔
368
            cache, sizeof(zend_op_array), 1);
369
    } else {
370
        memcpy(closure, cache, sizeof(zend_op_array));
74✔
371
    }
372

373
    if (source->op_array.static_variables) {
322✔
374
        HashTable *statics =
156✔
375
            ZEND_MAP_PTR_GET(
78✔
376
                source->op_array.static_variables_ptr);
377

378
        if (statics) {
78✔
379
        closure->op_array.static_variables =
120✔
380
            php_parallel_copy_hash_ctor(statics, 1);
60✔
381

382
#if PHP_VERSION_ID >= 80200
383
        ZEND_MAP_PTR_INIT(
60✔
384
            closure->op_array.static_variables_ptr,
385
            closure->op_array.static_variables);
386
#else
387
        ZEND_MAP_PTR_INIT(
388
            closure->op_array.static_variables_ptr,
389
            &closure->op_array.static_variables);
390
#endif
391
        }
392
    }
393

394
#if PHP_VERSION_ID >= 80100
395
    if (source->op_array.num_dynamic_func_defs) {
322✔
396
        uint32_t it = 0;
26✔
397
        /* Use regular persistent memory for dynamic_func_defs array, not cache pool */
398
        closure->op_array.dynamic_func_defs = pemalloc(
26✔
399
            sizeof(zend_op_array*) * source->op_array.num_dynamic_func_defs, 1);
400
        memcpy(closure->op_array.dynamic_func_defs,
82✔
401
            source->op_array.dynamic_func_defs,
26✔
402
            sizeof(zend_op_array*) * source->op_array.num_dynamic_func_defs);
26✔
403
        while (it < source->op_array.num_dynamic_func_defs) {
56✔
404
            closure->op_array.dynamic_func_defs[it] = (zend_op_array*) php_parallel_cache_closure((zend_function*) source->op_array.dynamic_func_defs[it], NULL);
30✔
405
            it++;
30✔
406
        }
407
    }
408
#endif
409

410
    return closure;
322✔
411
} /* }}} */
412

UNCOV
413
zend_function* php_parallel_cache_function(const zend_function *source) { /* {{{ */
×
UNCOV
414
    return php_parallel_cache_function_ex(source, 1);
×
415
} /* }}} */
416

417
/* {{{ */
418
PHP_MINIT_FUNCTION(PARALLEL_CACHE)
306✔
419
{
420
    zend_hash_init(&PCG(table), 32, NULL, NULL, 1);
306✔
421

422
    PCM(size) = PARALLEL_CACHE_CHUNK;
306✔
423
    PCM(mem) =
306✔
424
        PCM(block) =
306✔
425
            malloc(PCM(size));
306✔
426

427
    if (!PCM(mem)) {
306✔
428
        /* out of memory */
429
    }
306✔
430

431
    return SUCCESS;
306✔
432
}
433

434
PHP_MSHUTDOWN_FUNCTION(PARALLEL_CACHE)
306✔
435
{
436
    zend_hash_destroy(&PCG(table));
306✔
437

438
    if (PCM(mem))
306✔
439
        free(PCM(mem));
306✔
440

441
    return SUCCESS;
306✔
442
} /* }}} */
443
#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