Skip to content
Permalink
Browse files

Immutable clases and op_arrays.

Squashed commit of the following:

commit cd0c36c
Merge: 4740dab ad6738e
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Wed Oct 17 14:43:38 2018 +0300

    Merge branch 'master' into immutable

    * master:
      Remove the "auto" encoding
      Fixed bug #77025
      Add vtbls for EUC-TW encoding

commit 4740dab
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Wed Oct 17 14:12:28 2018 +0300

    Reverted back ce->iterator_funcs_ptr. Initialize ce->iterator_funcs_ptr fields in immutable classes.

commit ad7a78b
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Wed Oct 17 11:46:30 2018 +0300

    Added comment

commit 0276ea5
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Wed Oct 17 11:42:43 2018 +0300

    Added type cast

commit c63fc5d
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Wed Oct 17 11:36:51 2018 +0300

    Moved static class members initialization into the proper place.

commit b945548
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Wed Oct 17 11:21:03 2018 +0300

    Removed redundand assertion

commit d5a4108
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Wed Oct 17 11:19:13 2018 +0300

    Removed duplicate code

commit 8dadca8
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Wed Oct 17 11:05:43 2018 +0300

    Hide offset encoding magic in ZEND_MAP_PTR_IS_OFFSET(), ZEND_MAP_PTR_OFFSET2PTR() and ZEND_MAP_PTR_PTR2OFFSET() macros.

commit 9ef07c8
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Wed Oct 17 10:48:29 2018 +0300

    typo

commit a06f0f3
Merge: 9409958 3412345
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Wed Oct 17 10:47:07 2018 +0300

    Merge branch 'master' into immutable

    * master:
      Remove unused variable makefile_am_files
      Classify object handlers are required/optional
      Add support for getting SKIP_TAGSTART and SKIP_WHITE options
      Remove some obsolete config_vars.mk occurrences
      Remove bsd_converted from .gitignore
      Remove configuration parser and scanners ignores
      Remove obsolete buildconf.stamp from .gitignore
      [ci skip] Add magicdata.patch exception to .gitignore
      Remove outdated ext/spl/examples items from .gitignore
      Remove unused test.inc in ext/iconv/tests

commit 9409958
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Mon Oct 15 23:34:01 2018 +0300

    Immutable clases and op_arrays
  • Loading branch information...
dstogov committed Oct 17, 2018
1 parent ad6738e commit d57cd36e47b627dee5b825760163f8e62e23ab28
@@ -8,6 +8,7 @@ PHP 7.4 INTERNALS UPGRADE NOTES
e. php_win32_error_to_msg() memory management
f. get_properties_for() handler / Z_OBJDEBUG_P
g. Required object handlers
h. Immutable classes and op_arrays

2. Build system changes
a. Abstract
@@ -121,6 +122,20 @@ PHP 7.4 INTERNALS UPGRADE NOTES
It is recommended to initialize object handler structures by copying the
std object handlers and only overwriting those you want to change.

h. Opcache may make classes and op_arrays immutable. Such classes are marked
by ZEND_ACC_IMMUTABLE flag, they are not going to be copied from opcache
shared memory to process memory and must not be modified at all.
Few related data structures were changed to allow addressing mutable data
structures from immutable ones. This access is implemented through
ZEND_MAP_PTR... abstraction macros and, basically, uses additional level of
indirection. op_array->run_time_cache, op_array->static_variables_ptr and
class_entry->static_members_table now have to be accessed through
ZEND_MAP_PTR... macros.
It's also not allowed to change op_array->reserved[] handles of immutable
op_arrays. Instead, now you have to reserve op_array handle using
zend_get_op_array_extension_handle() during MINIT and access its value
using ZEND_OP_ARRAY_EXTENSION(op_array, handle).

========================
2. Build system changes
========================
@@ -33,6 +33,8 @@
#include "zend_smart_string.h"
#include "zend_cpuinfo.h"

static size_t global_map_ptr_last = 0;

#ifdef ZTS
ZEND_API int compiler_globals_id;
ZEND_API int executor_globals_id;
@@ -41,7 +43,6 @@ static HashTable *global_class_table = NULL;
static HashTable *global_constants_table = NULL;
static HashTable *global_auto_globals_table = NULL;
static HashTable *global_persistent_list = NULL;
static zend_uintptr_t global_last_static_member = 0;
ZEND_TSRMLS_CACHE_DEFINE()
# define GLOBAL_FUNCTION_TABLE global_function_table
# define GLOBAL_CLASS_TABLE global_class_table
@@ -626,13 +627,22 @@ static void compiler_globals_ctor(zend_compiler_globals *compiler_globals) /* {{
zend_hash_init_ex(compiler_globals->auto_globals, 8, NULL, auto_global_dtor, 1, 0);
zend_hash_copy(compiler_globals->auto_globals, global_auto_globals_table, auto_global_copy_ctor);

compiler_globals->last_static_member = global_last_static_member;
if (compiler_globals->last_static_member) {
compiler_globals->static_members_table = calloc(compiler_globals->last_static_member + 1, sizeof(zval*));
} else {
compiler_globals->static_members_table = NULL;
}
compiler_globals->script_encoding_list = NULL;

#if ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR_OR_OFFSET
/* Map region is going to be created and resized at run-time. */
compiler_globals->map_ptr_base = NULL;
compiler_globals->map_ptr_size = 0;
compiler_globals->map_ptr_last = global_map_ptr_last;
if (compiler_globals->map_ptr_last) {
/* Allocate map_ptr table */
compiler_globals->map_ptr_size = ZEND_MM_ALIGNED_SIZE_EX(compiler_globals->map_ptr_last, 4096);
compiler_globals->map_ptr_base = pemalloc(compiler_globals->map_ptr_size * sizeof(void*), 1);
memset(compiler_globals->map_ptr_base, 0, compiler_globals->map_ptr_last * sizeof(void*));
}
#else
# error "Unknown ZEND_MAP_PTR_KIND"
#endif
}
/* }}} */

@@ -650,13 +660,14 @@ static void compiler_globals_dtor(zend_compiler_globals *compiler_globals) /* {{
zend_hash_destroy(compiler_globals->auto_globals);
free(compiler_globals->auto_globals);
}
if (compiler_globals->static_members_table) {
free(compiler_globals->static_members_table);
}
if (compiler_globals->script_encoding_list) {
pefree((char*)compiler_globals->script_encoding_list, 1);
}
compiler_globals->last_static_member = 0;
if (compiler_globals->map_ptr_base) {
free(compiler_globals->map_ptr_base);
compiler_globals->map_ptr_base = NULL;
compiler_globals->map_ptr_size = 0;
}
}
/* }}} */

@@ -879,6 +890,22 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions) /
#ifdef ZEND_WIN32
zend_get_windows_version_info(&EG(windows_version_info));
#endif
# if ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR
/* Create a map region, used for indirect pointers from shared to
* process memory. It's allocatred once and never resized.
* All processes must map it into the same address space.
*/
CG(map_ptr_size) = 1024 * 1024; // TODO: initial size ???
CG(map_ptr_last) = 0;
CG(map_ptr_base) = pemalloc(CG(map_ptr_size) * sizeof(void*), 1);
# elif ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR_OR_OFFSET
/* Map region is going to be created and resized at run-time. */
CG(map_ptr_base) = NULL;
CG(map_ptr_size) = 0;
CG(map_ptr_last) = 0;
# else
# error "Unknown ZEND_MAP_PTR_KIND"
# endif
#endif
EG(error_reporting) = E_ALL & ~E_NOTICE;

@@ -931,7 +958,7 @@ int zend_post_startup(void) /* {{{ */
*GLOBAL_FUNCTION_TABLE = *compiler_globals->function_table;
*GLOBAL_CLASS_TABLE = *compiler_globals->class_table;
*GLOBAL_CONSTANTS_TABLE = *executor_globals->zend_constants;
global_last_static_member = compiler_globals->last_static_member;
global_map_ptr_last = compiler_globals->map_ptr_last;

short_tags_default = CG(short_tags);
compiler_options_default = CG(compiler_options);
@@ -950,6 +977,8 @@ int zend_post_startup(void) /* {{{ */
executor_globals_ctor(executor_globals);
global_persistent_list = &EG(persistent_list);
zend_copy_ini_directives();
#else
global_map_ptr_last = CG(map_ptr_last);
#endif

if (zend_post_startup_cb) {
@@ -996,6 +1025,12 @@ void zend_shutdown(void) /* {{{ */
GLOBAL_CLASS_TABLE = NULL;
GLOBAL_AUTO_GLOBALS_TABLE = NULL;
GLOBAL_CONSTANTS_TABLE = NULL;
#else
if (CG(map_ptr_base)) {
free(CG(map_ptr_base));
CG(map_ptr_base) = NULL;
CG(map_ptr_size) = 0;
}
#endif
zend_destroy_rsrc_list_dtors();
}
@@ -1077,17 +1112,12 @@ ZEND_API void zend_activate(void) /* {{{ */
init_compiler();
init_executor();
startup_scanner();
if (CG(map_ptr_last)) {
memset(CG(map_ptr_base), 0, CG(map_ptr_last) * sizeof(void*));
}
}
/* }}} */

#ifdef ZTS
void zend_reset_internal_classes(void) /* {{{ */
{
CG(last_static_member) = global_last_static_member;
}
/* }}} */
#endif

void zend_call_destructors(void) /* {{{ */
{
zend_try {
@@ -1619,6 +1649,62 @@ void free_estring(char **str_p) /* {{{ */
}
/* }}} */

ZEND_API void zend_map_ptr_reset(void)
{
CG(map_ptr_last) = global_map_ptr_last;
}

ZEND_API void *zend_map_ptr_new(void)
{
void **ptr;

if (CG(map_ptr_last) >= CG(map_ptr_size)) {
#if ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR
// TODO: error ???
ZEND_ASSERT(0);
#elif ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR_OR_OFFSET
/* Grow map_ptr table */
CG(map_ptr_size) = ZEND_MM_ALIGNED_SIZE_EX(CG(map_ptr_last) + 1, 4096);
CG(map_ptr_base) = perealloc(CG(map_ptr_base), CG(map_ptr_size) * sizeof(void*), 1);
#else
# error "Unknown ZEND_MAP_PTR_KIND"
#endif
}
ptr = (void**)CG(map_ptr_base) + CG(map_ptr_last);
*ptr = NULL;
CG(map_ptr_last)++;
#if ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR
return ptr;
#elif ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR_OR_OFFSET
return ZEND_MAP_PTR_PTR2OFFSET(ptr);
#else
# error "Unknown ZEND_MAP_PTR_KIND"
#endif
}

ZEND_API void zend_map_ptr_extend(size_t last)
{
if (last > CG(map_ptr_last)) {
void **ptr;

if (last >= CG(map_ptr_size)) {
#if ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR
/* This may never happen */
ZEND_ASSERT(0);
#elif ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR_OR_OFFSET
/* Grow map_ptr table */
CG(map_ptr_size) = ZEND_MM_ALIGNED_SIZE_EX(last, 4096);
CG(map_ptr_base) = perealloc(CG(map_ptr_base), CG(map_ptr_size) * sizeof(void*), 1);
#else
# error "Unknown ZEND_MAP_PTR_KIND"
#endif
}
ptr = (void**)CG(map_ptr_base) + CG(map_ptr_last);
memset(ptr, 0, (last - CG(map_ptr_last)) * sizeof(void*));
CG(map_ptr_last) = last;
}
}

/*
* Local variables:
* tab-width: 4
@@ -25,6 +25,7 @@
#define ZEND_ENGINE_3

#include "zend_types.h"
#include "zend_map_ptr.h"
#include "zend_errors.h"
#include "zend_alloc.h"
#include "zend_llist.h"
@@ -127,10 +128,7 @@ struct _zend_class_entry {
int default_static_members_count;
zval *default_properties_table;
zval *default_static_members_table;
union {
zval *static_members_table;
zend_uintptr_t static_members_table_idx;
};
ZEND_MAP_PTR_DEF(zval *, static_members_table);
HashTable function_table;
HashTable properties_info;
HashTable constants_table;
@@ -271,9 +269,8 @@ ZEND_API void zend_activate_modules(void);
ZEND_API void zend_deactivate_modules(void);
ZEND_API void zend_post_deactivate_modules(void);

void zend_reset_internal_classes(void);

ZEND_API void free_estring(char **str_p);

END_EXTERN_C()

/* output support */
@@ -2795,7 +2795,9 @@ ZEND_API int zend_register_class_alias_ex(const char *name, size_t name_len, zen
ce = zend_hash_add_ptr(CG(class_table), lcname, ce);
zend_string_release_ex(lcname, 0);
if (ce) {
ce->refcount++;
if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
ce->refcount++;
}
return SUCCESS;
}
return FAILURE;
@@ -3696,18 +3698,14 @@ ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, z
ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(zval) * ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);
}
ZVAL_COPY_VALUE(&ce->default_static_members_table[property_info->offset], property);
if (ce->type == ZEND_USER_CLASS) {
ce->static_members_table = ce->default_static_members_table;
#ifdef ZTS
} else if (!ce->static_members_table_idx) {
CG(last_static_member)++;
ce->static_members_table_idx = CG(last_static_member);
if (CG(static_members_table)) {
/* Support for run-time declaration: dl() */
CG(static_members_table) = realloc(CG(static_members_table), (CG(last_static_member) + 1) * sizeof(zval*));
CG(static_members_table)[ce->static_members_table_idx] = NULL;
if (!ZEND_MAP_PTR(ce->static_members_table)) {
ZEND_ASSERT(ce->type == ZEND_INTERNAL_CLASS);
if (!EG(current_execute_data)) {
ZEND_MAP_PTR_NEW(ce->static_members_table);
} else {
/* internal class loaded by dl() */
ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table);
}
#endif
}
} else {
if ((property_info_ptr = zend_hash_find_ptr(&ce->properties_info, name)) != NULL &&
@@ -228,11 +228,8 @@ typedef struct _zend_fcall_info_cache {
#define INIT_NS_CLASS_ENTRY(class_container, ns, class_name, functions) \
INIT_CLASS_ENTRY(class_container, ZEND_NS_NAME(ns, class_name), functions)

#ifdef ZTS
# define CE_STATIC_MEMBERS(ce) (((ce)->type==ZEND_USER_CLASS)?(ce)->static_members_table:CG(static_members_table)[(ce)->static_members_table_idx])
#else
# define CE_STATIC_MEMBERS(ce) ((ce)->static_members_table)
#endif
#define CE_STATIC_MEMBERS(ce) \
((zval*)ZEND_MAP_PTR_GET((ce)->static_members_table))

#define ZEND_FCI_INITIALIZED(fci) ((fci).size != 0)

@@ -1769,7 +1769,7 @@ static int copy_class_or_interface_name(zval *el, int num_args, va_list args, ze

if ((hash_key->key && ZSTR_VAL(hash_key->key)[0] != 0)
&& (comply_mask == (ce->ce_flags & mask))) {
if (ce->refcount > 1 &&
if ((ce->refcount > 1 || (ce->ce_flags & ZEND_ACC_IMMUTABLE)) &&
!same_name(hash_key->key, ce->name)) {
add_next_index_str(array, zend_string_copy(hash_key->key));
} else {

0 comments on commit d57cd36

Please sign in to comment.
You can’t perform that action at this time.