Skip to content

Commit 79133df

Browse files
authored
random: Pass algorithm and state together as php_random_algo_with_state (#13350)
* random: Remove `php_random_status` Since 162e1dc, the `php_random_status` struct contains just a single `void*`, resulting in needless indirection when accessing the engine state and thus decreasing readability because of the additional non-meaningful `->state` references / the local helper variables. There is also a small, but measurable performance benefit: <?php $e = new Random\Engine\Xoshiro256StarStar(0); $r = new Random\Randomizer($e); for ($i = 0; $i < 15; $i++) var_dump(strlen($r->getBytes(100000000))); goes from roughly 3.85s down to 3.60s. The names of the `status` variables have not yet been touched to keep the diff small. They will be renamed to the more appropriate `state` in a follow-up cleanup commit. * Introduce `php_random_algo_with_state`
1 parent d024dd3 commit 79133df

15 files changed

+211
-171
lines changed

UPGRADING.INTERNALS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,13 @@ PHP 8.4 INTERNALS UPGRADE NOTES
109109
the new php_random_result struct, replacing the last_generated_size
110110
member of the php_random_status struct and the generate_size member of
111111
the php_random_algo struct.
112+
- The php_random_status struct has been removed, since the previous change
113+
reduced it to a single void* member containing the actual state, resulting
114+
in needless indirection. Functions taking a php_random_algo struct pointer
115+
and a php_random_status struct pointer as separate parameters now take a
116+
single php_random_algo_with_state struct by value, making it easier to
117+
pass around the state with its associated algorithm and thus reducing
118+
the chance for mistakes.
112119
- The CSPRNG API (php_random_(bytes|int)_*) is now provided by the new
113120
and much smaller php_random_csprng.h header. The new header is included
114121
in php_random.h for compatibility with existing users.

ext/random/engine_combinedlcg.c

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,17 @@
3232
*/
3333
#define MODMULT(a, b, c, m, s) q = s / a; s = b * (s - a * q) - c * q; if (s < 0) s += m
3434

35-
static void seed(php_random_status *status, uint64_t seed)
35+
static void seed(void *status, uint64_t seed)
3636
{
37-
php_random_status_state_combinedlcg *s = status->state;
37+
php_random_status_state_combinedlcg *s = status;
3838

3939
s->state[0] = seed & 0xffffffffU;
4040
s->state[1] = seed >> 32;
4141
}
4242

43-
static php_random_result generate(php_random_status *status)
43+
static php_random_result generate(void *status)
4444
{
45-
php_random_status_state_combinedlcg *s = status->state;
45+
php_random_status_state_combinedlcg *s = status;
4646
int32_t q, z;
4747

4848
MODMULT(53668, 40014, 12211, 2147483563L, s->state[0]);
@@ -59,14 +59,17 @@ static php_random_result generate(php_random_status *status)
5959
};
6060
}
6161

62-
static zend_long range(php_random_status *status, zend_long min, zend_long max)
62+
static zend_long range(void *status, zend_long min, zend_long max)
6363
{
64-
return php_random_range(&php_random_algo_combinedlcg, status, min, max);
64+
return php_random_range((php_random_algo_with_state){
65+
.algo = &php_random_algo_combinedlcg,
66+
.status = status,
67+
}, min, max);
6568
}
6669

67-
static bool serialize(php_random_status *status, HashTable *data)
70+
static bool serialize(void *status, HashTable *data)
6871
{
69-
php_random_status_state_combinedlcg *s = status->state;
72+
php_random_status_state_combinedlcg *s = status;
7073
zval t;
7174

7275
for (uint32_t i = 0; i < 2; i++) {
@@ -77,9 +80,9 @@ static bool serialize(php_random_status *status, HashTable *data)
7780
return true;
7881
}
7982

80-
static bool unserialize(php_random_status *status, HashTable *data)
83+
static bool unserialize(void *status, HashTable *data)
8184
{
82-
php_random_status_state_combinedlcg *s = status->state;
85+
php_random_status_state_combinedlcg *s = status;
8386
zval *t;
8487

8588
for (uint32_t i = 0; i < 2; i++) {

ext/random/engine_mt19937.c

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -139,14 +139,14 @@ static inline void mt19937_seed_state(php_random_status_state_mt19937 *state, ui
139139
mt19937_reload(state);
140140
}
141141

142-
static void seed(php_random_status *status, uint64_t seed)
142+
static void seed(void *status, uint64_t seed)
143143
{
144-
mt19937_seed_state(status->state, seed);
144+
mt19937_seed_state(status, seed);
145145
}
146146

147-
static php_random_result generate(php_random_status *status)
147+
static php_random_result generate(void *status)
148148
{
149-
php_random_status_state_mt19937 *s = status->state;
149+
php_random_status_state_mt19937 *s = status;
150150
uint32_t s1;
151151

152152
if (s->count >= MT_N) {
@@ -164,14 +164,17 @@ static php_random_result generate(php_random_status *status)
164164
};
165165
}
166166

167-
static zend_long range(php_random_status *status, zend_long min, zend_long max)
167+
static zend_long range(void *status, zend_long min, zend_long max)
168168
{
169-
return php_random_range(&php_random_algo_mt19937, status, min, max);
169+
return php_random_range((php_random_algo_with_state){
170+
.algo = &php_random_algo_mt19937,
171+
.status = status,
172+
}, min, max);
170173
}
171174

172-
static bool serialize(php_random_status *status, HashTable *data)
175+
static bool serialize(void *status, HashTable *data)
173176
{
174-
php_random_status_state_mt19937 *s = status->state;
177+
php_random_status_state_mt19937 *s = status;
175178
zval t;
176179

177180
for (uint32_t i = 0; i < MT_N; i++) {
@@ -186,9 +189,9 @@ static bool serialize(php_random_status *status, HashTable *data)
186189
return true;
187190
}
188191

189-
static bool unserialize(php_random_status *status, HashTable *data)
192+
static bool unserialize(void *status, HashTable *data)
190193
{
191-
php_random_status_state_mt19937 *s = status->state;
194+
php_random_status_state_mt19937 *s = status;
192195
zval *t;
193196

194197
/* Verify the expected number of elements, this implicitly ensures that no additional elements are present. */
@@ -251,8 +254,8 @@ PHPAPI void php_random_mt19937_seed_default(php_random_status_state_mt19937 *sta
251254
/* {{{ Random\Engine\Mt19937::__construct() */
252255
PHP_METHOD(Random_Engine_Mt19937, __construct)
253256
{
254-
php_random_engine *engine = Z_RANDOM_ENGINE_P(ZEND_THIS);
255-
php_random_status_state_mt19937 *state = engine->status->state;
257+
php_random_algo_with_state engine = Z_RANDOM_ENGINE_P(ZEND_THIS)->engine;
258+
php_random_status_state_mt19937 *state = engine.status;
256259
zend_long seed, mode = MT_RAND_MT19937;
257260
bool seed_is_null = true;
258261

@@ -290,12 +293,12 @@ PHP_METHOD(Random_Engine_Mt19937, __construct)
290293
/* {{{ Random\Engine\Mt19937::generate() */
291294
PHP_METHOD(Random_Engine_Mt19937, generate)
292295
{
293-
php_random_engine *engine = Z_RANDOM_ENGINE_P(ZEND_THIS);
296+
php_random_algo_with_state engine = Z_RANDOM_ENGINE_P(ZEND_THIS)->engine;
294297
zend_string *bytes;
295298

296299
ZEND_PARSE_PARAMETERS_NONE();
297300

298-
php_random_result generated = engine->algo->generate(engine->status);
301+
php_random_result generated = engine.algo->generate(engine.status);
299302
if (EG(exception)) {
300303
RETURN_THROWS();
301304
}
@@ -329,7 +332,7 @@ PHP_METHOD(Random_Engine_Mt19937, __serialize)
329332

330333
/* state */
331334
array_init(&t);
332-
if (!engine->algo->serialize(engine->status, Z_ARRVAL(t))) {
335+
if (!engine->engine.algo->serialize(engine->engine.status, Z_ARRVAL(t))) {
333336
zend_throw_exception(NULL, "Engine serialize failed", 0);
334337
RETURN_THROWS();
335338
}
@@ -372,7 +375,7 @@ PHP_METHOD(Random_Engine_Mt19937, __unserialize)
372375
zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(engine->std.ce->name));
373376
RETURN_THROWS();
374377
}
375-
if (!engine->algo->unserialize(engine->status, Z_ARRVAL_P(t))) {
378+
if (!engine->engine.algo->unserialize(engine->engine.status, Z_ARRVAL_P(t))) {
376379
zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(engine->std.ce->name));
377380
RETURN_THROWS();
378381
}
@@ -392,9 +395,9 @@ PHP_METHOD(Random_Engine_Mt19937, __debugInfo)
392395
}
393396
ZVAL_ARR(return_value, zend_array_dup(engine->std.properties));
394397

395-
if (engine->algo->serialize) {
398+
if (engine->engine.algo->serialize) {
396399
array_init(&t);
397-
if (!engine->algo->serialize(engine->status, Z_ARRVAL(t))) {
400+
if (!engine->engine.algo->serialize(engine->engine.status, Z_ARRVAL(t))) {
398401
zend_throw_exception(NULL, "Engine serialize failed", 0);
399402
RETURN_THROWS();
400403
}

ext/random/engine_pcgoneseq128xslrr64.c

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,14 @@ static inline void seed128(php_random_status_state_pcgoneseq128xslrr64 *s, php_r
4343
step(s);
4444
}
4545

46-
static void seed(php_random_status *status, uint64_t seed)
46+
static void seed(void *status, uint64_t seed)
4747
{
48-
seed128(status->state, php_random_uint128_constant(0ULL, seed));
48+
seed128(status, php_random_uint128_constant(0ULL, seed));
4949
}
5050

51-
static php_random_result generate(php_random_status *status)
51+
static php_random_result generate(void *status)
5252
{
53-
php_random_status_state_pcgoneseq128xslrr64 *s = status->state;
53+
php_random_status_state_pcgoneseq128xslrr64 *s = status;
5454

5555
step(s);
5656

@@ -60,14 +60,17 @@ static php_random_result generate(php_random_status *status)
6060
};
6161
}
6262

63-
static zend_long range(php_random_status *status, zend_long min, zend_long max)
63+
static zend_long range(void *status, zend_long min, zend_long max)
6464
{
65-
return php_random_range(&php_random_algo_pcgoneseq128xslrr64, status, min, max);
65+
return php_random_range((php_random_algo_with_state){
66+
.algo = &php_random_algo_pcgoneseq128xslrr64,
67+
.status = status,
68+
}, min, max);
6669
}
6770

68-
static bool serialize(php_random_status *status, HashTable *data)
71+
static bool serialize(void *status, HashTable *data)
6972
{
70-
php_random_status_state_pcgoneseq128xslrr64 *s = status->state;
73+
php_random_status_state_pcgoneseq128xslrr64 *s = status;
7174
uint64_t u;
7275
zval z;
7376

@@ -82,9 +85,9 @@ static bool serialize(php_random_status *status, HashTable *data)
8285
return true;
8386
}
8487

85-
static bool unserialize(php_random_status *status, HashTable *data)
88+
static bool unserialize(void *status, HashTable *data)
8689
{
87-
php_random_status_state_pcgoneseq128xslrr64 *s = status->state;
90+
php_random_status_state_pcgoneseq128xslrr64 *s = status;
8891
uint64_t u[2];
8992
zval *t;
9093

@@ -142,8 +145,8 @@ PHPAPI void php_random_pcgoneseq128xslrr64_advance(php_random_status_state_pcgon
142145
/* {{{ Random\Engine\PcgOneseq128XslRr64::__construct */
143146
PHP_METHOD(Random_Engine_PcgOneseq128XslRr64, __construct)
144147
{
145-
php_random_engine *engine = Z_RANDOM_ENGINE_P(ZEND_THIS);
146-
php_random_status_state_pcgoneseq128xslrr64 *state = engine->status->state;
148+
php_random_algo_with_state engine = Z_RANDOM_ENGINE_P(ZEND_THIS)->engine;
149+
php_random_status_state_pcgoneseq128xslrr64 *state = engine.status;
147150
zend_string *str_seed = NULL;
148151
zend_long int_seed = 0;
149152
bool seed_is_null = true;
@@ -191,8 +194,8 @@ PHP_METHOD(Random_Engine_PcgOneseq128XslRr64, __construct)
191194
/* {{{ Random\Engine\PcgOneseq128XslRr64::jump() */
192195
PHP_METHOD(Random_Engine_PcgOneseq128XslRr64, jump)
193196
{
194-
php_random_engine *engine = Z_RANDOM_ENGINE_P(ZEND_THIS);
195-
php_random_status_state_pcgoneseq128xslrr64 *state = engine->status->state;
197+
php_random_algo_with_state engine = Z_RANDOM_ENGINE_P(ZEND_THIS)->engine;
198+
php_random_status_state_pcgoneseq128xslrr64 *state = engine.status;
196199
zend_long advance = 0;
197200

198201
ZEND_PARSE_PARAMETERS_START(1, 1)

ext/random/engine_secure.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
#include "Zend/zend_exceptions.h"
2727

28-
static php_random_result generate(php_random_status *status)
28+
static php_random_result generate(void *status)
2929
{
3030
zend_ulong r = 0;
3131

@@ -37,7 +37,7 @@ static php_random_result generate(php_random_status *status)
3737
};
3838
}
3939

40-
static zend_long range(php_random_status *status, zend_long min, zend_long max)
40+
static zend_long range(void *status, zend_long min, zend_long max)
4141
{
4242
zend_long result = 0;
4343

ext/random/engine_user.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121
#include "php.h"
2222
#include "php_random.h"
2323

24-
static php_random_result generate(php_random_status *status)
24+
static php_random_result generate(void *status)
2525
{
26-
php_random_status_state_user *s = status->state;
26+
php_random_status_state_user *s = status;
2727
uint64_t result = 0;
2828
size_t size;
2929
zval retval;
@@ -65,9 +65,12 @@ static php_random_result generate(php_random_status *status)
6565
};
6666
}
6767

68-
static zend_long range(php_random_status *status, zend_long min, zend_long max)
68+
static zend_long range(void *status, zend_long min, zend_long max)
6969
{
70-
return php_random_range(&php_random_algo_user, status, min, max);
70+
return php_random_range((php_random_algo_with_state){
71+
.algo = &php_random_algo_user,
72+
.status = status,
73+
}, min, max);
7174
}
7275

7376
const php_random_algo php_random_algo_user = {

ext/random/engine_xoshiro256starstar.c

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -102,27 +102,30 @@ static inline void seed64(php_random_status_state_xoshiro256starstar *state, uin
102102
seed256(state, s[0], s[1], s[2], s[3]);
103103
}
104104

105-
static void seed(php_random_status *status, uint64_t seed)
105+
static void seed(void *status, uint64_t seed)
106106
{
107-
seed64(status->state, seed);
107+
seed64(status, seed);
108108
}
109109

110-
static php_random_result generate(php_random_status *status)
110+
static php_random_result generate(void *status)
111111
{
112112
return (php_random_result){
113113
.size = sizeof(uint64_t),
114-
.result = generate_state(status->state),
114+
.result = generate_state(status),
115115
};
116116
}
117117

118-
static zend_long range(php_random_status *status, zend_long min, zend_long max)
118+
static zend_long range(void *status, zend_long min, zend_long max)
119119
{
120-
return php_random_range(&php_random_algo_xoshiro256starstar, status, min, max);
120+
return php_random_range((php_random_algo_with_state){
121+
.algo = &php_random_algo_xoshiro256starstar,
122+
.status = status,
123+
}, min, max);
121124
}
122125

123-
static bool serialize(php_random_status *status, HashTable *data)
126+
static bool serialize(void *status, HashTable *data)
124127
{
125-
php_random_status_state_xoshiro256starstar *s = status->state;
128+
php_random_status_state_xoshiro256starstar *s = status;
126129
zval t;
127130

128131
for (uint32_t i = 0; i < 4; i++) {
@@ -133,9 +136,9 @@ static bool serialize(php_random_status *status, HashTable *data)
133136
return true;
134137
}
135138

136-
static bool unserialize(php_random_status *status, HashTable *data)
139+
static bool unserialize(void *status, HashTable *data)
137140
{
138-
php_random_status_state_xoshiro256starstar *s = status->state;
141+
php_random_status_state_xoshiro256starstar *s = status;
139142
zval *t;
140143

141144
/* Verify the expected number of elements, this implicitly ensures that no additional elements are present. */
@@ -180,8 +183,8 @@ PHPAPI void php_random_xoshiro256starstar_jump_long(php_random_status_state_xosh
180183
/* {{{ Random\Engine\Xoshiro256StarStar::jump() */
181184
PHP_METHOD(Random_Engine_Xoshiro256StarStar, jump)
182185
{
183-
php_random_engine *engine = Z_RANDOM_ENGINE_P(ZEND_THIS);
184-
php_random_status_state_xoshiro256starstar *state = engine->status->state;
186+
php_random_algo_with_state engine = Z_RANDOM_ENGINE_P(ZEND_THIS)->engine;
187+
php_random_status_state_xoshiro256starstar *state = engine.status;
185188

186189
ZEND_PARSE_PARAMETERS_NONE();
187190

@@ -192,8 +195,8 @@ PHP_METHOD(Random_Engine_Xoshiro256StarStar, jump)
192195
/* {{{ Random\Engine\Xoshiro256StarStar::jumpLong() */
193196
PHP_METHOD(Random_Engine_Xoshiro256StarStar, jumpLong)
194197
{
195-
php_random_engine *engine = Z_RANDOM_ENGINE_P(ZEND_THIS);
196-
php_random_status_state_xoshiro256starstar *state = engine->status->state;
198+
php_random_algo_with_state engine = Z_RANDOM_ENGINE_P(ZEND_THIS)->engine;
199+
php_random_status_state_xoshiro256starstar *state = engine.status;
197200

198201
ZEND_PARSE_PARAMETERS_NONE();
199202

@@ -204,8 +207,8 @@ PHP_METHOD(Random_Engine_Xoshiro256StarStar, jumpLong)
204207
/* {{{ Random\Engine\Xoshiro256StarStar::__construct */
205208
PHP_METHOD(Random_Engine_Xoshiro256StarStar, __construct)
206209
{
207-
php_random_engine *engine = Z_RANDOM_ENGINE_P(ZEND_THIS);
208-
php_random_status_state_xoshiro256starstar *state = engine->status->state;
210+
php_random_algo_with_state engine = Z_RANDOM_ENGINE_P(ZEND_THIS)->engine;
211+
php_random_status_state_xoshiro256starstar *state = engine.status;
209212
zend_string *str_seed = NULL;
210213
zend_long int_seed = 0;
211214
bool seed_is_null = true;

0 commit comments

Comments
 (0)