Skip to content

Commit b712606

Browse files
committed
decoder: Optimise creating PHP objects
1 parent da26266 commit b712606

File tree

2 files changed

+37
-18
lines changed

2 files changed

+37
-18
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010

1111
| Operation | PHP Built-in | simdjson_php | Speedup |
1212
|-----------------------|--------------|--------------|----------|
13-
| Decode to array | 1.48 ms | 0.49 ms | **3.0×** |
14-
| Decode to object | 1.59 ms | 0.69 ms | **2.3×** |
13+
| Decode to array | 1.48 ms | 0.46 ms | **3.2×** |
14+
| Decode to object | 1.56 ms | 0.54 ms | **2.9×** |
1515
| Encode | 0.67 ms | 0.26 ms | **2.5×** |
1616
| Encode (pretty print) | 0.83 ms | 0.31 ms | **2.6×** |
1717
| Validate | 1.37 ms | 0.22 ms | **6.2×** |

src/simdjson_decoder.cpp

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ static zend_always_inline void simdjson_hash_str_add_or_update(HashTable *ht, co
312312
zend_ulong h;
313313

314314
// Check if array is initialized with proper flags and size
315-
// These checks are removed in production code
315+
// Note: These assertions are automatically removed in production builds
316316
ZEND_ASSERT(!(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED)); // make sure that hashtable was initialized
317317
ZEND_ASSERT(!(HT_FLAGS(ht) & HASH_FLAG_PACKED)); // make sure that hashtable is not packed
318318
ZEND_ASSERT(ht->nNumUsed < ht->nTableSize); // make sure that we still have space for new elements
@@ -372,6 +372,38 @@ static zend_always_inline void simdjson_add_key_to_symtable(HashTable *ht, const
372372
#endif // PHP_VERSION_ID >= 80200
373373
}
374374

375+
/**
376+
* Optimized function for adding keys to objects with built-in memory management.
377+
* - Uses interned strings for keys <= 1 byte to reduce memory allocation
378+
* - Implements version-specific optimizations for PHP 8.3+ and 8.2+
379+
* - Handles string deduplication for short keys
380+
*/
381+
static zend_always_inline void simdjson_add_key_to_object(HashTable *ht, const char *str, size_t len, zval *value, HashTable *dedup_key_strings) {
382+
#if PHP_VERSION_ID >= 80300 // see simdjson_init_object
383+
if (UNEXPECTED(len <= 1)) {
384+
// Use interned string
385+
zend_string *key = len == 1 ? ZSTR_CHAR((unsigned char)str[0]) : ZSTR_EMPTY_ALLOC();
386+
zend_hash_update(ht, key, value);
387+
} else {
388+
simdjson_hash_str_add_or_update(ht, str, len, value, dedup_key_strings);
389+
}
390+
#else
391+
zend_string *key;
392+
if (UNEXPECTED(len <= 1)) {
393+
key = len == 1 ? ZSTR_CHAR((unsigned char)str[0]) : ZSTR_EMPTY_ALLOC();
394+
} else {
395+
#if PHP_VERSION_ID >= 80200
396+
zend_ulong h = zend_inline_hash_func(str, len);
397+
key = simdjson_dedup_key(dedup_key_strings, str, len, h);
398+
#else
399+
key = simdjson_string_init(str, len);
400+
#endif // PHP_VERSION_ID >= 80200
401+
}
402+
zend_hash_update(ht, key, value);
403+
zend_string_release_ex(key, 0);
404+
#endif // PHP_VERSION_ID >= 80300
405+
}
406+
375407
static zend_always_inline void simdjson_set_zval_to_int64(zval *zv, int64_t value) {
376408
#if SIZEOF_ZEND_LONG < 8
377409
if (value != (zend_long)value) {
@@ -509,6 +541,7 @@ static simdjson_php_error_code simdjson_create_object(simdjson::dom::element ele
509541
case simdjson::dom::element_type::OBJECT : {
510542
const auto json_object = element.get_object().value_unsafe();
511543
zend_object *obj = simdjson_init_object(return_value, json_object.size());
544+
HashTable *ht = zend_std_get_properties(obj);
512545

513546
for (simdjson::dom::key_value_pair field : json_object) {
514547
const char *data = field.key.data();
@@ -527,21 +560,7 @@ static simdjson_php_error_code simdjson_create_object(simdjson::dom::element ele
527560
return error;
528561
}
529562

530-
/* Add the key to the object */
531-
zend_string *key;
532-
if (UNEXPECTED(size <= 1)) {
533-
key = size == 1 ? ZSTR_CHAR((unsigned char)data[0]) : ZSTR_EMPTY_ALLOC();
534-
} else {
535-
#if PHP_VERSION_ID >= 80200
536-
zend_ulong h = zend_inline_hash_func(data, size);
537-
key = simdjson_dedup_key(dedup_key_strings, data, size, h);
538-
#else
539-
key = simdjson_string_init(data, size);
540-
#endif
541-
}
542-
543-
zend_hash_update(zend_std_get_properties(obj), key, &value);
544-
zend_string_release_ex(key, 0);
563+
simdjson_add_key_to_object(ht, data, size, &value, dedup_key_strings);
545564
}
546565
break;
547566
}

0 commit comments

Comments
 (0)