diff options
author | Olly Betts <olly@survex.com> | 2021-12-17 10:11:52 +1300 |
---|---|---|
committer | Olly Betts <olly@survex.com> | 2021-12-17 14:50:49 +1300 |
commit | 78f5404727f18e821267b0500e811baf8042d892 (patch) | |
tree | 837854ee478071750abe965b8200f2c0cbbdcfa0 | |
parent | 5da86a14132ae96d885ef12ad04cf771bdb5dd57 (diff) | |
download | swig-78f5404727f18e821267b0500e811baf8042d892.tar.gz |
Improve generated object handlers
Do more initialisation at module load time.
Use a shared set of handlers for cases when the C/C++ object is
destroyed with free().
Most of the code in the free_obj and create_object handlers is the
same for every wrapped class so factor that out into common functions.
-rw-r--r-- | Lib/php/phprun.swg | 21 | ||||
-rw-r--r-- | Source/Modules/php.cxx | 143 |
2 files changed, 95 insertions, 69 deletions
diff --git a/Lib/php/phprun.swg b/Lib/php/phprun.swg index 6f0cc9650..426efe104 100644 --- a/Lib/php/phprun.swg +++ b/Lib/php/phprun.swg @@ -206,3 +206,24 @@ static swig_module_info *SWIG_Php_GetModule() { static void SWIG_Php_SetModule(swig_module_info *pointer, int module_number) { REGISTER_LONG_CONSTANT(const_name, (long) pointer, CONST_CS | CONST_PERSISTENT); } + +/* Common parts of the "create_object" object handler. */ +static zend_object *SWIG_Php_do_create_object(zend_class_entry *ce, zend_object_handlers *handlers) { + swig_object_wrapper *obj = (swig_object_wrapper*)zend_object_alloc(sizeof(swig_object_wrapper), ce); + zend_object_std_init(&obj->std, ce); + object_properties_init(&obj->std, ce); + obj->std.handlers = handlers; + obj->newobject = 1; + return &obj->std; +} + +/* Common parts of the "free_obj" object handler. + Returns void* pointer if the C/C++ object should be destroyed. */ +static void* SWIG_Php_free_obj(zend_object *object) { + if (object) { + swig_object_wrapper *obj = swig_php_fetch_object(object); + zend_object_std_dtor(&obj->std); + if (obj->newobject) return obj->ptr; + } + return NULL; +} diff --git a/Source/Modules/php.cxx b/Source/Modules/php.cxx index 3a62282d8..b83995956 100644 --- a/Source/Modules/php.cxx +++ b/Source/Modules/php.cxx @@ -74,9 +74,6 @@ static String *fake_class_name() { static String *result = NULL; if (!result) { result = Len(prefix) ? prefix : module; - if (!s_creation) { - s_creation = NewStringEmpty(); - } if (!fake_cs_entry) { fake_cs_entry = NewStringf("static zend_function_entry class_%s_functions[] = {\n", result); } @@ -116,56 +113,6 @@ extern "C" { static void (*r_prevtracefunc) (const SwigType *t, String *mangled, String *clientdata) = 0; } -static void print_creation_free_wrapper(Node *n) { - if (!s_creation) { - s_creation = NewStringEmpty(); - } - - String *s = s_creation; - - Printf(s, "/* class entry for %s */\n",class_name); - Printf(s, "static zend_class_entry *SWIGTYPE_%s_ce;\n\n",class_name); - Printf(s, "/* class object handlers for %s */\n",class_name); - Printf(s, "static zend_object_handlers %s_object_handlers;\n\n",class_name); - - if (Getattr(n, "has_destructor")) { - Printf(s, "/* Garbage Collection Method for class %s */\n",class_name); - Printf(s, "static void %s_free_storage(zend_object *object) {\n",class_name); - Printf(s, " swig_object_wrapper *obj = 0;\n"); - Printf(s, " if (!object)\n"); - Printf(s, " return;\n"); - Printf(s, " obj = swig_php_fetch_object(object);\n"); - - Printf(s, " zend_object_std_dtor(&obj->std);\n"); - - Printf(s, " if (obj->newobject)"); - String *type = Getattr(n, "classtype"); - if (destructor_action) { - Printv(s, - " {\n", - type, " * arg1 = (", type, " *)obj->ptr;\n", - destructor_action, "\n", - " }\n", NIL); - } else if (CPlusPlus) { - Printf(s, "\n delete (%s *)obj->ptr;\n", type); - } else { - Printf(s, "\n free(obj->ptr);\n", type); - } - Printf(s, "}\n\n"); - } - - Printf(s, "/* Object Creation Method for class %s */\n",class_name); - Printf(s, "static zend_object *%s_object_new(zend_class_entry *ce) {\n",class_name); - Printf(s, " swig_object_wrapper *obj = (swig_object_wrapper*)zend_object_alloc(sizeof(swig_object_wrapper), ce);\n"); - Printf(s, " zend_object_std_init(&obj->std, ce);\n"); - Printf(s, " object_properties_init(&obj->std, ce);\n"); - Printf(s, " %s_object_handlers.offset = XtOffsetOf(swig_object_wrapper, std);\n", class_name); - if (Getattr(n, "has_destructor")) { - Printf(s, " %s_object_handlers.free_obj = %s_free_storage;\n", class_name, class_name); - } - Printf(s, " obj->std.handlers = &%s_object_handlers;\n obj->newobject = 1;\n return &obj->std;\n}\n\n\n",class_name); -} - static void SwigPHP_emit_pointer_type_registrations() { if (!zend_types) return; @@ -208,17 +155,13 @@ static void SwigPHP_emit_pointer_type_registrations() { Printf(s_wrappers, "}\n\n"); Printf(s_oinit, "\n /* Register classes to represent non-class pointer types */\n"); - Printf(s_oinit, " memcpy(&swig_ptr_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));\n"); + Printf(s_oinit, " swig_ptr_object_handlers = *zend_get_std_object_handlers();\n"); Printf(s_oinit, " swig_ptr_object_handlers.offset = XtOffsetOf(swig_object_wrapper, std);\n"); Printf(s_oinit, " swig_ptr_object_handlers.cast_object = swig_ptr_cast_object;\n"); while (ki.key) { String *type = ki.key; - if (!s_creation) { - s_creation = NewStringEmpty(); - } - Printf(s_creation, "/* class entry for pointer to %s */\n", type); Printf(s_creation, "zend_class_entry *SWIGTYPE_%s_ce;\n\n", type); @@ -309,6 +252,7 @@ public: r_shutdown = NewStringEmpty(); s_header = NewString("/* header section */\n"); s_wrappers = NewString("/* wrapper section */\n"); + s_creation = NewStringEmpty(); /* subsections of the init section */ s_vdecl = NewString("/* vdecl subsection */\n"); s_cinit = NewString(" /* cinit subsection */\n"); @@ -428,11 +372,9 @@ public: Language::top(n); SwigPHP_emit_pointer_type_registrations(); - if (s_creation) { - Dump(s_creation, s_header); - Delete(s_creation); - s_creation = NULL; - } + Dump(s_creation, s_header); + Delete(s_creation); + s_creation = NULL; /* start the init section */ { @@ -1616,9 +1558,75 @@ public: Delete(interfaces); } - Printf(s_oinit, " SWIGTYPE_%s_ce->create_object = %s_object_new;\n", class_name, class_name); - Printf(s_oinit, " memcpy(&%s_object_handlers,zend_get_std_object_handlers(), sizeof(zend_object_handlers));\n", class_name); - Printf(s_oinit, " %s_object_handlers.clone_obj = NULL;\n", class_name); + Language::classHandler(n); + + static bool emitted_base_object_handlers = false; + if (!emitted_base_object_handlers) { + Printf(s_creation, "static zend_object_handlers SWIGTYPE_base_object_handlers;\n\n"); + + // Set up a base zend_object_handlers structure which we can use as-is + // for classes without a destructor, and copy as the basis for other + // classes. + Printf(s_oinit, " SWIGTYPE_base_object_handlers = *zend_get_std_object_handlers();\n"); + Printf(s_oinit, " SWIGTYPE_base_object_handlers.offset = XtOffsetOf(swig_object_wrapper, std);\n"); + Printf(s_oinit, " SWIGTYPE_base_object_handlers.clone_obj = NULL;\n"); + emitted_base_object_handlers = true; + } + + Printf(s_creation, "static zend_class_entry *SWIGTYPE_%s_ce;\n\n", class_name); + + if (Getattr(n, "has_destructor")) { + if (destructor_action ? Equal(destructor_action, "free((char *) arg1);") : !CPlusPlus) { + // We can use a single function if the destructor action calls free() + // (either explicitly or as the default in C-mode) since free() doesn't + // care about the object's type. We currently only check for the exact + // code that Swig_cdestructor_call() emits. + static bool emitted_common_cdestructor = false; + if (!emitted_common_cdestructor) { + Printf(s_creation, "static zend_object_handlers SWIGTYPE_common_c_object_handlers;\n\n"); + Printf(s_creation, "static void SWIG_Php_common_c_free_obj(zend_object *object) {free(SWIG_Php_free_obj(object));}\n\n"); + Printf(s_creation, "static zend_object *SWIG_Php_common_c_create_object(zend_class_entry *ce) {return SWIG_Php_do_create_object(ce, &SWIGTYPE_common_c_object_handlers);}\n"); + + Printf(s_oinit, " SWIGTYPE_common_c_object_handlers = SWIGTYPE_base_object_handlers;\n"); + Printf(s_oinit, " SWIGTYPE_common_c_object_handlers.free_obj = SWIG_Php_common_c_free_obj;\n"); + + emitted_common_cdestructor = true; + } + + Printf(s_oinit, " SWIGTYPE_%s_ce->create_object = SWIG_Php_common_c_create_object;\n", class_name); + } else { + Printf(s_creation, "static zend_object_handlers %s_object_handlers;\n", class_name); + Printf(s_creation, "static zend_object *SWIG_Php_create_object_%s(zend_class_entry *ce) {return SWIG_Php_do_create_object(ce, &%s_object_handlers);}\n", class_name, class_name); + + Printf(s_creation, "static void SWIG_Php_free_obj_%s(zend_object *object) {",class_name); + String *type = Getattr(n, "classtype"); + // Special case handling the delete call generated by + // Swig_cppdestructor_call() and generate simpler code. + if (destructor_action && !Equal(destructor_action, "delete arg1;")) { + Printv(s_creation, "\n" + " ", type, " *arg1 = (" , type, " *)SWIG_Php_free_obj(object);\n" + " if (arg1) {\n" + " ", destructor_action, "\n" + " }\n", NIL); + } else { + Printf(s_creation, "delete (%s *)SWIG_Php_free_obj(object);", type); + } + Printf(s_creation, "}\n\n"); + + Printf(s_oinit, " SWIGTYPE_%s_ce->create_object = SWIG_Php_create_object_%s;\n", class_name, class_name); + Printf(s_oinit, " %s_object_handlers = SWIGTYPE_base_object_handlers;\n", class_name); + Printf(s_oinit, " %s_object_handlers.free_obj = SWIG_Php_free_obj_%s;\n", class_name, class_name); + } + } else { + static bool emitted_destructorless_create_object = false; + if (!emitted_destructorless_create_object) { + emitted_destructorless_create_object = true; + Printf(s_creation, "static zend_object *SWIG_Php_create_object(zend_class_entry *ce) {return SWIG_Php_do_create_object(ce, &SWIGTYPE_base_object_handlers);}\n", class_name); + } + + Printf(s_oinit, " SWIGTYPE_%s_ce->create_object = SWIG_Php_create_object;\n", class_name); + } + // If not defined we aren't wrapping any functions which use this type as a // parameter or return value, in which case we don't need the clientdata // set. @@ -1627,9 +1635,6 @@ public: Printf(s_oinit, "#endif\n"); Printf(s_oinit, "\n"); - Language::classHandler(n); - - print_creation_free_wrapper(n); generate_magic_property_methods(n, base_class); Printf(all_cs_entry, " ZEND_FE_END\n};\n\n"); |