@@ -4058,6 +4058,7 @@ write_function_for_name(ostream &out, Object *obj,
40584058 int max_required_args = 0 ;
40594059 bool all_nonconst = true ;
40604060 bool has_keywords = false ;
4061+ bool has_fastcall = false ;
40614062
40624063 out << " /**\n * Python function wrapper for:\n " ;
40634064 for (ri = remaps.begin (); ri != remaps.end (); ++ri) {
@@ -4077,6 +4078,10 @@ write_function_for_name(ostream &out, Object *obj,
40774078 has_keywords = true ;
40784079 }
40794080
4081+ if (remap->_flags & FunctionRemap::F_fastcall) {
4082+ has_fastcall = true ;
4083+ }
4084+
40804085 max_required_args = max (max_num_args, max_required_args);
40814086
40824087 for (int i = min_num_args; i <= max_num_args; ++i) {
@@ -4169,6 +4174,58 @@ write_function_for_name(ostream &out, Object *obj,
41694174 max_required_args = collapse_default_remaps (map_sets, max_required_args);
41704175 }
41714176
4177+ if (has_fastcall) {
4178+ if (args_type == AT_keyword_args && has_keywords) {
4179+ out << " Py_ssize_t fc_nargs = PyTuple_GET_SIZE(args);\n " ;
4180+ out << " PyObject *const *fc_args;\n " ;
4181+ out << " PyObject *fc_kwnames;\n " ;
4182+ out << " if (kwds == nullptr) {\n " ;
4183+ out << " fc_args = &PyTuple_GET_ITEM(args, 0);\n " ;
4184+ out << " fc_kwnames = nullptr;\n " ;
4185+ out << " } else {\n " ;
4186+ out << " Py_BEGIN_CRITICAL_SECTION(kwds);\n " ;
4187+ out << " PyObject **fc_args_mut = (PyObject **)alloca(sizeof(PyObject *) * (fc_nargs + PyDict_GET_SIZE(kwds)));\n " ;
4188+ out << " for (Py_ssize_t i = 0; i < fc_nargs; i++) {\n " ;
4189+ out << " fc_args_mut[i] = PyTuple_GET_ITEM(args, i);\n " ;
4190+ out << " }\n " ;
4191+ out << " fc_kwnames = PyTuple_New(PyDict_GET_SIZE(kwds));\n " ;
4192+ out << " PyObject *key, *value;\n " ;
4193+ out << " Py_ssize_t pos = 0;\n " ;
4194+ out << " Py_ssize_t i = 0;\n " ;
4195+ out << " while (PyDict_Next(kwds, &pos, &key, &value)) {\n " ;
4196+ out << " Py_INCREF(key);\n " ;
4197+ out << " PyTuple_SET_ITEM(fc_kwnames, i, key);\n " ;
4198+ out << " fc_args_mut[fc_nargs + i] = value;\n " ;
4199+ out << " i++;\n " ;
4200+ out << " }\n " ;
4201+ out << " fc_args = fc_args_mut;\n " ;
4202+ out << " Py_END_CRITICAL_SECTION();\n " ;
4203+ out << " }\n " ;
4204+ return_flags |= RF_decref_kwnames;
4205+ }
4206+ else if (args_type == AT_varargs) {
4207+ out << " Py_ssize_t fc_nargs = PyTuple_GET_SIZE(args);\n " ;
4208+ out << " PyObject *const *fc_args = &PyTuple_GET_ITEM(args, 0);\n " ;
4209+ if (has_keywords) {
4210+ out << " PyObject *fc_kwnames = nullptr;\n " ;
4211+ }
4212+ }
4213+ else if (args_type == AT_single_arg) {
4214+ out << " Py_ssize_t fc_nargs = 1;\n " ;
4215+ out << " PyObject *const *fc_args = &arg;\n " ;
4216+ if (has_keywords) {
4217+ out << " PyObject *fc_kwnames = nullptr;\n " ;
4218+ }
4219+ }
4220+ else {
4221+ out << " Py_ssize_t fc_nargs = 0;\n " ;
4222+ out << " PyObject *const *fc_args = nullptr;\n " ;
4223+ if (has_keywords) {
4224+ out << " PyObject *fc_kwnames = nullptr;\n " ;
4225+ }
4226+ }
4227+ }
4228+
41724229 if (remap->_flags & FunctionRemap::F_explicit_args) {
41734230 // We have a remap that wants to handle the wrapper itself.
41744231 string expected_params;
@@ -5209,11 +5266,20 @@ write_function_instance(ostream &out, FunctionRemap *remap,
52095266 if (remap->_flags & FunctionRemap::F_explicit_args) {
52105267 // The function handles the arguments by itself.
52115268 expected_params += " *args" ;
5212- pexprs.push_back (" args" );
5269+ if (remap->_flags & FunctionRemap::F_fastcall) {
5270+ pexprs.push_back (" fc_args" );
5271+ pexprs.push_back (" fc_nargs" );
5272+ } else {
5273+ pexprs.push_back (" args" );
5274+ }
52135275 if (remap->_args_type == AT_keyword_args) {
52145276 if (args_type == AT_keyword_args) {
52155277 expected_params += " , **kwargs" ;
5216- pexprs.push_back (" kwds" );
5278+ if (remap->_flags & FunctionRemap::F_fastcall) {
5279+ pexprs.push_back (" fc_kwnames" );
5280+ } else {
5281+ pexprs.push_back (" kwds" );
5282+ }
52175283 } else {
52185284 pexprs.push_back (" nullptr" );
52195285 }
@@ -6726,6 +6792,11 @@ write_function_instance(ostream &out, FunctionRemap *remap,
67266792 return_flags &= ~RF_decref_args;
67276793 }
67286794
6795+ if (return_flags & RF_decref_kwnames) {
6796+ indent (out, indent_level) << " Py_XDECREF(fc_kwnames);\n " ;
6797+ return_flags &= ~RF_decref_kwnames;
6798+ }
6799+
67296800 // An even specialer special case for functions with void return or bool
67306801 // return. We have our own functions that do all this in a single
67316802 // function call, so it should reduce the amount of code output while not
@@ -6811,6 +6882,11 @@ write_function_instance(ostream &out, FunctionRemap *remap,
68116882 return_flags &= ~RF_decref_args;
68126883 }
68136884
6885+ if (return_flags & RF_decref_kwnames) {
6886+ indent (out, indent_level) << " Py_XDECREF(fc_kwnames);\n " ;
6887+ return_flags &= ~RF_decref_kwnames;
6888+ }
6889+
68146890 // Outputs code to check to see if an assertion has failed while the C++
68156891 // code was executing, and report this failure back to Python. Don't do
68166892 // this for coercion constructors since they are called by other wrapper
@@ -7006,6 +7082,9 @@ error_return(ostream &out, int indent_level, int return_flags) {
70067082 if (return_flags & RF_decref_args) {
70077083 indent (out, indent_level) << " Py_DECREF(args);\n " ;
70087084 }
7085+ if (return_flags & RF_decref_kwnames) {
7086+ indent (out, indent_level) << " Py_XDECREF(fc_kwnames);\n " ;
7087+ }
70097088
70107089 if (return_flags & RF_int) {
70117090 indent (out, indent_level) << " return -1;\n " ;
@@ -7032,6 +7111,9 @@ error_bad_args_return(ostream &out, int indent_level, int return_flags,
70327111 if (return_flags & RF_decref_args) {
70337112 indent (out, indent_level) << " Py_DECREF(args);\n " ;
70347113 }
7114+ if (return_flags & RF_decref_kwnames) {
7115+ indent (out, indent_level) << " Py_XDECREF(fc_kwnames);\n " ;
7116+ }
70357117
70367118 if ((return_flags & RF_err_null) != 0 &&
70377119 (return_flags & RF_pyobject) != 0 ) {
@@ -7083,6 +7165,10 @@ error_raise_return(ostream &out, int indent_level, int return_flags,
70837165 indent (out, indent_level) << " Py_DECREF(args);\n " ;
70847166 return_flags &= ~RF_decref_args;
70857167 }
7168+ if (return_flags & RF_decref_kwnames) {
7169+ indent (out, indent_level) << " Py_XDECREF(fc_kwnames);\n " ;
7170+ return_flags &= ~RF_decref_kwnames;
7171+ }
70867172
70877173 if (format_args.empty ()) {
70887174 if (exc_type == " TypeError" ) {
@@ -8303,6 +8389,14 @@ is_remap_legal(FunctionRemap *remap) {
83038389 ParameterRemap *param = remap->_parameters [pn]._remap ;
83048390 CPPType *orig_type = param->get_orig_type ();
83058391 if (param->get_default_value () == nullptr && !is_cpp_type_legal (orig_type)) {
8392+ if ((remap->_flags & FunctionRemap::F_explicit_args) != 0 &&
8393+ (remap->_flags & FunctionRemap::F_fastcall) != 0 &&
8394+ remap->_parameters [pn]._name == " args" &&
8395+ TypeManager::is_pointer_to_pointer_to_PyObject (orig_type) &&
8396+ TypeManager::is_const_pointer_to_anything (orig_type)) {
8397+ // Allow PyObject *const *args through.
8398+ continue ;
8399+ }
83068400 return false ;
83078401 }
83088402 }
0 commit comments