diff --git a/CHANGES.current b/CHANGES.current index 998d519a0..679d786f9 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -12,6 +12,16 @@ Version 3.0.11 (in progress) for every other language - to generate foo_wrap.cpp you can run SWIG with -cppext cpp). Fixes https://github.com/swig/swig/issues/571 +2016-11-30: olly + [PHP] Only emit one copy of each distinct arginfo. Previously we + emitted a separate one for every wrapped function, but typically + many functions have the same number of parameters and combinations + of parameters passed by reference or not. + + This change significantly reduces both the size of the generated + wrapper, and of the compiled PHP extension module (e.g. by ~6% for + the stripped extension module for Xapian's PHP7 bindings). + 2016-11-28: wsfulton Fix %rename override of wildcard %rename for templates. For example: diff --git a/Source/Modules/php.cxx b/Source/Modules/php.cxx index 74329fa4f..96ec49d2c 100644 --- a/Source/Modules/php.cxx +++ b/Source/Modules/php.cxx @@ -100,6 +100,11 @@ static String *s_oowrappers; static String *s_fakeoowrappers; static String *s_phpclasses; +/* To reduce code size (generated and compiled) we only want to emit each + * different arginfo once, so we need to track which have been used. + */ +static Hash *arginfo_used; + /* Variables for using PHP classes */ static Node *current_class = 0; @@ -473,6 +478,7 @@ public: /* start the arginfo section */ s_arginfo = NewString("/* arginfo subsection */\n"); + arginfo_used = NewHash(); /* start the function entry section */ s_entry = NewString("/* entry subsection */\n"); @@ -633,22 +639,35 @@ public: void create_command(String *cname, String *iname, Node *n) { // This is for the single main zend_function_entry record Printf(f_h, "ZEND_NAMED_FUNCTION(%s);\n", iname); - String * s = cs_entry; - if (!s) s = s_entry; - Printf(s, " SWIG_ZEND_NAMED_FE(%(lower)s,%s,swig_arginfo_%(lower)s)\n", cname, iname, cname); - // This is the above referenced arginfo structure. + // We want to only emit each different arginfo once, as that reduces the + // size of both the generated source code and the compiled extension + // module. To do this, we name the arginfo to encode the number of + // parameters and which (if any) are passed by reference by using a + // sequence of 0s (for non-reference) and 1s (for by references). ParmList *l = Getattr(n, "parms"); - Printf(s_arginfo, "ZEND_BEGIN_ARG_INFO_EX(swig_arginfo_%(lower)s, 0, 0, 0)\n", cname); + String * arginfo_code = NewStringEmpty(); for (Parm *p = l; p; p = Getattr(p, "tmap:in:next")) { /* Ignored parameters */ if (checkAttribute(p, "tmap:in:numinputs", "0")) { continue; } - int byref = GetFlag(p, "tmap:in:byref"); - Printf(s_arginfo, " ZEND_ARG_PASS_INFO(%d)\n", byref); + Append(arginfo_code, GetFlag(p, "tmap:in:byref") ? "1" : "0"); } - Printf(s_arginfo, "ZEND_END_ARG_INFO()\n"); + + if (!GetFlag(arginfo_used, arginfo_code)) { + // Not had this one before, so emit it. + SetFlag(arginfo_used, arginfo_code); + Printf(s_arginfo, "ZEND_BEGIN_ARG_INFO_EX(swig_arginfo_%s, 0, 0, 0)\n", arginfo_code); + for (const char * p = Char(arginfo_code); *p; ++p) { + Printf(s_arginfo, " ZEND_ARG_PASS_INFO(%c)\n", *p); + } + Printf(s_arginfo, "ZEND_END_ARG_INFO()\n"); + } + + String * s = cs_entry; + if (!s) s = s_entry; + Printf(s, " SWIG_ZEND_NAMED_FE(%(lower)s,%s,swig_arginfo_%s)\n", cname, iname, arginfo_code); } /* ------------------------------------------------------------ diff --git a/Source/Modules/php5.cxx b/Source/Modules/php5.cxx index dff5fa47f..87cb27e1c 100644 --- a/Source/Modules/php5.cxx +++ b/Source/Modules/php5.cxx @@ -100,6 +100,11 @@ static String *s_oowrappers; static String *s_fakeoowrappers; static String *s_phpclasses; +/* To reduce code size (generated and compiled) we only want to emit each + * different arginfo once, so we need to track which have been used. + */ +static Hash *arginfo_used; + /* Variables for using PHP classes */ static Node *current_class = 0; @@ -507,6 +512,7 @@ public: /* start the arginfo section */ s_arginfo = NewString("/* arginfo subsection */\n"); + arginfo_used = NewHash(); /* start the function entry section */ s_entry = NewString("/* entry subsection */\n"); @@ -667,22 +673,35 @@ public: void create_command(String *cname, String *iname, Node *n) { // This is for the single main zend_function_entry record Printf(f_h, "ZEND_NAMED_FUNCTION(%s);\n", iname); - String * s = cs_entry; - if (!s) s = s_entry; - Printf(s, " SWIG_ZEND_NAMED_FE(%(lower)s,%s,swig_arginfo_%(lower)s)\n", cname, iname, cname); - // This is the above referenced arginfo structure. + // We want to only emit each different arginfo once, as that reduces the + // size of both the generated source code and the compiled extension + // module. To do this, we name the arginfo to encode the number of + // parameters and which (if any) are passed by reference by using a + // sequence of 0s (for non-reference) and 1s (for by references). ParmList *l = Getattr(n, "parms"); - Printf(s_arginfo, "ZEND_BEGIN_ARG_INFO_EX(swig_arginfo_%(lower)s, 0, 0, 0)\n", cname); + String * arginfo_code = NewStringEmpty(); for (Parm *p = l; p; p = Getattr(p, "tmap:in:next")) { /* Ignored parameters */ if (checkAttribute(p, "tmap:in:numinputs", "0")) { continue; } - int byref = GetFlag(p, "tmap:in:byref"); - Printf(s_arginfo, " ZEND_ARG_PASS_INFO(%d)\n", byref); + Append(arginfo_code, GetFlag(p, "tmap:in:byref") ? "1" : "0"); } - Printf(s_arginfo, "ZEND_END_ARG_INFO()\n"); + + if (!GetFlag(arginfo_used, arginfo_code)) { + // Not had this one before, so emit it. + SetFlag(arginfo_used, arginfo_code); + Printf(s_arginfo, "ZEND_BEGIN_ARG_INFO_EX(swig_arginfo_%s, 0, 0, 0)\n", arginfo_code); + for (const char * p = Char(arginfo_code); *p; ++p) { + Printf(s_arginfo, " ZEND_ARG_PASS_INFO(%c)\n", *p); + } + Printf(s_arginfo, "ZEND_END_ARG_INFO()\n"); + } + + String * s = cs_entry; + if (!s) s = s_entry; + Printf(s, " SWIG_ZEND_NAMED_FE(%(lower)s,%s,swig_arginfo_%s)\n", cname, iname, arginfo_code); } /* ------------------------------------------------------------