From d62ab6c36e80250aa6c3c2fcc510469e6ad9f55e Mon Sep 17 00:00:00 2001 From: Dusan Malusev Date: Fri, 5 Jan 2024 13:32:46 +0100 Subject: [PATCH 1/5] Constants api Signed-off-by: Dusan Malusev --- .gitignore | 1 + Cargo.lock | 1 + phper/Cargo.toml | 1 + phper/src/constants.rs | 133 +++++++++++++++++++++++++---------------- phper/src/lib.rs | 2 +- phper/src/modules.rs | 5 +- 6 files changed, 89 insertions(+), 54 deletions(-) diff --git a/.gitignore b/.gitignore index 1e84f68..eefeaf4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ /vendor core .vscode/ +.idea/ diff --git a/Cargo.lock b/Cargo.lock index d3b05f6..bc5fa88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -823,6 +823,7 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" name = "phper" version = "0.13.0" dependencies = [ + "bitflags 2.4.1", "derive_more", "indexmap", "once_cell", diff --git a/phper/Cargo.toml b/phper/Cargo.toml index ccc98b5..454fffe 100644 --- a/phper/Cargo.toml +++ b/phper/Cargo.toml @@ -29,6 +29,7 @@ phper-alloc = { workspace = true } phper-macros = { workspace = true } phper-sys = { workspace = true } thiserror = "1.0.43" +bitflags = { version = "2.4.1" } [build-dependencies] phper-build = { workspace = true } diff --git a/phper/src/constants.rs b/phper/src/constants.rs index 0ca762e..3eba5c6 100644 --- a/phper/src/constants.rs +++ b/phper/src/constants.rs @@ -10,72 +10,103 @@ //! Apis relate to [zend_constant](crate::sys::zend_constant). -use crate::{sys::*, types::Scalar}; +use crate::strings::ZString; +use crate::values::ZVal; +use crate::{sys::*}; +use bitflags::bitflags; use std::ffi::{c_char, c_int}; -pub(crate) struct Constant { +pub struct Constant { name: String, - value: Scalar, + value: ZVal, + flags: Flags, +} + +// #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[repr(transparent)] +pub struct Flags(u32); + +impl Default for Flags { + fn default() -> Self { + Self::Cs | Self::Persistent + } +} + +bitflags! { + impl Flags: u32 { + const Cs = CONST_CS; + const Persistent = CONST_PERSISTENT; + const NoFileCache = CONST_NO_FILE_CACHE; + const Deprecated = CONST_DEPRECATED; + const Owned = CONST_OWNED; + } } impl Constant { - pub fn new(name: impl Into, value: impl Into) -> Self { + pub fn new(name: impl Into, value: impl Into, flags: Option) -> Self { Self { name: name.into(), value: value.into(), + flags: flags.unwrap_or_default(), } } pub(crate) fn register(&self, module_number: c_int) { - let name_ptr = self.name.as_ptr() as *const c_char; - let name_len = self.name.len(); - let flags = (CONST_PERSISTENT | CONST_CS) as c_int; + let flags = self.flags.bits() as c_int; unsafe { - match &self.value { - Scalar::Null => { - zend_register_null_constant(name_ptr, name_len, flags, module_number) - } - Scalar::Bool(b) => zend_register_bool_constant( - name_ptr, - name_len, - *b as zend_bool, - flags, - module_number, - ), - Scalar::I64(i) => zend_register_long_constant( - name_ptr, - name_len, - *i as zend_long, - flags, - module_number, - ), - Scalar::F64(f) => { - zend_register_double_constant(name_ptr, name_len, *f, flags, module_number) - } - Scalar::String(s) => { - let s_ptr = s.as_ptr() as *mut u8; - zend_register_stringl_constant( - name_ptr, - name_len, - s_ptr.cast(), - s.len(), - flags, - module_number, - ) - } - Scalar::Bytes(s) => { - let s_ptr = s.as_ptr() as *mut u8; - zend_register_stringl_constant( - name_ptr, - name_len, - s_ptr.cast(), - s.len(), - flags, - module_number, - ) - } - } + let mut name = ZString::new(self.name.clone()); + let mut constant = _zend_constant{ + value: self.value.clone().into_inner(), + name: name.as_mut_ptr(), + }; + + zend_register_constant(&mut constant); + + // match { + // Scalar::Null => { + // zend_register_null_constant(name_ptr, name_len, flags, module_number) + // } + // Scalar::Bool(b) => zend_register_bool_constant( + // name_ptr, + // name_len, + // *b as zend_bool, + // flags, + // module_number, + // ), + // Scalar::I64(i) => zend_register_long_constant( + // name_ptr, + // name_len, + // *i as zend_long, + // flags, + // module_number, + // ), + // Scalar::F64(f) => { + // zend_register_double_constant(name_ptr, name_len, *f, flags, module_number) + // } + // Scalar::String(s) => { + // let s_ptr = s.as_ptr() as *mut u8; + // zend_register_stringl_constant( + // name_ptr, + // name_len, + // s_ptr.cast(), + // s.len(), + // flags, + // module_number, + // ) + // } + // Scalar::Bytes(s) => { + // let s_ptr = s.as_ptr() as *mut u8; + // zend_register_stringl_constant( + // name_ptr, + // name_len, + // s_ptr.cast(), + // s.len(), + // flags, + // module_number, + // ) + // } + // } } } } diff --git a/phper/src/lib.rs b/phper/src/lib.rs index 31a58a5..6fa3d4d 100644 --- a/phper/src/lib.rs +++ b/phper/src/lib.rs @@ -17,7 +17,7 @@ mod macros; pub mod arrays; pub mod classes; -pub(crate) mod constants; +pub mod constants; pub mod errors; pub mod functions; pub mod ini; diff --git a/phper/src/modules.rs b/phper/src/modules.rs index 3b32f52..9d832fb 100644 --- a/phper/src/modules.rs +++ b/phper/src/modules.rs @@ -10,6 +10,7 @@ //! Apis relate to [zend_module_entry]. +use crate::constants; use crate::{ c_str_ptr, classes::{entity::ClassEntity, InterfaceEntity}, @@ -228,8 +229,8 @@ impl Module { } /// Register constant to module. - pub fn add_constant(&mut self, name: impl Into, value: impl Into) { - self.constants.push(Constant::new(name, value)); + pub fn add_constant(&mut self, name: impl Into, value: impl Into, flags: Option) { + self.constants.push(Constant::new(name, value, flags)); } /// Register ini configuration to module. From 8908f9478225f648e6c94433f71f4084e8d1084b Mon Sep 17 00:00:00 2001 From: Dusan Malusev Date: Fri, 5 Jan 2024 23:48:40 +0100 Subject: [PATCH 2/5] Improve Memory usage and Constants Signed-off-by: Dusan Malusev --- phper-sys/c/php_constants.c | 18 +++++ phper-sys/c/php_wrapper.c | 88 ++++++++++------------ phper-sys/include/phper.h | 10 ++- phper/src/classes/entity.rs | 75 ++++++++++--------- phper/src/classes/mod.rs | 47 ++++++------ phper/src/constants.rs | 85 +++++---------------- phper/src/functions.rs | 78 ++++--------------- phper/src/modules.rs | 116 ++++++++++++++++------------- phper/src/values.rs | 2 +- tests/integration/src/constants.rs | 14 ++-- 10 files changed, 237 insertions(+), 296 deletions(-) create mode 100644 phper-sys/c/php_constants.c diff --git a/phper-sys/c/php_constants.c b/phper-sys/c/php_constants.c new file mode 100644 index 0000000..1d9e310 --- /dev/null +++ b/phper-sys/c/php_constants.c @@ -0,0 +1,18 @@ +#include + +zend_constant phper_create_constant(const char *name, size_t name_len, zval val, + int flags) { + zend_constant c = { + .name = + zend_string_init_interned(name, name_len, flags & CONST_PERSISTENT), + .value = val, + }; + + return c; +} + +zend_result phper_register_constant(zend_constant *constant, int flags, + int module_number) { + ZEND_CONSTANT_SET_FLAGS(constant, flags, module_number); + return zend_register_constant(constant); +} \ No newline at end of file diff --git a/phper-sys/c/php_wrapper.c b/phper-sys/c/php_wrapper.c index 73557dc..65e1c19 100644 --- a/phper-sys/c/php_wrapper.c +++ b/phper-sys/c/php_wrapper.c @@ -14,34 +14,32 @@ // object apis: // ================================================== - zval *phper_get_this(zend_execute_data *execute_data) { +zval *phper_get_this(zend_execute_data *execute_data) { return getThis(); } - size_t phper_zend_object_properties_size(zend_class_entry *ce) { +size_t phper_zend_object_properties_size(zend_class_entry *ce) { return zend_object_properties_size(ce); } - void *phper_zend_object_alloc(size_t obj_size, - zend_class_entry *ce) { +void *phper_zend_object_alloc(size_t obj_size, zend_class_entry *ce) { return zend_object_alloc(obj_size, ce); } - zend_object *(**phper_get_create_object(zend_class_entry *ce))( +zend_object *(**phper_get_create_object(zend_class_entry *ce))( zend_class_entry *class_type) { return &ce->create_object; } - bool phper_object_init_ex(zval *arg, - zend_class_entry *class_type) { +bool phper_object_init_ex(zval *arg, zend_class_entry *class_type) { return object_init_ex(arg, class_type) == SUCCESS; } - void phper_zend_object_release(zend_object *obj) { +void phper_zend_object_release(zend_object *obj) { zend_object_release(obj); } - uint32_t phper_zend_object_gc_refcount(const zend_object *obj) { +uint32_t phper_zend_object_gc_refcount(const zend_object *obj) { return GC_REFCOUNT(obj); } @@ -49,7 +47,7 @@ // class apis: // ================================================== - zend_class_entry * +zend_class_entry * phper_init_class_entry_ex(const char *class_name, size_t class_name_len, const zend_function_entry *functions, phper_init_class_entry_handler handler, @@ -59,9 +57,8 @@ phper_init_class_entry_ex(const char *class_name, size_t class_name_len, return handler(&class_ce, argument); } - bool -phper_instanceof_function(const zend_class_entry *instance_ce, - const zend_class_entry *ce) { +bool phper_instanceof_function(const zend_class_entry *instance_ce, + const zend_class_entry *ce) { return instanceof_function(instance_ce, ce) != 0; } @@ -69,42 +66,36 @@ phper_instanceof_function(const zend_class_entry *instance_ce, // function apis: // ================================================== - zend_string * -phper_get_function_or_method_name(const zend_function *func) { +zend_string *phper_get_function_or_method_name(const zend_function *func) { return get_function_or_method_name(func); } - zend_string *phper_get_function_name(const zend_function *func) { +zend_string *phper_get_function_name(const zend_function *func) { return func->common.function_name; } - bool phper_call_user_function(HashTable *function_table, - zval *object, zval *function_name, - zval *retval_ptr, - uint32_t param_count, - zval params[]) { +bool phper_call_user_function(HashTable *function_table, zval *object, + zval *function_name, zval *retval_ptr, + uint32_t param_count, zval params[]) { (void)function_table; // suppress "unused parameter" warnings. return call_user_function(function_table, object, function_name, retval_ptr, param_count, params) == SUCCESS; } - zval *phper_zend_call_var_num(zend_execute_data *execute_data, - int index) { +zval *phper_zend_call_var_num(zend_execute_data *execute_data, int index) { return ZEND_CALL_VAR_NUM(execute_data, index); } - zval *phper_zend_call_arg(zend_execute_data *execute_data, - int index) { +zval *phper_zend_call_arg(zend_execute_data *execute_data, int index) { return ZEND_CALL_ARG(execute_data, index); } - uint32_t -phper_zend_num_args(const zend_execute_data *execute_data) { +uint32_t phper_zend_num_args(const zend_execute_data *execute_data) { return ZEND_NUM_ARGS(); } - bool phper_zend_get_parameters_array_ex(uint32_t param_count, - zval *argument_array) { +bool phper_zend_get_parameters_array_ex(uint32_t param_count, + zval *argument_array) { return zend_get_parameters_array_ex(param_count, argument_array) != 0; } @@ -112,44 +103,43 @@ phper_zend_num_args(const zend_execute_data *execute_data) { // module apis: // ================================================== - const char *phper_get_zend_module_build_id() { +const char *phper_get_zend_module_build_id() { return ZEND_MODULE_BUILD_ID; } - zend_resource * -phper_register_persistent_resource(const zend_string *id, const void *ptr, - int le_id) { +zend_resource *phper_register_persistent_resource(const zend_string *id, + const void *ptr, int le_id) { return zend_register_persistent_resource_ex((zend_string *)id, (void *)ptr, le_id); } - int phper_zend_register_persistent_list_destructors( - rsrc_dtor_func_t dtor, const char *name, int module_number) { +int phper_zend_register_persistent_list_destructors(rsrc_dtor_func_t dtor, + const char *name, + int module_number) { return zend_register_list_destructors_ex(NULL, dtor, name, module_number); } - int -phper_zend_register_list_destructors(const rsrc_dtor_func_t dtor, - const char *name, int module_number) { +int phper_zend_register_list_destructors(const rsrc_dtor_func_t dtor, + const char *name, int module_number) { return zend_register_list_destructors_ex((rsrc_dtor_func_t)dtor, NULL, name, module_number); } - int -phper_zend_register_list_destructors_ex(const rsrc_dtor_func_t dtor, - const rsrc_dtor_func_t pdtor, - const char *name, int module_number) { +int phper_zend_register_list_destructors_ex(const rsrc_dtor_func_t dtor, + const rsrc_dtor_func_t pdtor, + const char *name, + int module_number) { return zend_register_list_destructors_ex( (rsrc_dtor_func_t)dtor, (rsrc_dtor_func_t)pdtor, name, module_number); } - int phper_zend_fetch_list_dtor_id(const char *name) { +int phper_zend_fetch_list_dtor_id(const char *name) { return zend_fetch_list_dtor_id(name); } - const zend_resource * -phper_register_persistent_find(const char *hash, size_t len) { +const zend_resource *phper_register_persistent_find(const char *hash, + size_t len) { zend_resource *zv = zend_hash_str_find_ptr(&EG(persistent_list), hash, len); if (zv == NULL) { @@ -164,8 +154,9 @@ phper_register_persistent_find(const char *hash, size_t len) { // Argument API: // ================================================== - zend_internal_arg_info phper_zend_begin_arg_info_ex( - bool return_reference, uintptr_t required_num_args) { +zend_internal_arg_info +phper_zend_begin_arg_info_ex(bool return_reference, + uintptr_t required_num_args) { #define static #define const ZEND_BEGIN_ARG_INFO_EX(info, 0, return_reference, required_num_args) @@ -175,8 +166,7 @@ phper_register_persistent_find(const char *hash, size_t len) { #undef const } - zend_internal_arg_info phper_zend_arg_info(bool pass_by_ref, - const char *name) { +zend_internal_arg_info phper_zend_arg_info(bool pass_by_ref, const char *name) { zend_internal_arg_info info[] = {ZEND_ARG_INFO(pass_by_ref, )}; info[0].name = name; return info[0]; diff --git a/phper-sys/include/phper.h b/phper-sys/include/phper.h index 96a0f61..cbd2a4c 100644 --- a/phper-sys/include/phper.h +++ b/phper-sys/include/phper.h @@ -287,4 +287,12 @@ phper_register_persistent_find(const char *hash, size_t len); zend_internal_arg_info phper_zend_begin_arg_info_ex( bool return_reference, uintptr_t required_num_args); zend_internal_arg_info phper_zend_arg_info(bool pass_by_ref, - const char *name); \ No newline at end of file + const char *name); + // ================================================== + // Constants API: + // ================================================== + zend_constant phper_create_constant(const char *name, size_t name_len, + zval val, int flags); + + zend_result phper_register_constant(zend_constant *constant, int flags, + int module_number); \ No newline at end of file diff --git a/phper/src/classes/entity.rs b/phper/src/classes/entity.rs index c8b167c..acdcfd2 100644 --- a/phper/src/classes/entity.rs +++ b/phper/src/classes/entity.rs @@ -256,43 +256,6 @@ impl ClassEntity { })); } - #[allow(clippy::useless_conversion)] - pub(crate) unsafe fn init(&self) -> *mut zend_class_entry { - let parent: *mut zend_class_entry = self - .parent - .as_ref() - .map(|parent| parent()) - .map(|entry| entry.as_ptr() as *mut _) - .unwrap_or(null_mut()); - - let class_ce = phper_init_class_entry_ex( - self.class_name.as_ptr().cast(), - self.class_name.as_bytes().len().try_into().unwrap(), - self.function_entries(), - Some(class_init_handler), - parent.cast(), - ); - - if let Some(bind_class) = self.bind_class { - bind_class.bind(class_ce); - } - - for interface in &self.interfaces { - let interface_ce = interface().as_ptr(); - zend_class_implements(class_ce, 1, interface_ce); - } - - *phper_get_create_object(class_ce) = Some(create_object); - - class_ce - } - - pub(crate) unsafe fn declare_properties(&self, ce: *mut zend_class_entry) { - for property in &self.property_entities { - property.declare(ce); - } - } - unsafe fn function_entries(&self) -> *const zend_function_entry { let mut methods = self .method_entities @@ -329,3 +292,41 @@ impl ClassEntity { entry } } + +impl crate::modules::Registerer for ClassEntity { + fn register(&mut self, _: i32) -> Result<(), Box> { + unsafe { + let parent: *mut zend_class_entry = self + .parent + .as_ref() + .map(|parent| parent()) + .map(|entry| entry.as_ptr() as *mut _) + .unwrap_or(null_mut()); + + let class_ce = phper_init_class_entry_ex( + self.class_name.as_ptr().cast(), + self.class_name.as_bytes().len(), + self.function_entries(), + Some(class_init_handler), + parent.cast(), + ); + + if let Some(bind_class) = self.bind_class { + bind_class.bind(class_ce); + } + + for interface in &self.interfaces { + let interface_ce = interface().as_ptr(); + zend_class_implements(class_ce, 1, interface_ce); + } + + *phper_get_create_object(class_ce) = Some(create_object); + + for property in &self.property_entities { + property.declare(class_ce); + } + } + + Ok(()) + } +} diff --git a/phper/src/classes/mod.rs b/phper/src/classes/mod.rs index 1d29489..3225525 100644 --- a/phper/src/classes/mod.rs +++ b/phper/src/classes/mod.rs @@ -249,28 +249,6 @@ impl InterfaceEntity { self.bind_interface = Some(i); } - #[allow(clippy::useless_conversion)] - pub(crate) unsafe fn init(&self) -> *mut zend_class_entry { - let class_ce = phper_init_class_entry_ex( - self.interface_name.as_ptr().cast(), - self.interface_name.as_bytes().len().try_into().unwrap(), - self.function_entries(), - Some(interface_init_handler), - null_mut(), - ); - - if let Some(bind_interface) = self.bind_interface { - bind_interface.bind(class_ce); - } - - for interface in &self.extends { - let interface_ce = interface().as_ptr(); - zend_class_implements(class_ce, 1, interface_ce); - } - - class_ce - } - unsafe fn function_entries(&self) -> *const zend_function_entry { let mut methods = self .method_entities @@ -284,6 +262,31 @@ impl InterfaceEntity { } } +impl crate::modules::Registerer for InterfaceEntity { + fn register(&mut self, _: i32) -> Result<(), Box> { + unsafe { + let class_ce = phper_init_class_entry_ex( + self.interface_name.as_ptr().cast(), + self.interface_name.as_bytes().len(), + self.function_entries(), + Some(interface_init_handler), + null_mut(), + ); + + if let Some(bind_interface) = self.bind_interface { + bind_interface.bind(class_ce); + } + + for interface in &self.extends { + let interface_ce = interface().as_ptr(); + zend_class_implements(class_ce, 1, interface_ce); + } + }; + + Ok(()) + } +} + unsafe extern "C" fn interface_init_handler( class_ce: *mut zend_class_entry, _argument: *mut c_void, diff --git a/phper/src/constants.rs b/phper/src/constants.rs index 3eba5c6..7f85cbf 100644 --- a/phper/src/constants.rs +++ b/phper/src/constants.rs @@ -10,16 +10,14 @@ //! Apis relate to [zend_constant](crate::sys::zend_constant). -use crate::strings::ZString; +use crate::modules::Registerer; +use crate::sys::*; use crate::values::ZVal; -use crate::{sys::*}; use bitflags::bitflags; -use std::ffi::{c_char, c_int}; pub struct Constant { - name: String, - value: ZVal, - flags: Flags, + constant: zend_constant, + flags: i32, } // #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -43,70 +41,27 @@ bitflags! { } impl Constant { - pub fn new(name: impl Into, value: impl Into, flags: Option) -> Self { + pub fn new(name: impl AsRef, value: impl Into, flags: Option) -> Self { + let name = name.as_ref(); + let length = name.len(); + let ptr = name.as_bytes().as_ptr() as *const i8; + let flags = flags.unwrap_or(Flags::Cs | Flags::Persistent).bits() as i32; Self { - name: name.into(), - value: value.into(), - flags: flags.unwrap_or_default(), + constant: unsafe { phper_create_constant(ptr, length, value.into().inner, flags) }, + flags, } } +} - pub(crate) fn register(&self, module_number: c_int) { - let flags = self.flags.bits() as c_int; - - unsafe { - let mut name = ZString::new(self.name.clone()); - let mut constant = _zend_constant{ - value: self.value.clone().into_inner(), - name: name.as_mut_ptr(), - }; - - zend_register_constant(&mut constant); +impl Registerer for Constant { + fn register(&mut self, module_number: i32) -> Result<(), Box> { + let result = + unsafe { phper_register_constant(&mut self.constant, self.flags, module_number) }; - // match { - // Scalar::Null => { - // zend_register_null_constant(name_ptr, name_len, flags, module_number) - // } - // Scalar::Bool(b) => zend_register_bool_constant( - // name_ptr, - // name_len, - // *b as zend_bool, - // flags, - // module_number, - // ), - // Scalar::I64(i) => zend_register_long_constant( - // name_ptr, - // name_len, - // *i as zend_long, - // flags, - // module_number, - // ), - // Scalar::F64(f) => { - // zend_register_double_constant(name_ptr, name_len, *f, flags, module_number) - // } - // Scalar::String(s) => { - // let s_ptr = s.as_ptr() as *mut u8; - // zend_register_stringl_constant( - // name_ptr, - // name_len, - // s_ptr.cast(), - // s.len(), - // flags, - // module_number, - // ) - // } - // Scalar::Bytes(s) => { - // let s_ptr = s.as_ptr() as *mut u8; - // zend_register_stringl_constant( - // name_ptr, - // name_len, - // s_ptr.cast(), - // s.len(), - // flags, - // module_number, - // ) - // } - // } + if result == ZEND_RESULT_CODE_SUCCESS { + Ok(()) + } else { + Err("Failed to register new ZEND constant".into()) } } } diff --git a/phper/src/functions.rs b/phper/src/functions.rs index ff89b52..1856131 100644 --- a/phper/src/functions.rs +++ b/phper/src/functions.rs @@ -374,70 +374,20 @@ impl ZFunc { .unwrap_or(null_mut()); call_raw_common(|ret| unsafe { - #[cfg(phper_major_version = "8")] - { - let class_ptr = object - .as_mut() - .map(|o| o.get_mut_class().as_mut_ptr()) - .unwrap_or(null_mut()); - - zend_call_known_function( - function_handler, - object_ptr, - class_ptr, - ret.as_mut_ptr(), - arguments.len() as u32, - arguments.as_mut_ptr().cast(), - null_mut(), - ); - } - #[cfg(phper_major_version = "7")] - { - use std::mem::size_of; - - let called_scope = { - let mut called_scope = object - .as_mut() - .map(|o| o.get_class().as_ptr() as *mut zend_class_entry) - .unwrap_or(null_mut()); - if called_scope.is_null() { - called_scope = self.inner.common.scope; - } - called_scope - }; - - let mut fci = zend_fcall_info { - size: size_of::().try_into().unwrap(), - function_name: ZVal::from(()).into_inner(), - retval: ret.as_mut_ptr(), - params: arguments.as_mut_ptr().cast(), - object: object_ptr, - param_count: arguments.len() as u32, - no_separation: 1, - #[cfg(all(phper_major_version = "7", phper_minor_version = "0"))] - function_table: null_mut(), - #[cfg(all(phper_major_version = "7", phper_minor_version = "0"))] - symbol_table: null_mut(), - }; - - let mut fcc = zend_fcall_info_cache { - function_handler, - calling_scope: null_mut(), - called_scope, - object: object_ptr, - #[cfg(all( - phper_major_version = "7", - any( - phper_minor_version = "2", - phper_minor_version = "1", - phper_minor_version = "0", - ) - ))] - initialized: 1, - }; - - zend_call_function(&mut fci, &mut fcc); - } + let class_ptr = object + .as_mut() + .map(|o| o.get_mut_class().as_mut_ptr()) + .unwrap_or(null_mut()); + + zend_call_known_function( + function_handler, + object_ptr, + class_ptr, + ret.as_mut_ptr(), + arguments.len() as u32, + arguments.as_mut_ptr().cast(), + null_mut(), + ); }) } } diff --git a/phper/src/modules.rs b/phper/src/modules.rs index 9d832fb..81bc644 100644 --- a/phper/src/modules.rs +++ b/phper/src/modules.rs @@ -19,14 +19,13 @@ use crate::{ functions::{Function, FunctionEntity, FunctionEntry}, ini, sys::*, - types::Scalar, utils::ensure_end_with_zero, values::ZVal, }; use std::{ collections::HashMap, ffi::CString, - mem::{size_of, take, transmute, zeroed}, + mem::{size_of, take, zeroed}, os::raw::{c_int, c_uchar, c_uint, c_ushort}, ptr::{null, null_mut}, rc::Rc, @@ -34,11 +33,15 @@ use std::{ /// Global pointer hold the Module builder. /// Because PHP is single threaded, so there is no lock here. -static mut GLOBAL_MODULE: Option> = None; +static mut GLOBAL_MODULE: *mut Module = null_mut(); pub(crate) static mut GLOBAL_MODULE_NUMBER: i32 = 0; static mut GLOBAL_MODULE_ENTRY: *mut zend_module_entry = null_mut(); +unsafe fn get_module() -> &'static mut Module { + unsafe { GLOBAL_MODULE.as_mut().unwrap_unchecked() } +} + /// PHP Module information pub struct ModuleInfo { /// Module Type @@ -48,24 +51,24 @@ pub struct ModuleInfo { pub number: i32, } +pub(crate) trait Registerer { + fn register(&mut self, module_number: i32) -> Result<(), Box>; +} + unsafe extern "C" fn module_startup(_type: c_int, module_number: c_int) -> c_int { - let module = GLOBAL_MODULE.as_mut().unwrap(); + let module: &mut Module = get_module(); GLOBAL_MODULE_NUMBER = module_number; ini::register(take(&mut module.ini_entities), module_number); - for constant in &module.constants { - constant.register(module_number); + for mut entity in take(&mut module.entities).into_iter() { + entity.register(module_number).unwrap(); } - for class_entity in &module.class_entities { - let ce = class_entity.init(); - class_entity.declare_properties(ce); - } - - for interface_entity in &module.interface_entities { - interface_entity.init(); - } + // for class_entity in take(&mut module.class_entities).into_iter() { + // let ce = class_entity.init(); + // class_entity.declare_properties(ce); + // } if let Some(f) = take(&mut module.module_init) { f(ModuleInfo { @@ -79,7 +82,7 @@ unsafe extern "C" fn module_startup(_type: c_int, module_number: c_int) -> c_int unsafe extern "C" fn module_shutdown(_type: c_int, module_number: c_int) -> c_int { { - let module = GLOBAL_MODULE.as_mut().unwrap(); + let module = get_module(); ini::unregister(module_number); @@ -89,41 +92,43 @@ unsafe extern "C" fn module_shutdown(_type: c_int, module_number: c_int) -> c_in number: module_number, }); } - } - // std::mem::replace(GLOBAL_MODULE.as_mut().unwrap(), null_mut()); + if let Some(ref mut f) = take(&mut module.request_init) { + let _b = Box::from_raw(f); + } + + if let Some(ref mut f) = take(&mut module.request_shutdown) { + let _b = Box::from_raw(f); + } + } ZEND_RESULT_CODE_SUCCESS } unsafe extern "C" fn request_startup(_type: c_int, module_number: c_int) -> c_int { - let module = GLOBAL_MODULE.as_ref().unwrap(); + let f = get_module().request_init.unwrap_unchecked(); - if let Some(f) = &module.request_init { - f(ModuleInfo { - ty: _type, - number: module_number, - }); - } + f(ModuleInfo { + ty: _type, + number: module_number, + }); ZEND_RESULT_CODE_SUCCESS } unsafe extern "C" fn request_shutdown(_type: c_int, module_number: c_int) -> c_int { - let module = GLOBAL_MODULE.as_ref().unwrap(); + let f = get_module().request_shutdown.unwrap_unchecked(); - if let Some(f) = &module.request_shutdown { - f(ModuleInfo { - ty: _type, - number: module_number, - }); - } + f(ModuleInfo { + ty: _type, + number: module_number, + }); ZEND_RESULT_CODE_SUCCESS } unsafe extern "C" fn module_info(zend_module: *mut zend_module_entry) { - let module = GLOBAL_MODULE.as_ref().unwrap(); + let module = get_module(); php_info_print_table_start(); if !module.version.as_bytes().is_empty() { @@ -142,18 +147,17 @@ unsafe extern "C" fn module_info(zend_module: *mut zend_module_entry) { /// Builder for registering PHP Module. #[allow(clippy::type_complexity)] +#[derive(Default)] pub struct Module { name: CString, version: CString, author: CString, module_init: Option>, module_shutdown: Option>, - request_init: Option>, - request_shutdown: Option>, + request_init: Option<&'static dyn Fn(ModuleInfo)>, + request_shutdown: Option<&'static dyn Fn(ModuleInfo)>, function_entities: Vec, - class_entities: Vec>, - interface_entities: Vec, - constants: Vec, + entities: Vec>, ini_entities: Vec, infos: HashMap, } @@ -174,9 +178,7 @@ impl Module { request_init: None, request_shutdown: None, function_entities: vec![], - class_entities: Default::default(), - interface_entities: Default::default(), - constants: Default::default(), + entities: Default::default(), ini_entities: Default::default(), infos: Default::default(), } @@ -194,12 +196,12 @@ impl Module { /// Register `RINIT` hook. pub fn on_request_init(&mut self, func: impl Fn(ModuleInfo) + 'static) { - self.request_init = Some(Box::new(func)); + self.request_init = Some(Box::leak(Box::new(func))); } /// Register `RSHUTDOWN` hook. pub fn on_request_shutdown(&mut self, func: impl Fn(ModuleInfo) + 'static) { - self.request_shutdown = Some(Box::new(func)); + self.request_shutdown = Some(Box::leak(Box::new(func))); } /// Register function to module. @@ -220,17 +222,23 @@ impl Module { /// Register class to module. pub fn add_class(&mut self, class: ClassEntity) { - self.class_entities.push(unsafe { transmute(class) }); + self.entities.push(Box::new(class)); } /// Register interface to module. pub fn add_interface(&mut self, interface: InterfaceEntity) { - self.interface_entities.push(interface); + self.entities.push(Box::new(interface)); } /// Register constant to module. - pub fn add_constant(&mut self, name: impl Into, value: impl Into, flags: Option) { - self.constants.push(Constant::new(name, value, flags)); + pub fn add_constant( + &mut self, + name: impl AsRef, + value: impl Into, + flags: Option, + ) { + self.entities + .push(Box::new(Constant::new(name, value, flags))); } /// Register ini configuration to module. @@ -272,7 +280,7 @@ impl Module { "module version must be set" ); - let module: Box = Box::new(self); + let module = Box::leak(Box::new(self)); let entry = Box::new(zend_module_entry { size: size_of::() as c_ushort, @@ -285,8 +293,16 @@ impl Module { functions: module.function_entries(), module_startup_func: Some(module_startup), module_shutdown_func: Some(module_shutdown), - request_startup_func: Some(request_startup), - request_shutdown_func: Some(request_shutdown), + request_startup_func: if module.request_init.is_some() { + Some(request_startup) + } else { + None + }, + request_shutdown_func: if module.request_shutdown.is_some() { + Some(request_shutdown) + } else { + None + }, info_func: Some(module_info), version: module.version.as_ptr(), globals_size: 0, @@ -304,7 +320,7 @@ impl Module { build_id: phper_get_zend_module_build_id(), }); - GLOBAL_MODULE = Some(module); + GLOBAL_MODULE = module; GLOBAL_MODULE_ENTRY = Box::into_raw(entry); GLOBAL_MODULE_ENTRY diff --git a/phper/src/values.rs b/phper/src/values.rs index 0974b05..647a64d 100644 --- a/phper/src/values.rs +++ b/phper/src/values.rs @@ -180,7 +180,7 @@ impl ExecuteData { /// Wrapper of [zval]. #[repr(transparent)] pub struct ZVal { - inner: zval, + pub(crate) inner: zval, _p: PhantomData<*mut ()>, } diff --git a/tests/integration/src/constants.rs b/tests/integration/src/constants.rs index fdf40e0..4d21f7c 100644 --- a/tests/integration/src/constants.rs +++ b/tests/integration/src/constants.rs @@ -11,11 +11,11 @@ use phper::modules::Module; pub fn integrate(module: &mut Module) { - module.add_constant("INTEGRATE_CONST_NULL", ()); - module.add_constant("INTEGRATE_CONST_TRUE", true); - module.add_constant("INTEGRATE_CONST_FALSE", false); - module.add_constant("INTEGRATE_CONST_LONG", 100i64); - module.add_constant("INTEGRATE_CONST_DOUBLE", 200.); - module.add_constant("INTEGRATE_CONST_STRING", "something"); - module.add_constant("INTEGRATE_CONST_BYTES", "something".as_bytes().to_owned()); + module.add_constant("INTEGRATE_CONST_NULL", (), None); + module.add_constant("INTEGRATE_CONST_TRUE", true, None); + module.add_constant("INTEGRATE_CONST_FALSE", false, None); + module.add_constant("INTEGRATE_CONST_LONG", 100i64, None); + module.add_constant("INTEGRATE_CONST_DOUBLE", 200., None); + module.add_constant("INTEGRATE_CONST_STRING", "something", None); + module.add_constant("INTEGRATE_CONST_BYTES", "something".as_bytes().to_owned(), None); } From 4b95c9a570f4850c9266574cf0c0d1cee9459415 Mon Sep 17 00:00:00 2001 From: Dusan Malusev Date: Wed, 10 Jan 2024 21:46:29 +0100 Subject: [PATCH 3/5] implement optimized layout for zend entries Signed-off-by: Dusan Malusev --- examples/complex/src/lib.rs | 4 +- examples/http-client/src/client.rs | 16 +- examples/http-client/src/errors.rs | 2 +- examples/http-client/src/request.rs | 11 +- examples/http-client/src/response.rs | 12 +- examples/http-server/src/errors.rs | 2 +- examples/http-server/src/request.rs | 15 +- examples/http-server/src/response.rs | 9 +- examples/http-server/src/server.rs | 2 +- phper-sys/c/php_wrapper.c | 22 +- phper-sys/include/phper.h | 428 ++++++++++++--------------- phper/src/classes/entity.rs | 59 ++-- phper/src/classes/mod.rs | 56 +--- phper/src/functions.rs | 8 +- phper/src/lib.rs | 1 + phper/src/modules.rs | 36 ++- phper/src/objects.rs | 43 +-- phper/src/values.rs | 4 +- tests/integration/src/classes.rs | 22 +- tests/integration/src/objects.rs | 6 +- 20 files changed, 366 insertions(+), 392 deletions(-) diff --git a/examples/complex/src/lib.rs b/examples/complex/src/lib.rs index 4388a4b..a5b8596 100644 --- a/examples/complex/src/lib.rs +++ b/examples/complex/src/lib.rs @@ -77,7 +77,7 @@ pub fn get_module() -> Module { foo_class.add_method( "getFoo", Visibility::Public, - |this: &mut StateObj<()>, _: &mut [ZVal]| { + |this: &mut StateObj, _: &mut [ZVal]| { let prop = this.get_property("foo"); Ok::<_, phper::Error>(prop.clone()) }, @@ -86,7 +86,7 @@ pub fn get_module() -> Module { .add_method( "setFoo", Visibility::Public, - |this: &mut StateObj<()>, arguments: &mut [ZVal]| -> phper::Result<()> { + |this: &mut StateObj, arguments: &mut [ZVal]| -> phper::Result<()> { this.set_property("foo", arguments[0].clone()); Ok(()) }, diff --git a/examples/http-client/src/client.rs b/examples/http-client/src/client.rs index 1edaff1..0e326cc 100644 --- a/examples/http-client/src/client.rs +++ b/examples/http-client/src/client.rs @@ -21,12 +21,14 @@ const HTTP_CLIENT_BUILDER_CLASS_NAME: &str = "HttpClient\\HttpClientBuilder"; const HTTP_CLIENT_CLASS_NAME: &str = "HttpClient\\HttpClient"; -static HTTP_CLIENT_CLASS: StaticStateClass> = StaticStateClass::null(); +static HTTP_CLIENT_CLASS: StaticStateClass = StaticStateClass::null(); -pub fn make_client_builder_class() -> ClassEntity { +pub fn make_client_builder_class() -> ClassEntity { // `new_with_default_state_constructor` means initialize the state of // `ClientBuilder` as `Default::default`. - let mut class = ClassEntity::new_with_default_state_constructor(HTTP_CLIENT_BUILDER_CLASS_NAME); + let mut class = ClassEntity::new_with_default_state_constructor::>( + HTTP_CLIENT_BUILDER_CLASS_NAME, + ); // Inner call the `ClientBuilder::timeout`. class @@ -63,9 +65,9 @@ pub fn make_client_builder_class() -> ClassEntity { class } -pub fn make_client_class() -> ClassEntity> { +pub fn make_client_class() -> ClassEntity { let mut class = - ClassEntity::>::new_with_default_state_constructor(HTTP_CLIENT_CLASS_NAME); + ClassEntity::new_with_default_state_constructor::>(HTTP_CLIENT_CLASS_NAME); class.bind(&HTTP_CLIENT_CLASS); @@ -76,7 +78,7 @@ pub fn make_client_class() -> ClassEntity> { class .add_method("get", Visibility::Public, |this, arguments| { let url = arguments[0].expect_z_str()?.to_str().unwrap(); - let client = this.as_state().as_ref().unwrap(); + let client = this.as_state::>().as_ref().unwrap(); let request_builder = client.get(url); let mut object = REQUEST_BUILDER_CLASS.init_object()?; *object.as_mut_state() = Some(request_builder); @@ -87,7 +89,7 @@ pub fn make_client_class() -> ClassEntity> { class .add_method("post", Visibility::Public, |this, arguments| { let url = arguments[0].expect_z_str()?.to_str().unwrap(); - let client = this.as_state().as_ref().unwrap(); + let client = this.as_state::>().as_ref().unwrap(); let request_builder = client.post(url); let mut object = REQUEST_BUILDER_CLASS.init_object()?; *object.as_mut_state() = Some(request_builder); diff --git a/examples/http-client/src/errors.rs b/examples/http-client/src/errors.rs index e389f8f..d99854f 100644 --- a/examples/http-client/src/errors.rs +++ b/examples/http-client/src/errors.rs @@ -16,7 +16,7 @@ use phper::{ /// The exception class name of extension. const EXCEPTION_CLASS_NAME: &str = "HttpClient\\HttpClientException"; -pub fn make_exception_class() -> ClassEntity<()> { +pub fn make_exception_class() -> ClassEntity { let mut class = ClassEntity::new(EXCEPTION_CLASS_NAME); // The `extends` is same as the PHP class `extends`. class.extends(exception_class); diff --git a/examples/http-client/src/request.rs b/examples/http-client/src/request.rs index d07b07b..43aee3e 100644 --- a/examples/http-client/src/request.rs +++ b/examples/http-client/src/request.rs @@ -15,11 +15,10 @@ use std::{convert::Infallible, mem::take}; pub const REQUEST_BUILDER_CLASS_NAME: &str = "HttpClient\\RequestBuilder"; -pub static REQUEST_BUILDER_CLASS: StaticStateClass> = - StaticStateClass::null(); +pub static REQUEST_BUILDER_CLASS: StaticStateClass = StaticStateClass::null(); -pub fn make_request_builder_class() -> ClassEntity> { - let mut class = ClassEntity::>::new_with_default_state_constructor( +pub fn make_request_builder_class() -> ClassEntity { + let mut class = ClassEntity::new_with_default_state_constructor::>( REQUEST_BUILDER_CLASS_NAME, ); @@ -30,8 +29,8 @@ pub fn make_request_builder_class() -> ClassEntity> { }); class.add_method("send", Visibility::Public, |this, _arguments| { - let state = take(this.as_mut_state()); - let response = state.unwrap().send().map_err(HttpClientError::Reqwest)?; + let state = take(this.as_mut_state::>()).unwrap(); + let response = state.send().map_err(HttpClientError::Reqwest)?; let mut object = RESPONSE_CLASS.new_object([])?; *object.as_mut_state() = Some(response); Ok::<_, phper::Error>(object) diff --git a/examples/http-client/src/response.rs b/examples/http-client/src/response.rs index 6f57c31..c2a53ae 100644 --- a/examples/http-client/src/response.rs +++ b/examples/http-client/src/response.rs @@ -19,16 +19,16 @@ use std::mem::take; pub const RESPONSE_CLASS_NAME: &str = "HttpClient\\Response"; -pub static RESPONSE_CLASS: StaticStateClass> = StaticStateClass::null(); +pub static RESPONSE_CLASS: StaticStateClass = StaticStateClass::null(); -pub fn make_response_class() -> ClassEntity> { +pub fn make_response_class() -> ClassEntity { let mut class = - ClassEntity::>::new_with_default_state_constructor(RESPONSE_CLASS_NAME); + ClassEntity::new_with_default_state_constructor::>(RESPONSE_CLASS_NAME); class.bind(&RESPONSE_CLASS); class.add_method("body", Visibility::Public, |this, _arguments| { - let response = take(this.as_mut_state()); + let response = take(this.as_mut_state::>()); let response = response.ok_or(HttpClientError::ResponseHadRead)?; let body = response.bytes().map_err(HttpClientError::Reqwest)?; Ok::<_, phper::Error>(body.to_vec()) @@ -36,7 +36,7 @@ pub fn make_response_class() -> ClassEntity> { class.add_method("status", Visibility::Public, |this, _arguments| { let response = - this.as_state() + this.as_state::>() .as_ref() .ok_or_else(|| HttpClientError::ResponseAfterRead { method_name: "status".to_owned(), @@ -47,7 +47,7 @@ pub fn make_response_class() -> ClassEntity> { class.add_method("headers", Visibility::Public, |this, _arguments| { let response = - this.as_state() + this.as_state::>() .as_ref() .ok_or_else(|| HttpClientError::ResponseAfterRead { method_name: "headers".to_owned(), diff --git a/examples/http-server/src/errors.rs b/examples/http-server/src/errors.rs index c5fb151..a014f13 100644 --- a/examples/http-server/src/errors.rs +++ b/examples/http-server/src/errors.rs @@ -40,7 +40,7 @@ impl From for phper::Error { } /// Register the class `HttpServer\HttpServerException` by `ClassEntity`. -pub fn make_exception_class() -> ClassEntity<()> { +pub fn make_exception_class() -> ClassEntity { let mut class = ClassEntity::new(EXCEPTION_CLASS_NAME); // As an Exception class, inheriting from the base Exception class is important. class.extends(exception_class); diff --git a/examples/http-server/src/request.rs b/examples/http-server/src/request.rs index e4c22f8..d7fb43a 100644 --- a/examples/http-server/src/request.rs +++ b/examples/http-server/src/request.rs @@ -17,10 +17,10 @@ use std::convert::Infallible; pub const HTTP_REQUEST_CLASS_NAME: &str = "HttpServer\\HttpRequest"; -pub static HTTP_REQUEST_CLASS: StaticStateClass<()> = StaticStateClass::null(); +pub static HTTP_REQUEST_CLASS: StaticStateClass = StaticStateClass::null(); /// Register the class `HttpServer\HttpRequest` by `ClassEntity`. -pub fn make_request_class() -> ClassEntity<()> { +pub fn make_request_class() -> ClassEntity { let mut class = ClassEntity::new(HTTP_REQUEST_CLASS_NAME); // The state class will be initialized after class registered. @@ -34,15 +34,16 @@ pub fn make_request_class() -> ClassEntity<()> { // Register the constructor method with public visibility, initialize the // headers with empty array. - class.add_method("__construct", Visibility::Public, |this, _arguments| { - this.set_property("headers", ZArray::new()); - Ok::<_, Infallible>(()) - }); + class + .add_method("__construct", Visibility::Public, |this, _arguments| { + this.set_property("headers", ZArray::new()); + Ok::<_, Infallible>(()) + }); class } /// Instantiate the object with class `HttpServer\HttpRequest`. -pub fn new_request_object() -> phper::Result> { +pub fn new_request_object() -> phper::Result { HTTP_REQUEST_CLASS.new_object([]) } diff --git a/examples/http-server/src/response.rs b/examples/http-server/src/response.rs index ed9b5f3..89bff29 100644 --- a/examples/http-server/src/response.rs +++ b/examples/http-server/src/response.rs @@ -21,12 +21,13 @@ use phper::{ pub const HTTP_RESPONSE_CLASS_NAME: &str = "HttpServer\\HttpResponse"; -pub static HTTP_RESPONSE_CLASS: StaticStateClass> = StaticStateClass::null(); +pub static HTTP_RESPONSE_CLASS: StaticStateClass = StaticStateClass::null(); /// Register the class `HttpServer\HttpResponse` by `ClassEntity`, with the /// inner state `Response`. -pub fn make_response_class() -> ClassEntity> { - let mut class = ClassEntity::new_with_default_state_constructor(HTTP_RESPONSE_CLASS_NAME); +pub fn make_response_class() -> ClassEntity { + let mut class = + ClassEntity::new_with_default_state_constructor::>(HTTP_RESPONSE_CLASS_NAME); // The state class will be initialized after class registered. class.bind(&HTTP_RESPONSE_CLASS); @@ -64,6 +65,6 @@ pub fn make_response_class() -> ClassEntity> { } /// Instantiate the object with class `HttpServer\HttpResponse`. -pub fn new_response_object() -> phper::Result>> { +pub fn new_response_object() -> phper::Result { HTTP_RESPONSE_CLASS.new_object([]) } diff --git a/examples/http-server/src/server.rs b/examples/http-server/src/server.rs index 8d44630..6c1279e 100644 --- a/examples/http-server/src/server.rs +++ b/examples/http-server/src/server.rs @@ -35,7 +35,7 @@ thread_local! { } /// Register the class `HttpServer\HttpServer` by `ClassEntity`. -pub fn make_server_class() -> ClassEntity<()> { +pub fn make_server_class() -> ClassEntity { let mut class = ClassEntity::new(HTTP_SERVER_CLASS_NAME); // Register the server host field with public visibility. diff --git a/phper-sys/c/php_wrapper.c b/phper-sys/c/php_wrapper.c index 65e1c19..185c259 100644 --- a/phper-sys/c/php_wrapper.c +++ b/phper-sys/c/php_wrapper.c @@ -50,11 +50,25 @@ uint32_t phper_zend_object_gc_refcount(const zend_object *obj) { zend_class_entry * phper_init_class_entry_ex(const char *class_name, size_t class_name_len, const zend_function_entry *functions, - phper_init_class_entry_handler handler, - void *argument) { - zend_class_entry class_ce; + zend_class_entry *parent) { + zend_class_entry class_ce = {0}; INIT_CLASS_ENTRY_EX(class_ce, class_name, class_name_len, functions); - return handler(&class_ce, argument); + + if (parent == NULL) { + return zend_register_internal_class(&class_ce); + } + return zend_register_internal_class_ex(&class_ce, parent); +} + +zend_class_entry * +phper_init_interface_entry_ex(const char *class_name, size_t class_name_len, + const zend_function_entry *functions) { + zend_class_entry class_ce = {0}; + INIT_CLASS_ENTRY_EX(class_ce, class_name, class_name_len, functions); + + zend_class_entry *class_ptr; + + return zend_register_internal_interface(&class_ce); } bool phper_instanceof_function(const zend_class_entry *instance_ce, diff --git a/phper-sys/include/phper.h b/phper-sys/include/phper.h index cbd2a4c..cd3ece3 100644 --- a/phper-sys/include/phper.h +++ b/phper-sys/include/phper.h @@ -19,280 +19,244 @@ typedef ZEND_INI_MH(phper_zend_ini_mh); typedef zend_class_entry * phper_init_class_entry_handler(zend_class_entry *class_ce, void *argument); - void *phper_emalloc(size_t size); - void phper_efree(void *ptr); +void *phper_emalloc(size_t size); +void phper_efree(void *ptr); // ================================================== // zval apis: // ================================================== - const zend_long *phper_z_lval_p(const zval *zv); - const double *phper_z_dval_p(const zval *zv); - const zend_string *phper_z_str_p(const zval *zv); - const char *phper_z_strval_p(const zval *v); - const zend_array *phper_z_arr_p(const zval *zv); - bool phper_z_refcounted_p(const zval *zval_ptr); - int phper_z_res_handle_p(const zval *val); - uint32_t phper_z_type_info_p(const zval *zv); - int phper_z_type_p(const zval *zv); - const zend_resource *phper_z_res_p(const zval *zv); - const zend_reference *phper_z_ref_p(const zval *zv); - const zend_object_handlers *phper_z_obj_ht_p(const zval *zv); - const zend_object *phper_z_obj_p(const zval *zv); - uint32_t phper_z_addref_p(zval *zv); - zend_function *phper_z_func_p(const zval *zv); - const void *phper_z_ptr_p(const zval *zv); - zend_uchar phper_zval_get_type(const zval *pz); - void phper_zval_arr(zval *val, zend_array *arr); - void phper_zval_new_arr(zval *val); - void phper_zval_stringl(zval *val, const char *s, size_t len); - void phper_zval_zval(zval *val, zval *zv, int copy, int dtor); - void phper_zval_copy(zval *val, const zval *zv); - void phper_zval_copy_value(zval *val, const zval *zv); - zend_string *phper_zval_get_string(zval *op); - zend_long phper_zval_get_long(const zval *op); - void phper_zval_obj(zval *z, zend_object *o); - void phper_zval_func(zval *z, zend_function *f); - void phper_zval_ptr_dtor(zval *zv); - void phper_zval_ptr_dtor_nogc(zval *zval_ptr); - void phper_zval_null(zval *zv); - void phper_zval_bool(zval *zv, bool value); - void phper_zval_long(zval *zv, zend_long l); - void phper_zval_double(zval *zv, double d); - void phper_zval_str(zval *zv, zend_string *s); - void phper_convert_to_long(zval *op); - void phper_convert_to_boolean(zval *op); - void phper_convert_to_null(zval *op); - void phper_convert_to_double(zval *op); - void phper_convert_to_array(zval *op); - void phper_convert_to_object(zval *op); - void phper_convert_to_string(zval *op); - void phper_separate_array(zval *zv); - void phper_separate_string(zval *zv); - void phper_separate_zval(zval *zv); +const zend_long *phper_z_lval_p(const zval *zv); +const double *phper_z_dval_p(const zval *zv); +const zend_string *phper_z_str_p(const zval *zv); +const char *phper_z_strval_p(const zval *v); +const zend_array *phper_z_arr_p(const zval *zv); +bool phper_z_refcounted_p(const zval *zval_ptr); +int phper_z_res_handle_p(const zval *val); +uint32_t phper_z_type_info_p(const zval *zv); +int phper_z_type_p(const zval *zv); +const zend_resource *phper_z_res_p(const zval *zv); +const zend_reference *phper_z_ref_p(const zval *zv); +const zend_object_handlers *phper_z_obj_ht_p(const zval *zv); +const zend_object *phper_z_obj_p(const zval *zv); +uint32_t phper_z_addref_p(zval *zv); +zend_function *phper_z_func_p(const zval *zv); +const void *phper_z_ptr_p(const zval *zv); +zend_uchar phper_zval_get_type(const zval *pz); +void phper_zval_arr(zval *val, zend_array *arr); +void phper_zval_new_arr(zval *val); +void phper_zval_stringl(zval *val, const char *s, size_t len); +void phper_zval_zval(zval *val, zval *zv, int copy, int dtor); +void phper_zval_copy(zval *val, const zval *zv); +void phper_zval_copy_value(zval *val, const zval *zv); +zend_string *phper_zval_get_string(zval *op); +zend_long phper_zval_get_long(const zval *op); +void phper_zval_obj(zval *z, zend_object *o); +void phper_zval_func(zval *z, zend_function *f); +void phper_zval_ptr_dtor(zval *zv); +void phper_zval_ptr_dtor_nogc(zval *zval_ptr); +void phper_zval_null(zval *zv); +void phper_zval_bool(zval *zv, bool value); +void phper_zval_long(zval *zv, zend_long l); +void phper_zval_double(zval *zv, double d); +void phper_zval_str(zval *zv, zend_string *s); +void phper_convert_to_long(zval *op); +void phper_convert_to_boolean(zval *op); +void phper_convert_to_null(zval *op); +void phper_convert_to_double(zval *op); +void phper_convert_to_array(zval *op); +void phper_convert_to_object(zval *op); +void phper_convert_to_string(zval *op); +void phper_separate_array(zval *zv); +void phper_separate_string(zval *zv); +void phper_separate_zval(zval *zv); // ================================================== // string apis: // ================================================== - zend_string *phper_zend_new_interned_string(zend_string *str); +zend_string *phper_zend_new_interned_string(zend_string *str); - zend_string *phper_zend_string_init(const char *str, size_t len, - int persistent); - zend_string *phper_zend_string_alloc(size_t len, int persistent); - void phper_zend_string_release(zend_string *s); - int phper_zstr_len(const zend_string *s); - const char *phper_zstr_val(const zend_string *s); - zend_string *phper_zend_string_copy(zend_string *s); +zend_string *phper_zend_string_init(const char *str, size_t len, + int persistent); +zend_string *phper_zend_string_alloc(size_t len, int persistent); +void phper_zend_string_release(zend_string *s); +int phper_zstr_len(const zend_string *s); +const char *phper_zstr_val(const zend_string *s); +zend_string *phper_zend_string_copy(zend_string *s); // ================================================== // string builder apis: // ================================================== - void phper_smart_str_alloc(smart_str *str, size_t len, +void phper_smart_str_alloc(smart_str *str, size_t len, bool persistent); +void phper_smart_str_extend_ex(smart_str *dest, size_t len, bool persistent); +void phper_smart_str_erealloc(smart_str *str, size_t len); +void phper_smart_str_realloc(smart_str *str, size_t len); +void phper_smart_str_free_ex(smart_str *str, bool persistent); +void phper_smart_str_append_escaped(smart_str *str, const char *s, size_t l); +void phper_smart_str_append_double(smart_str *str, double num, int precision, + bool zero_fraction); +void phper_smart_str_append_escaped_truncated(smart_str *str, + const zend_string *value, + size_t length); + +void phper_smart_str_append_scalar(smart_str *str, const zval *value, + size_t truncate); +void phper_smart_str_0(smart_str *str); +size_t phper_smart_str_get_len(const smart_str *str); +zend_string *phper_smart_str_extract(smart_str *str); +void phper_smart_str_appendc_ex(smart_str *dest, char ch, bool persistent); + +void phper_smart_str_appendl_ex(smart_str *dest, const char *str, size_t len, + bool persistent); + +void phper_smart_str_append_ex(smart_str *dest, const zend_string *src, + bool persistent); +void phper_smart_str_append_smart_str_ex(smart_str *dest, const smart_str *src, bool persistent); - void phper_smart_str_extend_ex(smart_str *dest, size_t len, - bool persistent); - void phper_smart_str_erealloc(smart_str *str, size_t len); - void phper_smart_str_realloc(smart_str *str, size_t len); - void phper_smart_str_free_ex(smart_str *str, bool persistent); - void phper_smart_str_append_escaped(smart_str *str, const char *s, - size_t l); - void phper_smart_str_append_double(smart_str *str, double num, - int precision, - bool zero_fraction); - void phper_smart_str_append_escaped_truncated( - smart_str *str, const zend_string *value, size_t length); - - void phper_smart_str_append_scalar(smart_str *str, - const zval *value, - size_t truncate); - void phper_smart_str_0(smart_str *str); - size_t phper_smart_str_get_len(const smart_str *str); - zend_string *phper_smart_str_extract(smart_str *str); - void phper_smart_str_appendc_ex(smart_str *dest, char ch, - bool persistent); - - void phper_smart_str_appendl_ex(smart_str *dest, const char *str, - size_t len, bool persistent); - - void phper_smart_str_append_ex(smart_str *dest, - const zend_string *src, - bool persistent); - void phper_smart_str_append_smart_str_ex(smart_str *dest, - const smart_str *src, - bool persistent); - void -phper_smart_str_append_long_ex(smart_str *dest, zend_long num, bool persistent); - void phper_smart_str_append_unsigned_ex(smart_str *dest, - zend_ulong num, - bool persistent); - void phper_smart_str_setl(smart_str *dest, const char *src, - size_t len); +void phper_smart_str_append_long_ex(smart_str *dest, zend_long num, + bool persistent); +void phper_smart_str_append_unsigned_ex(smart_str *dest, zend_ulong num, + bool persistent); +void phper_smart_str_setl(smart_str *dest, const char *src, size_t len); // ================================================== // string builder apis: // ================================================== - void phper_smart_str_alloc(smart_str *str, size_t len, +void phper_smart_str_alloc(smart_str *str, size_t len, bool persistent); +void phper_smart_str_extend_ex(smart_str *dest, size_t len, bool persistent); +void phper_smart_str_erealloc(smart_str *str, size_t len); +void phper_smart_str_realloc(smart_str *str, size_t len); +void phper_smart_str_free_ex(smart_str *str, bool persistent); +void phper_smart_str_append_escaped(smart_str *str, const char *s, size_t l); +void phper_smart_str_append_double(smart_str *str, double num, int precision, + bool zero_fraction); +void phper_smart_str_append_escaped_truncated(smart_str *str, + const zend_string *value, + size_t length); + +void phper_smart_str_append_scalar(smart_str *str, const zval *value, + size_t truncate); +void phper_smart_str_0(smart_str *str); +size_t phper_smart_str_get_len(const smart_str *str); +zend_string *phper_smart_str_extract(smart_str *str); +void phper_smart_str_appendc_ex(smart_str *dest, char ch, bool persistent); + +void phper_smart_str_appendl_ex(smart_str *dest, const char *str, size_t len, + bool persistent); + +void phper_smart_str_append_ex(smart_str *dest, const zend_string *src, + bool persistent); +void phper_smart_str_append_smart_str_ex(smart_str *dest, const smart_str *src, bool persistent); - void phper_smart_str_extend_ex(smart_str *dest, size_t len, - bool persistent); - void phper_smart_str_erealloc(smart_str *str, size_t len); - void phper_smart_str_realloc(smart_str *str, size_t len); - void phper_smart_str_free_ex(smart_str *str, bool persistent); - void phper_smart_str_append_escaped(smart_str *str, const char *s, - size_t l); - void phper_smart_str_append_double(smart_str *str, double num, - int precision, - bool zero_fraction); - void phper_smart_str_append_escaped_truncated( - smart_str *str, const zend_string *value, size_t length); - - void phper_smart_str_append_scalar(smart_str *str, - const zval *value, - size_t truncate); - void phper_smart_str_0(smart_str *str); - size_t phper_smart_str_get_len(const smart_str *str); - zend_string *phper_smart_str_extract(smart_str *str); - void phper_smart_str_appendc_ex(smart_str *dest, char ch, - bool persistent); - - void phper_smart_str_appendl_ex(smart_str *dest, const char *str, - size_t len, bool persistent); - - void phper_smart_str_append_ex(smart_str *dest, - const zend_string *src, - bool persistent); - void phper_smart_str_append_smart_str_ex(smart_str *dest, - const smart_str *src, - bool persistent); - void -phper_smart_str_append_long_ex(smart_str *dest, zend_long num, bool persistent); - void phper_smart_str_append_unsigned_ex(smart_str *dest, - zend_ulong num, - bool persistent); - void phper_smart_str_setl(smart_str *dest, const char *src, - size_t len); +void phper_smart_str_append_long_ex(smart_str *dest, zend_long num, + bool persistent); +void phper_smart_str_append_unsigned_ex(smart_str *dest, zend_ulong num, + bool persistent); +void phper_smart_str_setl(smart_str *dest, const char *src, size_t len); // ================================================== // array apis: // ================================================== - zval *phper_zend_hash_str_update(HashTable *ht, const char *key, - size_t len, zval *pData); - - zval *phper_zend_hash_index_update(HashTable *ht, zend_ulong h, - zval *pData); - - zval *phper_zend_hash_next_index_insert(HashTable *ht, - zval *pData); - - void phper_array_init(zval *arg); - void *phper_zend_hash_str_find_ptr(const HashTable *ht, - const char *str, size_t len); - bool phper_zend_hash_str_exists(const HashTable *ht, - const char *str, size_t len); - bool phper_zend_hash_index_exists(const HashTable *ht, - zend_ulong h); - zend_array *phper_zend_new_array(uint32_t size); - zend_array *phper_zend_array_dup(zend_array *source); - zval *phper_zend_hash_index_find(const HashTable *ht, - zend_ulong h); - bool phper_zend_hash_index_del(HashTable *ht, zend_ulong h); - zval *phper_zend_symtable_str_update(HashTable *ht, - const char *str, size_t len, - zval *pData); - - bool phper_zend_symtable_str_del(HashTable *ht, const char *str, - size_t len); - zval *phper_zend_symtable_str_find(HashTable *ht, const char *str, - size_t len); - - bool phper_zend_symtable_str_exists(HashTable *ht, - const char *str, size_t len); - - zval *phper_zend_str_update(HashTable *ht, const char *str, - size_t len, zval *pData); - bool phper_zend_str_del(HashTable *ht, const char *str, - size_t len); - zval *phper_zend_str_find(HashTable *ht, const char *str, - size_t len); - bool phper_zend_str_exists(HashTable *ht, const char *str, - size_t len); +zval *phper_zend_hash_str_update(HashTable *ht, const char *key, size_t len, + zval *pData); + +zval *phper_zend_hash_index_update(HashTable *ht, zend_ulong h, zval *pData); + +zval *phper_zend_hash_next_index_insert(HashTable *ht, zval *pData); + +void phper_array_init(zval *arg); +void *phper_zend_hash_str_find_ptr(const HashTable *ht, const char *str, + size_t len); +bool phper_zend_hash_str_exists(const HashTable *ht, const char *str, + size_t len); +bool phper_zend_hash_index_exists(const HashTable *ht, zend_ulong h); +zend_array *phper_zend_new_array(uint32_t size); +zend_array *phper_zend_array_dup(zend_array *source); +zval *phper_zend_hash_index_find(const HashTable *ht, zend_ulong h); +bool phper_zend_hash_index_del(HashTable *ht, zend_ulong h); +zval *phper_zend_symtable_str_update(HashTable *ht, const char *str, size_t len, + zval *pData); + +bool phper_zend_symtable_str_del(HashTable *ht, const char *str, size_t len); +zval *phper_zend_symtable_str_find(HashTable *ht, const char *str, size_t len); + +bool phper_zend_symtable_str_exists(HashTable *ht, const char *str, size_t len); + +zval *phper_zend_str_update(HashTable *ht, const char *str, size_t len, + zval *pData); +bool phper_zend_str_del(HashTable *ht, const char *str, size_t len); +zval *phper_zend_str_find(HashTable *ht, const char *str, size_t len); +bool phper_zend_str_exists(HashTable *ht, const char *str, size_t len); // ================================================== // object apis: // ================================================== - zval *phper_get_this(zend_execute_data *execute_data); - size_t phper_zend_object_properties_size(zend_class_entry *ce); - void *phper_zend_object_alloc(size_t obj_size, - zend_class_entry *ce); - zend_object *(**phper_get_create_object(zend_class_entry *ce))( +zval *phper_get_this(zend_execute_data *execute_data); +size_t phper_zend_object_properties_size(zend_class_entry *ce); +void *phper_zend_object_alloc(size_t obj_size, zend_class_entry *ce); +zend_object *(**phper_get_create_object(zend_class_entry *ce))( zend_class_entry *class_type); - bool phper_object_init_ex(zval *arg, - zend_class_entry *class_type); - void phper_zend_object_release(zend_object *obj); - uint32_t phper_zend_object_gc_refcount(const zend_object *obj); +bool phper_object_init_ex(zval *arg, zend_class_entry *class_type); +void phper_zend_object_release(zend_object *obj); +uint32_t phper_zend_object_gc_refcount(const zend_object *obj); // ================================================== // class apis: // ================================================== - zend_class_entry * +zend_class_entry * phper_init_class_entry_ex(const char *class_name, size_t class_name_len, const zend_function_entry *functions, - phper_init_class_entry_handler handler, - void *argument); - bool -phper_instanceof_function(const zend_class_entry *instance_ce, - const zend_class_entry *ce); - zend_string * -phper_get_function_or_method_name(const zend_function *func); - zend_string *phper_get_function_name(const zend_function *func); - bool phper_call_user_function(HashTable *function_table, - zval *object, zval *function_name, - zval *retval_ptr, - uint32_t param_count, - zval params[]); - zval *phper_zend_call_var_num(zend_execute_data *execute_data, - int index); - zval *phper_zend_call_arg(zend_execute_data *execute_data, - int index); - uint32_t -phper_zend_num_args(const zend_execute_data *execute_data); - bool phper_zend_get_parameters_array_ex(uint32_t param_count, - zval *argument_array); + zend_class_entry *argument); +zend_class_entry * +phper_init_interface_entry_ex(const char *class_name, size_t class_name_len, + const zend_function_entry *functions); +bool phper_instanceof_function(const zend_class_entry *instance_ce, + const zend_class_entry *ce); + +zend_string *phper_get_function_or_method_name(const zend_function *func); +zend_string *phper_get_function_name(const zend_function *func); +bool phper_call_user_function(HashTable *function_table, zval *object, + zval *function_name, zval *retval_ptr, + uint32_t param_count, zval params[]); +zval *phper_zend_call_var_num(zend_execute_data *execute_data, int index); +zval *phper_zend_call_arg(zend_execute_data *execute_data, int index); +uint32_t phper_zend_num_args(const zend_execute_data *execute_data); +bool phper_zend_get_parameters_array_ex(uint32_t param_count, + zval *argument_array); // ================================================== // module apis: // ================================================== - const char *phper_get_zend_module_build_id(); - zend_resource * -phper_register_persistent_resource(const zend_string *id, const void *ptr, - int le_id); - int phper_zend_register_persistent_list_destructors( - rsrc_dtor_func_t dtor, const char *name, int module_number); - int -phper_zend_register_list_destructors(const rsrc_dtor_func_t dtor, - const char *name, int module_number); - int -phper_zend_register_list_destructors_ex(const rsrc_dtor_func_t dtor, - const rsrc_dtor_func_t pdtor, - const char *name, int module_number); - int phper_zend_fetch_list_dtor_id(const char *name); - const zend_resource * -phper_register_persistent_find(const char *hash, size_t len); +const char *phper_get_zend_module_build_id(); +zend_resource *phper_register_persistent_resource(const zend_string *id, + const void *ptr, int le_id); +int phper_zend_register_persistent_list_destructors(rsrc_dtor_func_t dtor, + const char *name, + int module_number); +int phper_zend_register_list_destructors(const rsrc_dtor_func_t dtor, + const char *name, int module_number); +int phper_zend_register_list_destructors_ex(const rsrc_dtor_func_t dtor, + const rsrc_dtor_func_t pdtor, + const char *name, + int module_number); +int phper_zend_fetch_list_dtor_id(const char *name); +const zend_resource *phper_register_persistent_find(const char *hash, + size_t len); // ================================================== // Argument API: // ================================================== - zend_internal_arg_info phper_zend_begin_arg_info_ex( - bool return_reference, uintptr_t required_num_args); - zend_internal_arg_info phper_zend_arg_info(bool pass_by_ref, - const char *name); - // ================================================== - // Constants API: - // ================================================== - zend_constant phper_create_constant(const char *name, size_t name_len, - zval val, int flags); - - zend_result phper_register_constant(zend_constant *constant, int flags, - int module_number); \ No newline at end of file +zend_internal_arg_info +phper_zend_begin_arg_info_ex(bool return_reference, + uintptr_t required_num_args); +zend_internal_arg_info phper_zend_arg_info(bool pass_by_ref, const char *name); +// ================================================== +// Constants API: +// ================================================== +zend_constant phper_create_constant(const char *name, size_t name_len, zval val, + int flags); + +zend_result phper_register_constant(zend_constant *constant, int flags, + int module_number); \ No newline at end of file diff --git a/phper/src/classes/entity.rs b/phper/src/classes/entity.rs index acdcfd2..61965b5 100644 --- a/phper/src/classes/entity.rs +++ b/phper/src/classes/entity.rs @@ -14,60 +14,64 @@ use crate::{ }; use super::{ - class_init_handler, create_object, entry::ClassEntry, PropertyEntity, StateCloner, - StateConstructor, StaticStateClass, Visibility, + create_object, entry::ClassEntry, PropertyEntity, StateCloner, StateConstructor, + StaticStateClass, Visibility, }; /// Builder for registering class. /// -/// `` means the type of holding state. -/// /// *It is a common practice for PHP extensions to use PHP objects to package /// third-party resources.* -pub struct ClassEntity { +pub struct ClassEntity { class_name: CString, state_constructor: Rc, method_entities: Vec, property_entities: Vec, parent: Option &'static ClassEntry>>, interfaces: Vec &'static ClassEntry>>, - bind_class: Option<&'static StaticStateClass>, + bind_class: Option<&'static StaticStateClass>, state_cloner: Option>, - _p: PhantomData<(*mut (), T)>, + _p: PhantomData<*mut ()>, } -impl ClassEntity<()> { +impl ClassEntity { /// Construct a new `ClassEntity` with class name, do not own state. pub fn new(class_name: impl Into) -> Self { - Self::new_with_state_constructor(class_name, || ()) + Self::new_with_state_constructor::<()>(class_name, || ()) } } -impl ClassEntity { +impl ClassEntity { /// Construct a new `ClassEntity` with class name and default state /// constructor. - pub fn new_with_default_state_constructor(class_name: impl Into) -> Self { - Self::new_with_state_constructor(class_name, Default::default) + pub fn new_with_default_state_constructor(class_name: impl Into) -> Self + where + T: Default + 'static, + { + Self::new_with_state_constructor(class_name, T::default) } } -pub trait Handler { - fn execute(&self, state: &mut StateObj, args: &mut [ZVal]) -> Result; +pub trait Handler { + fn execute(&self, state: &mut StateObj, args: &mut [ZVal]) -> Result; } -impl Handler for dyn Fn(&mut StateObj, &mut [ZVal]) -> Result + 'static { - fn execute(&self, state: &mut StateObj, args: &mut [ZVal]) -> Result { +impl Handler for dyn Fn(&mut StateObj, &mut [ZVal]) -> Result + 'static { + fn execute(&self, state: &mut StateObj, args: &mut [ZVal]) -> Result { self(state, args) } } -impl ClassEntity { +impl ClassEntity { /// Construct a new `ClassEntity` with class name and the constructor to /// build state. - pub fn new_with_state_constructor( + pub fn new_with_state_constructor( class_name: impl Into, state_constructor: impl Fn() -> T + 'static, - ) -> Self { + ) -> Self + where + T: 'static, + { Self { class_name: crate::utils::ensure_end_with_zero(class_name), state_constructor: Rc::new(move || { @@ -79,9 +83,9 @@ impl ClassEntity { property_entities: Vec::new(), parent: None, interfaces: Vec::new(), - bind_class: None, state_cloner: None, - _p: PhantomData, + bind_class: None, + _p: Default::default(), } } @@ -93,13 +97,13 @@ impl ClassEntity { handler: F, ) -> &mut MethodEntity where - F: Fn(&mut StateObj, &mut [ZVal]) -> Result + 'static, + F: Fn(&mut StateObj, &mut [ZVal]) -> Result + 'static, Z: Into + 'static, E: Throwable + 'static, { self.method_entities.push(MethodEntity::new( name, - Some(Rc::new(Method::new(handler))), + Some(Rc::new(Method::::new(handler))), vis, )); self.method_entities.last_mut().unwrap() @@ -211,7 +215,7 @@ impl ClassEntity { /// /// When the class registered, the [StaticStateClass] will be initialized, /// so you can use the [StaticStateClass] to new stateful object, etc. - pub fn bind(&mut self, cls: &'static StaticStateClass) { + pub fn bind(&mut self, cls: &'static StaticStateClass) { self.bind_class = Some(cls); } @@ -242,7 +246,7 @@ impl ClassEntity { /// class /// } /// ``` - pub fn state_cloner(&mut self, clone_fn: impl Fn(&T) -> T + 'static) { + pub fn state_cloner(&mut self, clone_fn: impl Fn(&T) -> T + 'static) { self.state_cloner = Some(Rc::new(move |src| { let src = unsafe { src.as_ref() @@ -293,7 +297,7 @@ impl ClassEntity { } } -impl crate::modules::Registerer for ClassEntity { +impl crate::modules::Registerer for ClassEntity { fn register(&mut self, _: i32) -> Result<(), Box> { unsafe { let parent: *mut zend_class_entry = self @@ -307,8 +311,7 @@ impl crate::modules::Registerer for ClassEntity { self.class_name.as_ptr().cast(), self.class_name.as_bytes().len(), self.function_entries(), - Some(class_init_handler), - parent.cast(), + parent, ); if let Some(bind_class) = self.bind_class { diff --git a/phper/src/classes/mod.rs b/phper/src/classes/mod.rs index 3225525..3518ff1 100644 --- a/phper/src/classes/mod.rs +++ b/phper/src/classes/mod.rs @@ -26,8 +26,7 @@ use crate::{ use std::{ any::Any, convert::TryInto, - ffi::{c_void, CString}, - marker::PhantomData, + ffi::CString, mem::{size_of, zeroed}, os::raw::c_int, ptr::null_mut, @@ -79,18 +78,16 @@ fn find_global_class_entry_ptr(name: impl AsRef) -> *mut zend_class_entry { /// } /// ``` #[repr(transparent)] -pub struct StaticStateClass { +pub struct StaticStateClass { inner: AtomicPtr, - _p: PhantomData, } -impl StaticStateClass { +impl StaticStateClass { /// Create empty [StaticStateClass], with null /// [zend_class_entry]. pub const fn null() -> Self { Self { inner: AtomicPtr::new(null_mut()), - _p: PhantomData, } } @@ -107,28 +104,25 @@ impl StaticStateClass { /// /// If the `__construct` is private, or protected and the called scope isn't /// parent class, it will throw PHP Error. - pub fn new_object( - &'static self, - arguments: impl AsMut<[ZVal]>, - ) -> crate::Result> { + pub fn new_object(&'static self, arguments: impl AsMut<[ZVal]>) -> crate::Result { self.as_class_entry() .new_object(arguments) .map(ZObject::into_raw) - .map(StateObject::::from_raw_object) + .map(StateObject::from_raw_object) } /// Create the object from class, without calling `__construct`. /// /// **Be careful when `__construct` is necessary.** - pub fn init_object(&'static self) -> crate::Result> { + pub fn init_object(&'static self) -> crate::Result { self.as_class_entry() .init_object() .map(ZObject::into_raw) - .map(StateObject::::from_raw_object) + .map(StateObject::from_raw_object) } } -unsafe impl Sync for StaticStateClass {} +unsafe impl Sync for StaticStateClass {} /// The [StaticInterface] holds /// [zend_class_entry], always as the static @@ -181,18 +175,6 @@ pub(crate) type StateConstructor = dyn Fn() -> *mut dyn Any; pub(crate) type StateCloner = dyn Fn(*const dyn Any) -> *mut dyn Any; -unsafe extern "C" fn class_init_handler( - class_ce: *mut zend_class_entry, - argument: *mut c_void, -) -> *mut zend_class_entry { - let parent = argument as *mut zend_class_entry; - if parent.is_null() { - zend_register_internal_class(class_ce) - } else { - zend_register_internal_class_ex(class_ce, parent) - } -} - /// Builder for registering interface. pub struct InterfaceEntity { interface_name: CString, @@ -269,7 +251,6 @@ impl crate::modules::Registerer for InterfaceEntity { self.interface_name.as_ptr().cast(), self.interface_name.as_bytes().len(), self.function_entries(), - Some(interface_init_handler), null_mut(), ); @@ -287,13 +268,6 @@ impl crate::modules::Registerer for InterfaceEntity { } } -unsafe extern "C" fn interface_init_handler( - class_ce: *mut zend_class_entry, - _argument: *mut c_void, -) -> *mut zend_class_entry { - zend_register_internal_interface(class_ce) -} - /// Builder for declare class property. struct PropertyEntity { name: String, @@ -382,8 +356,8 @@ pub(crate) type RawVisibility = u32; unsafe extern "C" fn create_object(ce: *mut zend_class_entry) -> *mut zend_object { // Alloc more memory size to store state data. - let state_object = phper_zend_object_alloc(size_of::>(), ce); - let state_object = StateObj::<()>::from_mut_ptr(state_object); + let state_object = phper_zend_object_alloc(size_of::(), ce); + let state_object = StateObj::from_mut_ptr(state_object); // Find the hack elements hidden behind null builtin_function. let mut func_ptr = (*ce).info.internal.builtin_functions; @@ -410,7 +384,7 @@ unsafe extern "C" fn create_object(ce: *mut zend_class_entry) -> *mut zend_objec // Set handlers let mut handlers = Box::new(std_object_handlers); - handlers.offset = StateObj::<()>::offset() as c_int; + handlers.offset = StateObj::offset() as c_int; handlers.free_obj = Some(free_object); handlers.clone_obj = has_state_cloner.then_some(clone_object); (*object).handlers = Box::into_raw(handlers); @@ -430,8 +404,8 @@ unsafe fn clone_object_common(object: *mut zend_object) -> *mut zend_object { let ce = (*object).ce; // Alloc more memory size to store state data. - let new_state_object = phper_zend_object_alloc(size_of::>(), ce); - let new_state_object = StateObj::<()>::from_mut_ptr(new_state_object); + let new_state_object = phper_zend_object_alloc(size_of::(), ce); + let new_state_object = StateObj::from_mut_ptr(new_state_object); // Find the hack elements hidden behind null builtin_function. let mut func_ptr = (*(*object).ce).info.internal.builtin_functions; @@ -454,7 +428,7 @@ unsafe fn clone_object_common(object: *mut zend_object) -> *mut zend_object { (*new_object).handlers = (*object).handlers; // Call the state cloner and store the state. - let state_object = StateObj::<()>::from_mut_object_ptr(object); + let state_object = StateObj::from_mut_object_ptr(object); let data = (state_cloner)(*state_object.as_mut_any_state()); *new_state_object.as_mut_any_state() = data; @@ -462,7 +436,7 @@ unsafe fn clone_object_common(object: *mut zend_object) -> *mut zend_object { } unsafe extern "C" fn free_object(object: *mut zend_object) { - let state_object = StateObj::<()>::from_mut_object_ptr(object); + let state_object = StateObj::from_mut_object_ptr(object); // Drop the state. state_object.drop_state(); diff --git a/phper/src/functions.rs b/phper/src/functions.rs index 1856131..79bf358 100644 --- a/phper/src/functions.rs +++ b/phper/src/functions.rs @@ -64,17 +64,17 @@ where } } -pub(crate) struct Method(F, PhantomData<(Z, E, T)>); +pub(crate) struct Method(F, PhantomData<(Z, E)>); -impl Method { +impl Method { pub(crate) fn new(f: F) -> Self { Self(f, PhantomData) } } -impl Callable for Method +impl Callable for Method where - F: Fn(&mut StateObj, &mut [ZVal]) -> Result, + F: Fn(&mut StateObj, &mut [ZVal]) -> Result, Z: Into, E: Throwable, { diff --git a/phper/src/lib.rs b/phper/src/lib.rs index 6fa3d4d..474fa6d 100644 --- a/phper/src/lib.rs +++ b/phper/src/lib.rs @@ -11,6 +11,7 @@ #![warn(rust_2018_idioms)] #![warn(clippy::dbg_macro, clippy::print_stdout)] #![doc = include_str!("../README.md")] +// #![feature(unboxed_closures)] #[macro_use] mod macros; diff --git a/phper/src/modules.rs b/phper/src/modules.rs index 81bc644..3af4bfc 100644 --- a/phper/src/modules.rs +++ b/phper/src/modules.rs @@ -62,14 +62,12 @@ unsafe extern "C" fn module_startup(_type: c_int, module_number: c_int) -> c_int ini::register(take(&mut module.ini_entities), module_number); for mut entity in take(&mut module.entities).into_iter() { - entity.register(module_number).unwrap(); + if let Err(err) = entity.register(module_number) { + crate::output::log(crate::output::LogLevel::Error, format!("Failed to register: {err:?}")); + return ZEND_RESULT_CODE_FAILURE; + } } - // for class_entity in take(&mut module.class_entities).into_iter() { - // let ce = class_entity.init(); - // class_entity.declare_properties(ce); - // } - if let Some(f) = take(&mut module.module_init) { f(ModuleInfo { ty: _type, @@ -157,11 +155,27 @@ pub struct Module { request_init: Option<&'static dyn Fn(ModuleInfo)>, request_shutdown: Option<&'static dyn Fn(ModuleInfo)>, function_entities: Vec, - entities: Vec>, + entities: Vec, ini_entities: Vec, infos: HashMap, } +pub(crate) enum Entities { + Constant(Constant), + Class(ClassEntity), + Interface(InterfaceEntity), +} + +impl Registerer for Entities { + fn register(&mut self, module_number: i32) -> Result<(), Box> { + match self { + Entities::Constant(con) => con.register(module_number), + Entities::Class(class) => class.register(module_number), + Entities::Interface(interface) => interface.register(module_number), + } + } +} + impl Module { /// Construct the `Module` with base metadata. pub fn new( @@ -221,13 +235,13 @@ impl Module { } /// Register class to module. - pub fn add_class(&mut self, class: ClassEntity) { - self.entities.push(Box::new(class)); + pub fn add_class(&mut self, class: ClassEntity) { + self.entities.push(Entities::Class(class)); } /// Register interface to module. pub fn add_interface(&mut self, interface: InterfaceEntity) { - self.entities.push(Box::new(interface)); + self.entities.push(Entities::Interface(interface)); } /// Register constant to module. @@ -238,7 +252,7 @@ impl Module { flags: Option, ) { self.entities - .push(Box::new(Constant::new(name, value, flags))); + .push(Entities::Constant(Constant::new(name, value, flags))); } /// Register ini configuration to module. diff --git a/phper/src/objects.rs b/phper/src/objects.rs index 4de125a..3137f51 100644 --- a/phper/src/objects.rs +++ b/phper/src/objects.rs @@ -102,7 +102,7 @@ impl ZObj { /// /// Should only call this method for the class of object defined by the /// extension created by `phper`, otherwise, memory problems will caused. - pub unsafe fn as_state_obj(&self) -> &StateObj { + pub unsafe fn as_state_obj(&self) -> &StateObj { StateObj::from_object_ptr(self.as_ptr()) } @@ -112,7 +112,7 @@ impl ZObj { /// /// Should only call this method for the class of object defined by the /// extension created by `phper`, otherwise, memory problems will caused. - pub unsafe fn as_mut_state_obj(&mut self) -> &mut StateObj { + pub unsafe fn as_mut_state_obj(&mut self) -> &mut StateObj { StateObj::from_mut_object_ptr(self.as_mut_ptr()) } @@ -382,13 +382,12 @@ pub(crate) type AnyState = *mut dyn Any; /// The object owned state, usually as the parameter of method handler. #[repr(C)] -pub struct StateObj { +pub struct StateObj { any_state: AnyState, object: ZObj, - _p: PhantomData, } -impl StateObj { +impl StateObj { /// The `zend_object_alloc` often allocate more memory to hold the state /// (usually is a pointer), and place it before `zend_object`. pub(crate) const fn offset() -> usize { @@ -400,12 +399,14 @@ impl StateObj { (ptr as *mut Self).as_mut().expect("ptr should't be null") } + #[inline] pub(crate) unsafe fn from_object_ptr<'a>(ptr: *const zend_object) -> &'a Self { ((ptr as usize - Self::offset()) as *const Self) .as_ref() .unwrap() } + #[inline] pub(crate) unsafe fn from_mut_object_ptr<'a>(ptr: *mut zend_object) -> &'a mut Self { ((ptr as usize - Self::offset()) as *mut Self) .as_mut() @@ -434,9 +435,9 @@ impl StateObj { } } -impl StateObj { +impl StateObj { /// Gets inner state. - pub fn as_state(&self) -> &T { + pub fn as_state(&self) -> &T { unsafe { let any_state = self.any_state.as_ref().unwrap(); any_state.downcast_ref().unwrap() @@ -444,7 +445,7 @@ impl StateObj { } /// Gets inner mutable state. - pub fn as_mut_state(&mut self) -> &mut T { + pub fn as_mut_state(&mut self) -> &mut T { unsafe { let any_state = self.any_state.as_mut().unwrap(); any_state.downcast_mut().unwrap() @@ -452,7 +453,7 @@ impl StateObj { } } -impl Deref for StateObj { +impl Deref for StateObj { type Target = ZObj; fn deref(&self) -> &Self::Target { @@ -460,13 +461,13 @@ impl Deref for StateObj { } } -impl DerefMut for StateObj { +impl DerefMut for StateObj { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.object } } -impl Debug for StateObj { +impl Debug for StateObj { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { common_fmt(self, f, "StateObj") } @@ -474,11 +475,11 @@ impl Debug for StateObj { /// The object owned state, usually crated by /// [StaticStateClass](crate::classes::StaticStateClass). -pub struct StateObject { - inner: *mut StateObj, +pub struct StateObject { + inner: *mut StateObj, } -impl StateObject { +impl StateObject { #[inline] pub(crate) fn from_raw_object(object: *mut zend_object) -> Self { unsafe { @@ -499,14 +500,14 @@ impl StateObject { } } -impl StateObject { +impl StateObject { /// Converts into state. /// /// Because the [zend_object] is refcounted type, /// therefore, you can only obtain state ownership when the refcount of the /// [zend_object] is `1`, otherwise, it will return /// `None`. - pub fn into_state(mut self) -> Option { + pub fn into_state(mut self) -> Option { unsafe { if self.gc_refcount() != 1 { return None; @@ -518,7 +519,7 @@ impl StateObject { } } -impl Drop for StateObject { +impl Drop for StateObject { fn drop(&mut self) { unsafe { drop(ZObject::from_raw(self.as_mut_ptr())); @@ -526,21 +527,21 @@ impl Drop for StateObject { } } -impl Deref for StateObject { - type Target = StateObj; +impl Deref for StateObject { + type Target = StateObj; fn deref(&self) -> &Self::Target { unsafe { self.inner.as_ref().unwrap() } } } -impl DerefMut for StateObject { +impl DerefMut for StateObject { fn deref_mut(&mut self) -> &mut Self::Target { unsafe { self.inner.as_mut().unwrap() } } } -impl Debug for StateObject { +impl Debug for StateObject { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { common_fmt(self, f, "StateObject") } diff --git a/phper/src/values.rs b/phper/src/values.rs index 647a64d..606a476 100644 --- a/phper/src/values.rs +++ b/phper/src/values.rs @@ -798,8 +798,8 @@ impl From for ZVal { } } -impl From> for ZVal { - fn from(obj: StateObject) -> Self { +impl From for ZVal { + fn from(obj: StateObject) -> Self { ZVal::from(obj.into_z_object()) } } diff --git a/tests/integration/src/classes.rs b/tests/integration/src/classes.rs index 7b6397b..46386ca 100644 --- a/tests/integration/src/classes.rs +++ b/tests/integration/src/classes.rs @@ -8,8 +8,8 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. +use phper::alloc::RefClone; use phper::{ - alloc::RefClone, classes::{ entity::ClassEntity, entry::ClassEntry, @@ -59,7 +59,7 @@ fn integrate_a(module: &mut Module) { module.add_class(class); } -static FOO_CLASS: StaticStateClass = StaticStateClass::null(); +static FOO_CLASS: StaticStateClass = StaticStateClass::null(); struct Foo { position: usize, @@ -79,25 +79,25 @@ fn integrate_foo(module: &mut Module) { // Implement Iterator interface. class.add_method("current", Visibility::Public, |this, _arguments| { - let state = this.as_state(); + let state = this.as_state::(); Ok::<_, phper::Error>(format!("Current: {}", state.position)) }); class.add_method("key", Visibility::Public, |this, _arguments| { - let state = this.as_state(); + let state = this.as_state::(); Ok::<_, phper::Error>(state.position as i64) }); class.add_method("next", Visibility::Public, |this, _arguments| { - let state = this.as_mut_state(); + let state = this.as_mut_state::(); state.position += 1; Ok::<_, Infallible>(()) }); class.add_method("rewind", Visibility::Public, |this, _arguments| { - let state = this.as_mut_state(); + let state = this.as_mut_state::(); state.position = 0; Ok::<_, Infallible>(()) }); class.add_method("valid", Visibility::Public, |this, _arguments| { - let state = this.as_state(); + let state = this.as_state::(); Ok::<_, Infallible>(state.position < 3) }); @@ -105,7 +105,7 @@ fn integrate_foo(module: &mut Module) { class .add_method("offsetExists", Visibility::Public, |this, arguments| { let offset = arguments[0].expect_long()?; - let state = this.as_state(); + let state = this.as_state::(); Ok::<_, phper::Error>(state.array.get(&offset).is_some()) }) .argument(Argument::by_val("offset")); @@ -113,7 +113,7 @@ fn integrate_foo(module: &mut Module) { class .add_method("offsetGet", Visibility::Public, |this, arguments| { let offset = arguments[0].expect_long()?; - let state = this.as_mut_state(); + let state = this.as_mut_state::(); let val = state.array.get_mut(&offset).map(|val| val.ref_clone()); Ok::<_, phper::Error>(val) }) @@ -123,7 +123,7 @@ fn integrate_foo(module: &mut Module) { .add_method("offsetSet", Visibility::Public, |this, arguments| { let offset = arguments[0].expect_long()?; let value = arguments[1].clone(); - let state = this.as_mut_state(); + let state = this.as_mut_state::(); state.array.insert(offset, value); Ok::<_, phper::Error>(()) }) @@ -132,7 +132,7 @@ fn integrate_foo(module: &mut Module) { class .add_method("offsetUnset", Visibility::Public, |this, arguments| { let offset = arguments[0].expect_long()?; - let state = this.as_mut_state(); + let state = this.as_mut_state::(); state.array.remove(&offset); Ok::<_, phper::Error>(()) }) diff --git a/tests/integration/src/objects.rs b/tests/integration/src/objects.rs index 7ca20b3..ca390c8 100644 --- a/tests/integration/src/objects.rs +++ b/tests/integration/src/objects.rs @@ -151,13 +151,13 @@ pub fn integrate(module: &mut Module) { let mut class_b = ClassEntity::new_with_state_constructor("IntegrationTest\\Objects\\B", || 123456i64); - class_b.state_cloner(Clone::clone); + class_b.state_cloner::(Clone::clone); class_b.add_method("incr", Visibility::Public, |this, _| { - *this.as_mut_state() += 1; + *this.as_mut_state::() += 1; Ok::<_, Infallible>(()) }); class_b.add_method("get", Visibility::Public, |this, _| { - Ok::<_, Infallible>(*this.as_state()) + Ok::<_, Infallible>(*this.as_state::()) }); module.add_class(class_b); } From 0ddfb07778b0ea337d35be8aac9710ca31ed3efb Mon Sep 17 00:00:00 2001 From: Dusan Malusev Date: Wed, 10 Jan 2024 22:27:24 +0100 Subject: [PATCH 4/5] Remove allocation tripple allocation for class entry Signed-off-by: Dusan Malusev --- phper-sys/c/php_wrapper.c | 27 +++++++++++++++++---------- phper-sys/include/phper.h | 10 +++++++--- phper/src/classes/entity.rs | 31 +++++++++++++++---------------- phper/src/classes/mod.rs | 9 ++++----- phper/src/functions.rs | 12 ++++++------ phper/src/modules.rs | 8 ++++---- phper/src/output.rs | 7 +++---- phper/src/utils.rs | 4 ++-- 8 files changed, 58 insertions(+), 50 deletions(-) diff --git a/phper-sys/c/php_wrapper.c b/phper-sys/c/php_wrapper.c index 185c259..158664f 100644 --- a/phper-sys/c/php_wrapper.c +++ b/phper-sys/c/php_wrapper.c @@ -47,26 +47,33 @@ uint32_t phper_zend_object_gc_refcount(const zend_object *obj) { // class apis: // ================================================== -zend_class_entry * -phper_init_class_entry_ex(const char *class_name, size_t class_name_len, - const zend_function_entry *functions, - zend_class_entry *parent) { +zend_class_entry phper_init_class_entry_ex(const char *class_name, + size_t class_name_len) { zend_class_entry class_ce = {0}; - INIT_CLASS_ENTRY_EX(class_ce, class_name, class_name_len, functions); + class_ce.name = zend_string_init_interned(class_name, class_name_len, true); + class_ce.default_object_handlers = &std_object_handlers; + return class_ce; +} + +zend_class_entry * +phper_register_class_entry_ex(zend_class_entry ce, zend_class_entry *parent, + const zend_function_entry *functions) { + ce.info.internal.builtin_functions = functions; if (parent == NULL) { - return zend_register_internal_class(&class_ce); + return zend_register_internal_class(&ce); } - return zend_register_internal_class_ex(&class_ce, parent); + + return zend_register_internal_class_ex(&ce, parent); } zend_class_entry * phper_init_interface_entry_ex(const char *class_name, size_t class_name_len, const zend_function_entry *functions) { zend_class_entry class_ce = {0}; - INIT_CLASS_ENTRY_EX(class_ce, class_name, class_name_len, functions); - - zend_class_entry *class_ptr; + class_ce.name = zend_string_init_interned(class_name, class_name_len, true); + class_ce.default_object_handlers = &std_object_handlers; + class_ce.info.internal.builtin_functions = functions; return zend_register_internal_interface(&class_ce); } diff --git a/phper-sys/include/phper.h b/phper-sys/include/phper.h index cd3ece3..cfe332a 100644 --- a/phper-sys/include/phper.h +++ b/phper-sys/include/phper.h @@ -204,13 +204,17 @@ uint32_t phper_zend_object_gc_refcount(const zend_object *obj); // ================================================== // class apis: // ================================================== +zend_class_entry phper_init_class_entry_ex(const char *class_name, + size_t class_name_len); + zend_class_entry * -phper_init_class_entry_ex(const char *class_name, size_t class_name_len, - const zend_function_entry *functions, - zend_class_entry *argument); +phper_register_class_entry_ex(zend_class_entry ce, zend_class_entry *parent, + const zend_function_entry *functions); + zend_class_entry * phper_init_interface_entry_ex(const char *class_name, size_t class_name_len, const zend_function_entry *functions); + bool phper_instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce); diff --git a/phper/src/classes/entity.rs b/phper/src/classes/entity.rs index 61965b5..1349696 100644 --- a/phper/src/classes/entity.rs +++ b/phper/src/classes/entity.rs @@ -1,8 +1,8 @@ -use std::{any::Any, ffi::CString, marker::PhantomData, mem::zeroed, ptr::null_mut, rc::Rc}; +use std::{any::Any, marker::PhantomData, mem::zeroed, ptr::null_mut, rc::Rc}; use phper_sys::{ phper_get_create_object, phper_init_class_entry_ex, zend_class_entry, zend_class_implements, - zend_function_entry, + zend_function_entry, phper_register_class_entry_ex, }; use crate::{ @@ -23,7 +23,7 @@ use super::{ /// *It is a common practice for PHP extensions to use PHP objects to package /// third-party resources.* pub struct ClassEntity { - class_name: CString, + class: zend_class_entry, state_constructor: Rc, method_entities: Vec, property_entities: Vec, @@ -36,7 +36,7 @@ pub struct ClassEntity { impl ClassEntity { /// Construct a new `ClassEntity` with class name, do not own state. - pub fn new(class_name: impl Into) -> Self { + pub fn new(class_name: impl AsRef) -> Self { Self::new_with_state_constructor::<()>(class_name, || ()) } } @@ -44,7 +44,7 @@ impl ClassEntity { impl ClassEntity { /// Construct a new `ClassEntity` with class name and default state /// constructor. - pub fn new_with_default_state_constructor(class_name: impl Into) -> Self + pub fn new_with_default_state_constructor(class_name: impl AsRef) -> Self where T: Default + 'static, { @@ -66,14 +66,17 @@ impl ClassEntity { /// Construct a new `ClassEntity` with class name and the constructor to /// build state. pub fn new_with_state_constructor( - class_name: impl Into, + class_name: impl AsRef, state_constructor: impl Fn() -> T + 'static, ) -> Self where T: 'static, { + let class_name = class_name.as_ref(); + let class_name_len = class_name.len(); + Self { - class_name: crate::utils::ensure_end_with_zero(class_name), + class: unsafe { phper_init_class_entry_ex(class_name.as_ptr().cast(), class_name_len) }, state_constructor: Rc::new(move || { let state = state_constructor(); let boxed = Box::new(state) as Box; @@ -92,7 +95,7 @@ impl ClassEntity { /// Add member method to class, with visibility and method handler. pub fn add_method( &mut self, - name: impl Into, + name: impl AsRef, vis: Visibility, handler: F, ) -> &mut MethodEntity @@ -112,7 +115,7 @@ impl ClassEntity { /// Add static method to class, with visibility and method handler. pub fn add_static_method( &mut self, - name: impl Into, + name: impl AsRef, vis: Visibility, handler: F, ) -> &mut MethodEntity @@ -130,7 +133,7 @@ impl ClassEntity { /// Add abstract method to class, with visibility (shouldn't be private). pub fn add_abstract_method( &mut self, - name: impl Into, + name: impl AsRef, vis: Visibility, ) -> &mut MethodEntity { let mut entity = MethodEntity::new(name, None, vis); @@ -307,12 +310,8 @@ impl crate::modules::Registerer for ClassEntity { .map(|entry| entry.as_ptr() as *mut _) .unwrap_or(null_mut()); - let class_ce = phper_init_class_entry_ex( - self.class_name.as_ptr().cast(), - self.class_name.as_bytes().len(), - self.function_entries(), - parent, - ); + let class_ce = + phper_register_class_entry_ex(self.class, parent, self.function_entries()); if let Some(bind_class) = self.bind_class { bind_class.bind(class_ce); diff --git a/phper/src/classes/mod.rs b/phper/src/classes/mod.rs index 3518ff1..88ab21b 100644 --- a/phper/src/classes/mod.rs +++ b/phper/src/classes/mod.rs @@ -185,9 +185,9 @@ pub struct InterfaceEntity { impl InterfaceEntity { /// Construct a new `InterfaceEntity` with interface name. - pub fn new(interface_name: impl Into) -> Self { + pub fn new(interface_name: impl AsRef) -> Self { Self { - interface_name: ensure_end_with_zero(interface_name.into()), + interface_name: ensure_end_with_zero(interface_name), method_entities: Vec::new(), extends: Vec::new(), bind_interface: None, @@ -196,7 +196,7 @@ impl InterfaceEntity { /// Add member method to interface, with mandatory visibility public /// abstract. - pub fn add_method(&mut self, name: impl Into) -> &mut MethodEntity { + pub fn add_method(&mut self, name: impl AsRef) -> &mut MethodEntity { let mut entity = MethodEntity::new(name, None, Visibility::Public); entity.set_vis_abstract(); self.method_entities.push(entity); @@ -247,11 +247,10 @@ impl InterfaceEntity { impl crate::modules::Registerer for InterfaceEntity { fn register(&mut self, _: i32) -> Result<(), Box> { unsafe { - let class_ce = phper_init_class_entry_ex( + let class_ce = phper_init_interface_entry_ex( self.interface_name.as_ptr().cast(), self.interface_name.as_bytes().len(), self.function_entries(), - null_mut(), ); if let Some(bind_interface) = self.bind_interface { diff --git a/phper/src/functions.rs b/phper/src/functions.rs index 79bf358..dbd1006 100644 --- a/phper/src/functions.rs +++ b/phper/src/functions.rs @@ -177,7 +177,7 @@ pub struct FunctionEntity { impl FunctionEntity { #[inline] - pub(crate) fn new(name: impl Into, handler: Rc) -> Self { + pub(crate) fn new(name: impl AsRef, handler: Rc) -> Self { FunctionEntity { name: ensure_end_with_zero(name), handler, @@ -211,7 +211,7 @@ pub struct MethodEntity { impl MethodEntity { #[inline] pub(crate) fn new( - name: impl Into, + name: impl AsRef, handler: Option>, visibility: Visibility, ) -> Self { @@ -259,7 +259,7 @@ pub struct Argument { impl Argument { /// Indicate the argument is pass by value. - pub fn by_val(name: impl Into) -> Self { + pub fn by_val(name: impl AsRef) -> Self { let name = ensure_end_with_zero(name); Self { name, @@ -269,7 +269,7 @@ impl Argument { } /// Indicate the argument is pass by reference. - pub fn by_ref(name: impl Into) -> Self { + pub fn by_ref(name: impl AsRef) -> Self { let name = ensure_end_with_zero(name); Self { name, @@ -279,7 +279,7 @@ impl Argument { } /// Indicate the argument is pass by value and is optional. - pub fn by_val_optional(name: impl Into) -> Self { + pub fn by_val_optional(name: impl AsRef) -> Self { let name = ensure_end_with_zero(name); Self { name, @@ -289,7 +289,7 @@ impl Argument { } /// Indicate the argument is pass by reference nad is optional. - pub fn by_ref_optional(name: impl Into) -> Self { + pub fn by_ref_optional(name: impl AsRef) -> Self { let name = ensure_end_with_zero(name); Self { name, diff --git a/phper/src/modules.rs b/phper/src/modules.rs index 3af4bfc..9b154e6 100644 --- a/phper/src/modules.rs +++ b/phper/src/modules.rs @@ -179,9 +179,9 @@ impl Registerer for Entities { impl Module { /// Construct the `Module` with base metadata. pub fn new( - name: impl Into, - version: impl Into, - author: impl Into, + name: impl AsRef, + version: impl AsRef, + author: impl AsRef, ) -> Self { Self { name: ensure_end_with_zero(name), @@ -221,7 +221,7 @@ impl Module { /// Register function to module. pub fn add_function( &mut self, - name: impl Into, + name: impl AsRef, handler: F, ) -> &mut FunctionEntity where diff --git a/phper/src/output.rs b/phper/src/output.rs index 452d633..a428b41 100644 --- a/phper/src/output.rs +++ b/phper/src/output.rs @@ -28,7 +28,7 @@ pub enum LogLevel { } /// log message with level. -pub fn log(level: LogLevel, message: impl Into) { +pub fn log(level: LogLevel, message: impl AsRef) { let message = ensure_end_with_zero(message); unsafe { php_error_docref1( @@ -41,13 +41,12 @@ pub fn log(level: LogLevel, message: impl Into) { } /// Just like PHP `echo`. -#[allow(clippy::useless_conversion)] -pub fn echo(message: impl Into) { +pub fn echo(message: impl AsRef) { let message = ensure_end_with_zero(message); unsafe { zend_write.expect("function zend_write can't be null")( message.as_ptr().cast(), - message.as_bytes().len().try_into().unwrap(), + message.as_bytes().len(), ); } } diff --git a/phper/src/utils.rs b/phper/src/utils.rs index 1fbf73a..a4975b5 100644 --- a/phper/src/utils.rs +++ b/phper/src/utils.rs @@ -12,6 +12,6 @@ use std::ffi::CString; -pub(crate) fn ensure_end_with_zero(s: impl Into) -> CString { - CString::new(s.into()).expect("CString::new failed") +pub(crate) fn ensure_end_with_zero(s: impl AsRef) -> CString { + CString::new(s.as_ref()).expect("CString::new failed") } From 89c1c69c4544e49256e0b17336b48d5ad35f17f7 Mon Sep 17 00:00:00 2001 From: Dusan Malusev Date: Wed, 10 Jan 2024 22:36:58 +0100 Subject: [PATCH 5/5] Remove tripple allocation for interfaces Signed-off-by: Dusan Malusev --- phper-sys/c/php_wrapper.c | 23 ++++++++++++++--------- phper-sys/include/phper.h | 11 +++++++---- phper/src/classes/entity.rs | 6 +++--- phper/src/classes/mod.rs | 18 +++++++++--------- 4 files changed, 33 insertions(+), 25 deletions(-) diff --git a/phper-sys/c/php_wrapper.c b/phper-sys/c/php_wrapper.c index 158664f..37bb9b1 100644 --- a/phper-sys/c/php_wrapper.c +++ b/phper-sys/c/php_wrapper.c @@ -56,26 +56,31 @@ zend_class_entry phper_init_class_entry_ex(const char *class_name, } zend_class_entry * -phper_register_class_entry_ex(zend_class_entry ce, zend_class_entry *parent, +phper_register_class_entry_ex(zend_class_entry *ce, zend_class_entry *parent, const zend_function_entry *functions) { - ce.info.internal.builtin_functions = functions; + ce->info.internal.builtin_functions = functions; if (parent == NULL) { - return zend_register_internal_class(&ce); + return zend_register_internal_class(ce); } - return zend_register_internal_class_ex(&ce, parent); + return zend_register_internal_class_ex(ce, parent); } -zend_class_entry * -phper_init_interface_entry_ex(const char *class_name, size_t class_name_len, - const zend_function_entry *functions) { +zend_class_entry phper_init_interface_entry_ex(const char *class_name, + size_t class_name_len) { zend_class_entry class_ce = {0}; class_ce.name = zend_string_init_interned(class_name, class_name_len, true); class_ce.default_object_handlers = &std_object_handlers; - class_ce.info.internal.builtin_functions = functions; - return zend_register_internal_interface(&class_ce); + return class_ce; +} + +zend_class_entry * +phper_register_interface_entry_ex(zend_class_entry *ce, + const zend_function_entry *functions) { + ce->info.internal.builtin_functions = functions; + return zend_register_internal_interface(ce); } bool phper_instanceof_function(const zend_class_entry *instance_ce, diff --git a/phper-sys/include/phper.h b/phper-sys/include/phper.h index cfe332a..7eb942f 100644 --- a/phper-sys/include/phper.h +++ b/phper-sys/include/phper.h @@ -208,16 +208,19 @@ zend_class_entry phper_init_class_entry_ex(const char *class_name, size_t class_name_len); zend_class_entry * -phper_register_class_entry_ex(zend_class_entry ce, zend_class_entry *parent, +phper_register_class_entry_ex(zend_class_entry *ce, zend_class_entry *parent, const zend_function_entry *functions); -zend_class_entry * -phper_init_interface_entry_ex(const char *class_name, size_t class_name_len, - const zend_function_entry *functions); +zend_class_entry phper_init_interface_entry_ex(const char *class_name, + size_t class_name_len); bool phper_instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce); +zend_class_entry * +phper_register_interface_entry_ex(zend_class_entry *ce, + const zend_function_entry *functions); + zend_string *phper_get_function_or_method_name(const zend_function *func); zend_string *phper_get_function_name(const zend_function *func); bool phper_call_user_function(HashTable *function_table, zval *object, diff --git a/phper/src/classes/entity.rs b/phper/src/classes/entity.rs index 1349696..be1bf1e 100644 --- a/phper/src/classes/entity.rs +++ b/phper/src/classes/entity.rs @@ -1,8 +1,8 @@ use std::{any::Any, marker::PhantomData, mem::zeroed, ptr::null_mut, rc::Rc}; use phper_sys::{ - phper_get_create_object, phper_init_class_entry_ex, zend_class_entry, zend_class_implements, - zend_function_entry, phper_register_class_entry_ex, + phper_get_create_object, phper_init_class_entry_ex, phper_register_class_entry_ex, + zend_class_entry, zend_class_implements, zend_function_entry, }; use crate::{ @@ -311,7 +311,7 @@ impl crate::modules::Registerer for ClassEntity { .unwrap_or(null_mut()); let class_ce = - phper_register_class_entry_ex(self.class, parent, self.function_entries()); + phper_register_class_entry_ex(&mut self.class, parent, self.function_entries()); if let Some(bind_class) = self.bind_class { bind_class.bind(class_ce); diff --git a/phper/src/classes/mod.rs b/phper/src/classes/mod.rs index 88ab21b..aac367c 100644 --- a/phper/src/classes/mod.rs +++ b/phper/src/classes/mod.rs @@ -20,13 +20,11 @@ use crate::{ objects::{StateObj, StateObject, ZObject}, sys::*, types::Scalar, - utils::ensure_end_with_zero, values::ZVal, }; use std::{ any::Any, convert::TryInto, - ffi::CString, mem::{size_of, zeroed}, os::raw::c_int, ptr::null_mut, @@ -177,7 +175,7 @@ pub(crate) type StateCloner = dyn Fn(*const dyn Any) -> *mut dyn Any; /// Builder for registering interface. pub struct InterfaceEntity { - interface_name: CString, + interface: zend_class_entry, method_entities: Vec, extends: Vec &'static ClassEntry>>, bind_interface: Option<&'static StaticInterface>, @@ -186,8 +184,13 @@ pub struct InterfaceEntity { impl InterfaceEntity { /// Construct a new `InterfaceEntity` with interface name. pub fn new(interface_name: impl AsRef) -> Self { + let interface_name = interface_name.as_ref(); + let interface_name_len = interface_name.len(); + Self { - interface_name: ensure_end_with_zero(interface_name), + interface: unsafe { + phper_init_class_entry_ex(interface_name.as_ptr().cast(), interface_name_len) + }, method_entities: Vec::new(), extends: Vec::new(), bind_interface: None, @@ -247,11 +250,8 @@ impl InterfaceEntity { impl crate::modules::Registerer for InterfaceEntity { fn register(&mut self, _: i32) -> Result<(), Box> { unsafe { - let class_ce = phper_init_interface_entry_ex( - self.interface_name.as_ptr().cast(), - self.interface_name.as_bytes().len(), - self.function_entries(), - ); + let class_ce = + phper_register_interface_entry_ex(&mut self.interface, self.function_entries()); if let Some(bind_interface) = self.bind_interface { bind_interface.bind(class_ce);