Skip to content

Commit

Permalink
Provide more macros for handling of interned strings
Browse files Browse the repository at this point in the history
 * str_erealloc behaves like erealloc for normal strings, but will
   use emalloc+memcpy for interned strings.
 * str_estrndup behaves like estrndup for normal strings, but will
   not copy interned strings.
 * str_strndup behaves like zend_strndup for normal strings, but
   will not copy interned strings.
 * str_efree_rel behaves like efree_rel for normal strings, but
   will not free interned strings.
 * str_hash will return INTERNED_HASH for interned strings and
   compute it using zend_hash_func for normal strings.
  • Loading branch information
nikic committed Sep 13, 2013
1 parent d2950ac commit 96b1c21
Show file tree
Hide file tree
Showing 14 changed files with 511 additions and 773 deletions.
4 changes: 2 additions & 2 deletions Zend/zend.h
Expand Up @@ -670,8 +670,8 @@ END_EXTERN_C()

/* FIXME: Check if we can save if (ptr) too */

#define STR_FREE(ptr) if (ptr && !IS_INTERNED(ptr)) { efree(ptr); }
#define STR_FREE_REL(ptr) if (ptr && !IS_INTERNED(ptr)) { efree_rel(ptr); }
#define STR_FREE(ptr) if (ptr) { str_efree(ptr); }
#define STR_FREE_REL(ptr) if (ptr) { str_efree_rel(ptr); }

#define STR_EMPTY_ALLOC() estrndup("", sizeof("")-1)

Expand Down
19 changes: 7 additions & 12 deletions Zend/zend_API.c
Expand Up @@ -2029,14 +2029,15 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio
const zend_function_entry *ptr = functions;
zend_function function, *reg_function;
zend_internal_function *internal_function = (zend_internal_function *)&function;
int count=0, unload=0, result=0;
int count=0, unload=0;
HashTable *target_function_table = function_table;
int error_type;
zend_function *ctor = NULL, *dtor = NULL, *clone = NULL, *__get = NULL, *__set = NULL, *__unset = NULL, *__isset = NULL, *__call = NULL, *__callstatic = NULL, *__tostring = NULL;
const char *lowercase_name;
int fname_len;
const char *lc_class_name = NULL;
int class_name_len = 0;
zend_ulong hash;

if (type==MODULE_PERSISTENT) {
error_type = E_CORE_WARNING;
Expand Down Expand Up @@ -2135,12 +2136,8 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio
}
fname_len = strlen(ptr->fname);
lowercase_name = zend_new_interned_string(zend_str_tolower_dup(ptr->fname, fname_len), fname_len + 1, 1 TSRMLS_CC);
if (IS_INTERNED(lowercase_name)) {
result = zend_hash_quick_add(target_function_table, lowercase_name, fname_len+1, INTERNED_HASH(lowercase_name), &function, sizeof(zend_function), (void**)&reg_function);
} else {
result = zend_hash_add(target_function_table, lowercase_name, fname_len+1, &function, sizeof(zend_function), (void**)&reg_function);
}
if (result == FAILURE) {
hash = str_hash(lowercase_name, fname_len);
if (zend_hash_quick_add(target_function_table, lowercase_name, fname_len+1, hash, &function, sizeof(zend_function), (void**)&reg_function) == FAILURE) {
unload=1;
str_efree(lowercase_name);
break;
Expand Down Expand Up @@ -2493,6 +2490,7 @@ static zend_class_entry *do_register_internal_class(zend_class_entry *orig_class
{
zend_class_entry *class_entry = malloc(sizeof(zend_class_entry));
char *lowercase_name = emalloc(orig_class_entry->name_length + 1);
zend_ulong hash;
*class_entry = *orig_class_entry;

class_entry->type = ZEND_INTERNAL_CLASS;
Expand All @@ -2506,11 +2504,8 @@ static zend_class_entry *do_register_internal_class(zend_class_entry *orig_class

zend_str_tolower_copy(lowercase_name, orig_class_entry->name, class_entry->name_length);
lowercase_name = (char*)zend_new_interned_string(lowercase_name, class_entry->name_length + 1, 1 TSRMLS_CC);
if (IS_INTERNED(lowercase_name)) {
zend_hash_quick_update(CG(class_table), lowercase_name, class_entry->name_length+1, INTERNED_HASH(lowercase_name), &class_entry, sizeof(zend_class_entry *), NULL);
} else {
zend_hash_update(CG(class_table), lowercase_name, class_entry->name_length+1, &class_entry, sizeof(zend_class_entry *), NULL);
}
hash = str_hash(lowercase_name, class_entry->name_length);
zend_hash_quick_update(CG(class_table), lowercase_name, class_entry->name_length+1, hash, &class_entry, sizeof(zend_class_entry *), NULL);
str_efree(lowercase_name);
return class_entry;
}
Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_builtin_functions.c
Expand Up @@ -706,7 +706,7 @@ ZEND_FUNCTION(define)
zval_ptr_dtor(&val_free);
}
c.flags = case_sensitive; /* non persistent */
c.name = IS_INTERNED(name) ? name : zend_strndup(name, name_len);
c.name = str_strndup(name, name_len);
if(c.name == NULL) {
RETURN_FALSE;
}
Expand Down
60 changes: 20 additions & 40 deletions Zend/zend_compile.c
Expand Up @@ -61,11 +61,8 @@
} while (0)

#define CALCULATE_LITERAL_HASH(num) do { \
if (IS_INTERNED(Z_STRVAL(CONSTANT(num)))) { \
Z_HASH_P(&CONSTANT(num)) = INTERNED_HASH(Z_STRVAL(CONSTANT(num))); \
} else { \
Z_HASH_P(&CONSTANT(num)) = zend_hash_func(Z_STRVAL(CONSTANT(num)), Z_STRLEN(CONSTANT(num))+1); \
} \
zval *c = &CONSTANT(num); \
Z_HASH_P(c) = str_hash(Z_STRVAL_P(c), Z_STRLEN_P(c)); \
} while (0)

#define GET_CACHE_SLOT(literal) do { \
Expand Down Expand Up @@ -107,9 +104,7 @@ ZEND_API zend_executor_globals executor_globals;

static void zend_duplicate_property_info(zend_property_info *property_info) /* {{{ */
{
if (!IS_INTERNED(property_info->name)) {
property_info->name = estrndup(property_info->name, property_info->name_length);
}
property_info->name = str_estrndup(property_info->name, property_info->name_length);
if (property_info->doc_comment) {
property_info->doc_comment = estrndup(property_info->doc_comment, property_info->doc_comment_len);
}
Expand All @@ -118,9 +113,7 @@ static void zend_duplicate_property_info(zend_property_info *property_info) /* {

static void zend_duplicate_property_info_internal(zend_property_info *property_info) /* {{{ */
{
if (!IS_INTERNED(property_info->name)) {
property_info->name = zend_strndup(property_info->name, property_info->name_length);
}
property_info->name = str_strndup(property_info->name, property_info->name_length);
}
/* }}} */

Expand Down Expand Up @@ -657,13 +650,13 @@ void fetch_simple_variable_ex(znode *result, znode *varname, int bp, zend_uchar
zend_llist *fetch_list_ptr;

if (varname->op_type == IS_CONST) {
ulong hash = 0;
ulong hash;

if (Z_TYPE(varname->u.constant) != IS_STRING) {
convert_to_string(&varname->u.constant);
} else if (IS_INTERNED(Z_STRVAL(varname->u.constant))) {
hash = INTERNED_HASH(Z_STRVAL(varname->u.constant));
}

hash = str_hash(Z_STRVAL(varname->u.constant), Z_STRLEN(varname->u.constant));
if (!zend_is_auto_global_quick(Z_STRVAL(varname->u.constant), Z_STRLEN(varname->u.constant), hash TSRMLS_CC) &&
!(Z_STRLEN(varname->u.constant) == (sizeof("this")-1) &&
!memcmp(Z_STRVAL(varname->u.constant), "this", sizeof("this"))) &&
Expand Down Expand Up @@ -1568,16 +1561,11 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
op_array.line_start = zend_get_compiled_lineno(TSRMLS_C);

if (is_method) {
int result;
zend_ulong hash;

lcname = zend_new_interned_string(zend_str_tolower_dup(name, name_len), name_len + 1, 1 TSRMLS_CC);

if (IS_INTERNED(lcname)) {
result = zend_hash_quick_add(&CG(active_class_entry)->function_table, lcname, name_len+1, INTERNED_HASH(lcname), &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array));
} else {
result = zend_hash_add(&CG(active_class_entry)->function_table, lcname, name_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array));
}
if (result == FAILURE) {
hash = str_hash(lcname, name_len);
if (zend_hash_quick_add(&CG(active_class_entry)->function_table, lcname, name_len+1, hash, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)) == FAILURE) {
zend_error(E_COMPILE_ERROR, "Cannot redeclare %s::%s()", CG(active_class_entry)->name, name);
}

Expand Down Expand Up @@ -1840,7 +1828,7 @@ void zend_do_receive_arg(zend_uchar op, znode *varname, const znode *offset, con
zend_arg_info *cur_arg_info;
znode var;

if (zend_is_auto_global_quick(Z_STRVAL(varname->u.constant), Z_STRLEN(varname->u.constant), 0 TSRMLS_CC)) {
if (zend_is_auto_global(Z_STRVAL(varname->u.constant), Z_STRLEN(varname->u.constant) TSRMLS_CC)) {
zend_error(E_COMPILE_ERROR, "Cannot re-assign auto-global variable %s", Z_STRVAL(varname->u.constant));
} else {
var.op_type = IS_CV;
Expand Down Expand Up @@ -1984,9 +1972,7 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */
if (Z_TYPE(name) != IS_STRING) {
zend_error(E_COMPILE_ERROR, "Method name must be a string");
}
if (!IS_INTERNED(Z_STRVAL(name))) {
Z_STRVAL(name) = estrndup(Z_STRVAL(name), Z_STRLEN(name));
}
Z_STRVAL(name) = str_estrndup(Z_STRVAL(name), Z_STRLEN(name));
FREE_POLYMORPHIC_CACHE_SLOT(last_op->op2.constant);
last_op->op2.constant =
zend_add_func_name_literal(CG(active_op_array), &name TSRMLS_CC);
Expand Down Expand Up @@ -2112,7 +2098,7 @@ void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace
memcpy(Z_STRVAL(tmp.u.constant), Z_STRVAL_P(CG(current_namespace)), Z_STRLEN_P(CG(current_namespace)));
memcpy(&(Z_STRVAL(tmp.u.constant)[Z_STRLEN_P(CG(current_namespace))]), "\\", sizeof("\\")-1);
memcpy(&(Z_STRVAL(tmp.u.constant)[Z_STRLEN_P(CG(current_namespace)) + sizeof("\\")-1]), Z_STRVAL(element_name->u.constant), Z_STRLEN(element_name->u.constant)+1);
STR_FREE(Z_STRVAL(element_name->u.constant));
str_efree(Z_STRVAL(element_name->u.constant));
*element_name = tmp;
}
}
Expand Down Expand Up @@ -2405,14 +2391,14 @@ void zend_do_build_full_name(znode *result, znode *prefix, znode *name, int is_c
Z_STRVAL(result->u.constant) = erealloc(Z_STRVAL(result->u.constant), length+1);
memcpy(&Z_STRVAL(result->u.constant)[Z_STRLEN(result->u.constant)], "::", sizeof("::")-1);
memcpy(&Z_STRVAL(result->u.constant)[Z_STRLEN(result->u.constant) + sizeof("::")-1], Z_STRVAL(name->u.constant), Z_STRLEN(name->u.constant)+1);
STR_FREE(Z_STRVAL(name->u.constant));
str_efree(Z_STRVAL(name->u.constant));
Z_STRLEN(result->u.constant) = length;
} else {
length = sizeof("\\")-1 + Z_STRLEN(result->u.constant) + Z_STRLEN(name->u.constant);
Z_STRVAL(result->u.constant) = erealloc(Z_STRVAL(result->u.constant), length+1);
memcpy(&Z_STRVAL(result->u.constant)[Z_STRLEN(result->u.constant)], "\\", sizeof("\\")-1);
memcpy(&Z_STRVAL(result->u.constant)[Z_STRLEN(result->u.constant) + sizeof("\\")-1], Z_STRVAL(name->u.constant), Z_STRLEN(name->u.constant)+1);
STR_FREE(Z_STRVAL(name->u.constant));
str_efree(Z_STRVAL(name->u.constant));
Z_STRLEN(result->u.constant) = length;
}
}
Expand Down Expand Up @@ -5305,7 +5291,7 @@ void zend_do_declare_class_constant(znode *var_name, const znode *value TSRMLS_D
{
zval *property;
const char *cname = NULL;
int result;
zend_ulong hash;

if(Z_TYPE(value->u.constant) == IS_CONSTANT_ARRAY) {
zend_error(E_COMPILE_ERROR, "Arrays are not allowed in class constants");
Expand All @@ -5320,13 +5306,8 @@ void zend_do_declare_class_constant(znode *var_name, const znode *value TSRMLS_D
*property = value->u.constant;

cname = zend_new_interned_string(Z_STRVAL(var_name->u.constant), Z_STRLEN(var_name->u.constant)+1, 0 TSRMLS_CC);

if (IS_INTERNED(cname)) {
result = zend_hash_quick_add(&CG(active_class_entry)->constants_table, cname, Z_STRLEN(var_name->u.constant)+1, INTERNED_HASH(cname), &property, sizeof(zval *), NULL);
} else {
result = zend_hash_add(&CG(active_class_entry)->constants_table, cname, Z_STRLEN(var_name->u.constant)+1, &property, sizeof(zval *), NULL);
}
if (result == FAILURE) {
hash = str_hash(cname, Z_STRLEN(var_name->u.constant));
if (zend_hash_quick_add(&CG(active_class_entry)->constants_table, cname, Z_STRLEN(var_name->u.constant)+1, hash, &property, sizeof(zval *), NULL) == FAILURE) {
FREE_ZVAL(property);
zend_error(E_COMPILE_ERROR, "Cannot redefine class constant %s::%s", CG(active_class_entry)->name, Z_STRVAL(var_name->u.constant));
}
Expand Down Expand Up @@ -6692,10 +6673,9 @@ void zend_do_ticks(TSRMLS_D) /* {{{ */
}
/* }}} */

zend_bool zend_is_auto_global_quick(const char *name, uint name_len, ulong hashval TSRMLS_DC) /* {{{ */
zend_bool zend_is_auto_global_quick(const char *name, uint name_len, ulong hash TSRMLS_DC) /* {{{ */
{
zend_auto_global *auto_global;
ulong hash = hashval ? hashval : zend_hash_func(name, name_len+1);

if (zend_hash_quick_find(CG(auto_globals), name, name_len+1, hash, (void **) &auto_global)==SUCCESS) {
if (auto_global->armed) {
Expand All @@ -6709,7 +6689,7 @@ zend_bool zend_is_auto_global_quick(const char *name, uint name_len, ulong hashv

zend_bool zend_is_auto_global(const char *name, uint name_len TSRMLS_DC) /* {{{ */
{
return zend_is_auto_global_quick(name, name_len, 0 TSRMLS_CC);
return zend_is_auto_global_quick(name, name_len, zend_hash_func(name, name_len+1) TSRMLS_CC);
}
/* }}} */

Expand Down
19 changes: 6 additions & 13 deletions Zend/zend_constants.c
Expand Up @@ -38,9 +38,7 @@ void free_zend_constant(zend_constant *c)

void copy_zend_constant(zend_constant *c)
{
if (!IS_INTERNED(c->name)) {
c->name = zend_strndup(c->name, c->name_len - 1);
}
c->name = str_strndup(c->name, c->name_len - 1);
if (!(c->flags & CONST_PERSISTENT)) {
zval_copy_ctor(&c->value);
}
Expand Down Expand Up @@ -474,7 +472,7 @@ ZEND_API int zend_register_constant(zend_constant *c TSRMLS_DC)
char *lowercase_name = NULL;
char *name;
int ret = SUCCESS;
ulong chash = 0;
ulong chash;

#if 0
printf("Registering constant for module %d\n", c->module_number);
Expand All @@ -486,23 +484,18 @@ ZEND_API int zend_register_constant(zend_constant *c TSRMLS_DC)
zend_str_tolower(lowercase_name, c->name_len-1);
lowercase_name = (char*)zend_new_interned_string(lowercase_name, c->name_len, 1 TSRMLS_CC);
name = lowercase_name;
chash = IS_INTERNED(lowercase_name) ? INTERNED_HASH(lowercase_name) : 0;
} else {
char *slash = strrchr(c->name, '\\');
if(slash) {
if (slash) {
lowercase_name = estrndup(c->name, c->name_len-1);
zend_str_tolower(lowercase_name, slash-c->name);
lowercase_name = (char*)zend_new_interned_string(lowercase_name, c->name_len, 1 TSRMLS_CC);
name = lowercase_name;

chash = IS_INTERNED(lowercase_name) ? INTERNED_HASH(lowercase_name) : 0;
} else {
name = c->name;
}
}
if (chash == 0) {
chash = zend_hash_func(name, c->name_len);
}
chash = str_hash(name, c->name_len-1);

/* Check if the user is trying to define the internal pseudo constant name __COMPILER_HALT_OFFSET__ */
if ((c->name_len == sizeof("__COMPILER_HALT_OFFSET__")
Expand All @@ -521,8 +514,8 @@ ZEND_API int zend_register_constant(zend_constant *c TSRMLS_DC)
}
ret = FAILURE;
}
if (lowercase_name && !IS_INTERNED(lowercase_name)) {
efree(lowercase_name);
if (lowercase_name) {
str_efree(lowercase_name);
}
return ret;
}
Expand Down
49 changes: 17 additions & 32 deletions Zend/zend_execute.c
Expand Up @@ -767,32 +767,21 @@ static inline void zend_assign_to_object(zval **retval, zval **object_ptr, zval

static inline int zend_assign_to_string_offset(const temp_variable *T, const zval *value, int value_type TSRMLS_DC)
{
if (Z_TYPE_P(T->str_offset.str) == IS_STRING) {

if (((int)T->str_offset.offset < 0)) {
zend_error(E_WARNING, "Illegal string offset: %d", T->str_offset.offset);
zval *str = T->str_offset.str;
zend_uint offset = T->str_offset.offset;
if (Z_TYPE_P(str) == IS_STRING) {
if ((int)offset < 0) {
zend_error(E_WARNING, "Illegal string offset: %d", offset);
return 0;
}

if (T->str_offset.offset >= Z_STRLEN_P(T->str_offset.str)) {
if (IS_INTERNED(Z_STRVAL_P(T->str_offset.str))) {
char *tmp = (char *) emalloc(T->str_offset.offset+1+1);

memcpy(tmp, Z_STRVAL_P(T->str_offset.str), Z_STRLEN_P(T->str_offset.str)+1);
Z_STRVAL_P(T->str_offset.str) = tmp;
} else {
Z_STRVAL_P(T->str_offset.str) = (char *) erealloc(Z_STRVAL_P(T->str_offset.str), T->str_offset.offset+1+1);
}
memset(Z_STRVAL_P(T->str_offset.str) + Z_STRLEN_P(T->str_offset.str),
' ',
T->str_offset.offset - Z_STRLEN_P(T->str_offset.str));
Z_STRVAL_P(T->str_offset.str)[T->str_offset.offset+1] = 0;
Z_STRLEN_P(T->str_offset.str) = T->str_offset.offset+1;
} else if (IS_INTERNED(Z_STRVAL_P(T->str_offset.str))) {
char *tmp = (char *) emalloc(Z_STRLEN_P(T->str_offset.str) + 1);

memcpy(tmp, Z_STRVAL_P(T->str_offset.str), Z_STRLEN_P(T->str_offset.str) + 1);
Z_STRVAL_P(T->str_offset.str) = tmp;
if (offset >= Z_STRLEN_P(str)) {
Z_STRVAL_P(str) = str_erealloc(Z_STRVAL_P(str), offset+1+1);
memset(Z_STRVAL_P(str) + Z_STRLEN_P(str), ' ', offset - Z_STRLEN_P(str));
Z_STRVAL_P(str)[offset+1] = 0;
Z_STRLEN_P(str) = offset+1;
} else if (IS_INTERNED(Z_STRVAL_P(str))) {
Z_STRVAL_P(str) = estrndup(Z_STRVAL_P(str), Z_STRLEN_P(str));
}

if (Z_TYPE_P(value) != IS_STRING) {
Expand All @@ -803,15 +792,15 @@ static inline int zend_assign_to_string_offset(const temp_variable *T, const zva
zval_copy_ctor(&tmp);
}
convert_to_string(&tmp);
Z_STRVAL_P(T->str_offset.str)[T->str_offset.offset] = Z_STRVAL(tmp)[0];
STR_FREE(Z_STRVAL(tmp));
Z_STRVAL_P(str)[offset] = Z_STRVAL(tmp)[0];
str_efree(Z_STRVAL(tmp));
} else {
Z_STRVAL_P(T->str_offset.str)[T->str_offset.offset] = Z_STRVAL_P(value)[0];
Z_STRVAL_P(str)[offset] = Z_STRVAL_P(value)[0];
if (value_type == IS_TMP_VAR) {
/* we can safely free final_value here
* because separation is done only
* in case value_type == IS_VAR */
STR_FREE(Z_STRVAL_P(value));
str_efree(Z_STRVAL_P(value));
}
}
/*
Expand Down Expand Up @@ -1024,11 +1013,7 @@ static inline zval **zend_fetch_dimension_address_inner(HashTable *ht, const zva
hval = Z_HASH_P(dim);
} else {
ZEND_HANDLE_NUMERIC_EX(offset_key, offset_key_length+1, hval, goto num_index);
if (IS_INTERNED(offset_key)) {
hval = INTERNED_HASH(offset_key);
} else {
hval = zend_hash_func(offset_key, offset_key_length+1);
}
hval = str_hash(offset_key, offset_key_length);
}
fetch_string_dim:
if (zend_hash_quick_find(ht, offset_key, offset_key_length+1, hval, (void **) &retval) == FAILURE) {
Expand Down

0 comments on commit 96b1c21

Please sign in to comment.