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

krakjoe / parallel / 20135157308

11 Dec 2025 01:43PM UTC coverage: 94.351% (-2.5%) from 96.877%
20135157308

Pull #354

github

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

56 of 56 new or added lines in 3 files covered. (100.0%)

78 existing lines in 3 files now uncovered.

2923 of 3098 relevant lines covered (94.35%)

379.48 hits per line

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

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

46
    ZEND_ASSERT(size < PARALLEL_CACHE_CHUNK);
169✔
47

48
    if ((PCM(used) + aligned) >= PCM(size)) {
169✔
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);
169✔
62
    PCM(block) =
169✔
63
        (void*)(((char*)PCM(block)) + aligned);
169✔
64
    PCM(used) += aligned;
169✔
65

66
    return mem;
169✔
67
}
68

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

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

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

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

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

85
    cached = php_parallel_copy_hash_persistent(
1✔
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);
1✔
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) {
149✔
127
    zend_op_array *cached = php_parallel_cache_copy_mem((void*) source, sizeof(zend_op_array));
149✔
128

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

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

136
#if PHP_VERSION_ID >= 80200
137
    ZEND_MAP_PTR_INIT(cached->static_variables_ptr, cached->static_variables);
149✔
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);
149✔
143

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

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

165
    cached->refcount  = NULL;
3✔
166

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

174
        cached->literals = slot;
3✔
175

176
        while (literal < end) {
9✔
177
            if (Z_TYPE_P(literal) == IS_ARRAY) {
6✔
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));
183
            } else if (Z_TYPE_P(literal) == IS_STRING) {
6✔
184
                ZVAL_STR(slot,
3✔
185
                    php_parallel_copy_string_interned(Z_STR_P(literal)));
186
            }
187

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

194
    if (cached->last_var) {
3✔
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

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

213
        while (opline < end) {
11✔
214
            if (opline->op1_type == IS_CONST) {
8✔
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
218
                opline->op1.constant =
4✔
219
                    (char*)(cached->literals +
4✔
220
                            ((zval*)((char*)(source->op_array.opcodes + (opline - opcodes)) +
4✔
221
                            (int32_t)opline->op1.constant) - source->op_array.literals)) -
4✔
222
                            (char*)opline;
223
#endif
224
                if (opline->opcode == ZEND_SEND_VAL
4✔
225
                 || opline->opcode == ZEND_SEND_VAL_EX
4✔
226
                 || opline->opcode == ZEND_QM_ASSIGN) {
4✔
UNCOV
227
                    zend_vm_set_opcode_handler_ex(opline, 0, 0, 0);
×
228
                }
229
            }
230
            if (opline->op2_type == IS_CONST) {
8✔
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
234
                opline->op2.constant =
2✔
235
                    (char*)(cached->literals +
2✔
236
                            ((zval*)((char*)(source->op_array.opcodes + (opline - opcodes)) +
2✔
237
                            (int32_t)opline->op2.constant) - source->op_array.literals)) -
2✔
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

270
            opline++;
8✔
271
        }
272
        cached->opcodes = opcodes;
3✔
273
    }
274

275
    if (cached->arg_info) {
3✔
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

305
    if (cached->try_catch_array) {
3✔
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

312
    if (cached->live_range) {
3✔
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

319
    if (cached->function_name)
3✔
320
        cached->function_name =
3✔
321
            php_parallel_copy_string_interned(cached->function_name);
3✔
322

323
    if (cached->filename)
3✔
324
        cached->filename =
3✔
325
            php_parallel_copy_string_interned(cached->filename);
3✔
326

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

331
_php_parallel_cached_function_return:
3✔
332
    return cached;
149✔
333
} /* }}} */
334

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

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

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

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

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

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

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

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

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

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

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

382
#if PHP_VERSION_ID >= 80200
383
        ZEND_MAP_PTR_INIT(
30✔
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) {
167✔
396
        uint32_t it = 0;
13✔
397
        /* Use regular persistent memory for dynamic_func_defs array, not cache pool */
398
        closure->op_array.dynamic_func_defs = pemalloc(
13✔
399
            sizeof(zend_op_array*) * source->op_array.num_dynamic_func_defs, 1);
400
        memcpy(closure->op_array.dynamic_func_defs,
41✔
401
            source->op_array.dynamic_func_defs,
13✔
402
            sizeof(zend_op_array*) * source->op_array.num_dynamic_func_defs);
13✔
403
        while (it < source->op_array.num_dynamic_func_defs) {
28✔
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);
15✔
405
            it++;
15✔
406
        }
407
    }
408
#endif
409

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

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

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

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

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

431
    return SUCCESS;
160✔
432
}
433

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

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

441
    return SUCCESS;
160✔
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