Skip to content

Commit 6d573e0

Browse files
committed
implementation of is_noble
1 parent 182e3ac commit 6d573e0

27 files changed

+1414
-555
lines changed

Zend/zend_compile.c

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,8 @@ static inline int zend_add_literal_string(zend_string **str) /* {{{ */
546546
{
547547
int ret;
548548
zval zv;
549+
*str = zend_string_set_noble(*str);
550+
549551
ZVAL_STR(&zv, *str);
550552
ret = zend_add_literal(&zv);
551553
*str = Z_STR(zv);
@@ -3821,7 +3823,21 @@ static zend_result zend_compile_func_is_scalar(znode *result, zend_ast_list *arg
38213823
opline = zend_emit_op_tmp(result, ZEND_TYPE_CHECK, &arg_node, NULL);
38223824
opline->extended_value = (1 << IS_FALSE | 1 << IS_TRUE | 1 << IS_DOUBLE | 1 << IS_LONG | 1 << IS_STRING);
38233825
return SUCCESS;
3824-
}
3826+
} /* }}} */
3827+
3828+
static zend_result zend_compile_func_is_noble(znode *result, zend_ast_list *args) /* {{{ */
3829+
{
3830+
znode arg_node;
3831+
3832+
if (args->children != 1) {
3833+
return FAILURE;
3834+
}
3835+
3836+
zend_compile_expr(&arg_node, args->child[0]);
3837+
zend_emit_op(result, ZEND_NOBLE_CHECK, &arg_node, NULL);
3838+
3839+
return SUCCESS;
3840+
} /* }}} */
38253841

38263842
zend_result zend_compile_func_cast(znode *result, zend_ast_list *args, uint32_t type) /* {{{ */
38273843
{
@@ -4352,6 +4368,8 @@ zend_result zend_try_compile_special_func(znode *result, zend_string *lcname, ze
43524368
return zend_compile_func_typecheck(result, args, IS_RESOURCE);
43534369
} else if (zend_string_equals_literal(lcname, "is_scalar")) {
43544370
return zend_compile_func_is_scalar(result, args);
4371+
} else if (zend_string_equals_literal(lcname, "is_noble")) {
4372+
return zend_compile_func_is_noble(result, args);
43554373
} else if (zend_string_equals_literal(lcname, "boolval")) {
43564374
return zend_compile_func_cast(result, args, _IS_BOOL);
43574375
} else if (zend_string_equals_literal(lcname, "intval")) {
@@ -6384,6 +6402,8 @@ static void zend_compile_attributes(HashTable **attributes, zend_ast *ast, uint3
63846402
zend_string *name = zend_resolve_class_name_ast(el->child[0]);
63856403
zend_ast_list *args = el->child[1] ? zend_ast_get_list(el->child[1]) : NULL;
63866404

6405+
ZSTR_SET_NOBLE(&name);
6406+
63876407
uint32_t flags = (CG(active_op_array)->fn_flags & ZEND_ACC_STRICT_TYPES)
63886408
? ZEND_ATTRIBUTE_STRICT_TYPES : 0;
63896409
attr = zend_add_attribute(
@@ -6409,6 +6429,8 @@ static void zend_compile_attributes(HashTable **attributes, zend_ast *ast, uint3
64096429
arg_ast_ptr = &arg_ast->child[1];
64106430
uses_named_args = 1;
64116431

6432+
ZSTR_SET_NOBLE(&attr->args[j].name);
6433+
64126434
for (uint32_t k = 0; k < j; k++) {
64136435
if (attr->args[k].name &&
64146436
zend_string_equals(attr->args[k].name, attr->args[j].name)) {
@@ -6422,6 +6444,10 @@ static void zend_compile_attributes(HashTable **attributes, zend_ast *ast, uint3
64226444
}
64236445

64246446
zend_const_expr_to_zval(&attr->args[j].value, arg_ast_ptr);
6447+
6448+
if (Z_TYPE(attr->args[j].value) == IS_STRING) {
6449+
ZSTR_SET_NOBLE(&Z_STR(attr->args[j].value));
6450+
}
64256451
}
64266452
}
64276453
}
@@ -6964,6 +6990,7 @@ zend_string *zend_begin_method_decl(zend_op_array *op_array, zend_string *name,
69646990

69656991
op_array->scope = ce;
69666992
op_array->function_name = zend_string_copy(name);
6993+
ZSTR_SET_NOBLE(&op_array->function_name);
69676994

69686995
lcname = zend_string_tolower(name);
69696996
lcname = zend_new_interned_string(lcname);
@@ -6998,6 +7025,8 @@ static void zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_as
69987025

69997026
unqualified_name = decl->name;
70007027
op_array->function_name = name = zend_prefix_with_ns(unqualified_name);
7028+
7029+
ZSTR_SET_NOBLE(&op_array->function_name);
70017030
lcname = zend_string_tolower(name);
70027031

70037032
if (FC(imports_function)) {
@@ -7244,12 +7273,19 @@ void zend_compile_prop_decl(zend_ast *ast, zend_ast *type_ast, uint32_t flags, z
72447273
ZSTR_VAL(ce->name), ZSTR_VAL(name), ZSTR_VAL(str));
72457274
}
72467275
}
7276+
if (Z_TYPE(value_zv) == IS_STRING) {
7277+
ZSTR_SET_NOBLE(&Z_STR(value_zv));
7278+
}
72477279
} else if (!ZEND_TYPE_IS_SET(type)) {
72487280
ZVAL_NULL(&value_zv);
72497281
} else {
72507282
ZVAL_UNDEF(&value_zv);
72517283
}
72527284

7285+
if (Z_TYPE(value_zv) == IS_STRING) {
7286+
ZSTR_SET_NOBLE(&Z_STR(value_zv));
7287+
}
7288+
72537289
info = zend_declare_typed_property(ce, name, &value_zv, flags, doc_comment, type);
72547290

72557291
if (attr_ast) {
@@ -8364,11 +8400,20 @@ static bool zend_try_ct_eval_array(zval *result, zend_ast *ast) /* {{{ */
83648400
}
83658401
}
83668402

8403+
if (Z_TYPE_P(value) == IS_STRING) {
8404+
ZSTR_SET_NOBLE(&Z_STR_P(value));
8405+
}
8406+
83678407
Z_TRY_ADDREF_P(value);
83688408

83698409
key_ast = elem_ast->child[1];
83708410
if (key_ast) {
83718411
zval *key = zend_ast_get_zval(key_ast);
8412+
8413+
if (Z_TYPE_P(key) == IS_STRING) {
8414+
ZSTR_SET_NOBLE(&Z_STR_P(key));
8415+
}
8416+
83728417
switch (Z_TYPE_P(key)) {
83738418
case IS_LONG:
83748419
zend_hash_index_update(Z_ARRVAL_P(result), Z_LVAL_P(key), value);

Zend/zend_operators.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1859,10 +1859,15 @@ ZEND_API zend_result ZEND_FASTCALL concat_function(zval *result, zval *op1, zval
18591859
{
18601860
zval *orig_op1 = op1;
18611861
zval op1_copy, op2_copy;
1862-
1862+
bool noble = false;
1863+
18631864
ZVAL_UNDEF(&op1_copy);
18641865
ZVAL_UNDEF(&op2_copy);
18651866

1867+
if (UNEXPECTED(Z_IS_NOBLE_P(op1) && Z_IS_NOBLE_P(op2))) {
1868+
noble = true;
1869+
}
1870+
18661871
do {
18671872
if (UNEXPECTED(Z_TYPE_P(op1) != IS_STRING)) {
18681873
if (Z_ISREF_P(op1)) {
@@ -1913,13 +1918,23 @@ ZEND_API zend_result ZEND_FASTCALL concat_function(zval *result, zval *op1, zval
19131918
}
19141919
ZVAL_COPY(result, op2);
19151920
}
1921+
if (noble) {
1922+
ZSTR_SET_NOBLE(&Z_STR_P(result));
1923+
} else {
1924+
ZSTR_UNSET_NOBLE(&Z_STR_P(result));
1925+
}
19161926
} else if (UNEXPECTED(Z_STRLEN_P(op2) == 0)) {
19171927
if (EXPECTED(result != op1)) {
19181928
if (result == orig_op1) {
19191929
i_zval_ptr_dtor(result);
19201930
}
19211931
ZVAL_COPY(result, op1);
19221932
}
1933+
if (noble) {
1934+
ZSTR_SET_NOBLE(&Z_STR_P(result));
1935+
} else {
1936+
ZSTR_UNSET_NOBLE(&Z_STR_P(result));
1937+
}
19231938
} else {
19241939
size_t op1_len = Z_STRLEN_P(op1);
19251940
size_t op2_len = Z_STRLEN_P(op2);
@@ -1939,12 +1954,18 @@ ZEND_API zend_result ZEND_FASTCALL concat_function(zval *result, zval *op1, zval
19391954
if (result == op1 && Z_REFCOUNTED_P(result)) {
19401955
/* special case, perform operations on result */
19411956
result_str = zend_string_extend(Z_STR_P(result), result_len, 0);
1957+
if (UNEXPECTED(!noble && ZSTR_IS_NOBLE(result_str))) {
1958+
ZSTR_UNSET_NOBLE(&result_str);
1959+
}
19421960
} else {
19431961
result_str = zend_string_alloc(result_len, 0);
19441962
memcpy(ZSTR_VAL(result_str), Z_STRVAL_P(op1), op1_len);
19451963
if (result == orig_op1) {
19461964
i_zval_ptr_dtor(result);
19471965
}
1966+
if (UNEXPECTED(noble && !ZSTR_IS_NOBLE(result_str))) {
1967+
ZSTR_SET_NOBLE_FAST(result_str);
1968+
}
19481969
}
19491970

19501971
/* This has to happen first to account for the cases where result == op1 == op2 and

Zend/zend_string.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,54 @@ static zend_always_inline void zend_string_release_ex(zend_string *s, bool persi
330330
}
331331
}
332332

333+
#define ZSTR_IS_NOBLE(s) (GC_TYPE_INFO(s) & (IS_STR_NOBLE|IS_STR_INTERNED))
334+
335+
static zend_always_inline zend_string* zend_string_set_noble(zend_string *s) {
336+
if (UNEXPECTED(ZSTR_IS_NOBLE(s))) {
337+
return s;
338+
}
339+
340+
if (EXPECTED(GC_REFCOUNT(s) == 1 && !ZSTR_IS_INTERNED(s))) {
341+
GC_TYPE_INFO(s) |= IS_STR_NOBLE;
342+
return s;
343+
}
344+
345+
zend_string *noble = zend_string_dup(s, 0);
346+
347+
GC_TYPE_INFO(noble) |= IS_STR_NOBLE;
348+
349+
zend_string_release(s);
350+
351+
return noble;
352+
}
353+
354+
static zend_always_inline zend_string* zend_string_unset_noble(zend_string *s) {
355+
if (UNEXPECTED(!ZSTR_IS_NOBLE(s))) {
356+
return s;
357+
}
358+
359+
if (EXPECTED(GC_REFCOUNT(s) == 1 && !ZSTR_IS_INTERNED(s))) {
360+
GC_TYPE_INFO(s) &= ~IS_STR_NOBLE;
361+
return s;
362+
}
363+
364+
zend_string *noble = zend_string_dup(s, 0);
365+
366+
zend_string_release(s);
367+
368+
return noble;
369+
}
370+
371+
static zend_always_inline void zend_string_set_noble_fast(zend_string *s) {
372+
ZEND_ASSERT(GC_REFCOUNT(s) == 1 && !ZSTR_IS_INTERNED(s));
373+
374+
GC_TYPE_INFO(s) |= IS_STR_NOBLE;
375+
}
376+
377+
#define ZSTR_SET_NOBLE(s) *(s) = zend_string_set_noble(*(s))
378+
#define ZSTR_SET_NOBLE_FAST zend_string_set_noble_fast
379+
#define ZSTR_UNSET_NOBLE(s) *(s) = zend_string_unset_noble(*(s))
380+
333381
#if defined(__GNUC__) && (defined(__i386__) || (defined(__x86_64__) && !defined(__ILP32__)))
334382
BEGIN_EXTERN_C()
335383
ZEND_API bool ZEND_FASTCALL zend_string_equal_val(zend_string *s1, zend_string *s2);

Zend/zend_types.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,7 @@ static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) {
698698
#define IS_STR_PERSISTENT GC_PERSISTENT /* allocated using malloc */
699699
#define IS_STR_PERMANENT (1<<8) /* relives request boundary */
700700
#define IS_STR_VALID_UTF8 (1<<9) /* valid UTF-8 according to PCRE */
701+
#define IS_STR_NOBLE (1<<10)
701702

702703
/* array flags */
703704
#define IS_ARRAY_IMMUTABLE GC_IMMUTABLE
@@ -745,6 +746,9 @@ static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) {
745746
#define Z_PROTECT_RECURSION_P(zv) Z_PROTECT_RECURSION(*(zv))
746747
#define Z_UNPROTECT_RECURSION_P(zv) Z_UNPROTECT_RECURSION(*(zv))
747748

749+
#define Z_IS_NOBLE(zval) ((Z_TYPE(zval) == IS_LONG) || (Z_TYPE(zval) == IS_STRING && ZSTR_IS_NOBLE(Z_STR(zval))))
750+
#define Z_IS_NOBLE_P(zv) Z_IS_NOBLE(*(zv))
751+
748752
/* All data types < IS_STRING have their constructor/destructors skipped */
749753
#define Z_CONSTANT(zval) (Z_TYPE(zval) == IS_CONSTANT_AST)
750754
#define Z_CONSTANT_P(zval_p) Z_CONSTANT(*(zval_p))

0 commit comments

Comments
 (0)