@@ -30,7 +30,7 @@ pub union PyMethodPointer {
3030 ) -> * mut PyObject ,
3131 pub PyCFunctionFast : unsafe extern "C" fn (
3232 slf : * mut PyObject ,
33- args : * mut * mut PyObject ,
33+ args : * const * mut PyObject ,
3434 nargs : isize ,
3535 ) -> * mut PyObject ,
3636 pub PyCFunctionFastWithKeywords : unsafe extern "C" fn (
@@ -45,24 +45,26 @@ pub(crate) fn build_method_def(
4545 vm : & VirtualMachine ,
4646 ml : & PyMethodDef ,
4747 has_self : bool ,
48- ) -> PyRef < HeapMethodDef > {
48+ ) -> PyResult < PyRef < HeapMethodDef > > {
4949 let name = unsafe { CStr :: from_ptr ( ml. ml_name ) }
5050 . to_str ( )
51- . expect ( "Method name was not valid UTF-8" ) ;
51+ . map_err ( |_| vm . new_system_error ( "Method name was not valid UTF-8" ) ) ? ;
5252
53- let doc = NonNull :: new ( ml. ml_doc . cast_mut ( ) ) . map ( |doc| {
54- unsafe { CStr :: from_ptr ( doc. as_ptr ( ) ) }
55- . to_str ( )
56- . expect ( "Method doc was not valid UTF-8" )
57- } ) ;
53+ let doc = NonNull :: new ( ml. ml_doc . cast_mut ( ) )
54+ . map ( |doc| {
55+ unsafe { CStr :: from_ptr ( doc. as_ptr ( ) ) }
56+ . to_str ( )
57+ . map_err ( |_| vm. new_system_error ( "Method doc was not valid UTF-8" ) )
58+ } )
59+ . transpose ( ) ?;
5860
59- let flags =
60- PyMethodFlags :: from_bits ( ml . ml_flags as u32 ) . expect ( "PyMethodDef contains unknown flags" ) ;
61+ let flags = PyMethodFlags :: from_bits ( ml . ml_flags as u32 )
62+ . ok_or_else ( || vm . new_system_error ( "PyMethodDef contains unknown flags" ) ) ? ;
6163
6264 let method = ml. ml_meth ;
6365
6466 if flags. contains ( PyMethodFlags :: METHOD ) {
65- panic ! ( "METH_METHOD is not supported on abi3" )
67+ return Err ( vm . new_system_error ( "METH_METHOD is not supported on abi3" ) ) ;
6668 }
6769
6870 let call_flags = flags
@@ -76,39 +78,43 @@ pub(crate) fn build_method_def(
7678 PyMethodFlags :: NOARGS => {
7779 if has_self {
7880 let callable = move |zelf: PyObjectRef , vm: & VirtualMachine | unsafe {
79- call_function( vm, method, flags, Some ( vec![ zelf] ) )
81+ let f = method. PyCFunction ;
82+ let ret_ptr = f( zelf. as_raw( ) . cast_mut( ) , core:: ptr:: null_mut( ) ) ;
83+ ret_ptr_to_pyresult( vm, ret_ptr)
8084 } ;
81- vm. ctx. new_method_def( name, callable, flags, doc)
85+ Ok ( vm. ctx. new_method_def( name, callable, flags, doc) )
8286 } else {
8387 let callable = move |vm: & VirtualMachine | unsafe {
84- call_function:: <FuncArgs >( vm, method, flags, None )
88+ let f = method. PyCFunction ;
89+ let ret_ptr = f( core:: ptr:: null_mut( ) , core:: ptr:: null_mut( ) ) ;
90+ ret_ptr_to_pyresult( vm, ret_ptr)
8591 } ;
86- vm. ctx. new_method_def( name, callable, flags, doc)
92+ Ok ( vm. ctx. new_method_def( name, callable, flags, doc) )
8793 }
8894 } ,
8995 PyMethodFlags :: VARARGS => {
9096 let callable = move |args: PosArgs , vm: & VirtualMachine | unsafe {
9197 call_function( vm, method, flags, Some ( args) )
9298 } ;
93- vm. ctx. new_method_def( name, callable, flags, doc)
99+ Ok ( vm. ctx. new_method_def( name, callable, flags, doc) )
94100 } ,
95101 PyMethodFlags :: VARARGS | PyMethodFlags :: KEYWORDS => {
96102 let callable = move | args: FuncArgs , vm: & VirtualMachine | unsafe {
97103 call_function_with_keywords( vm, method, flags, args)
98104 } ;
99- vm. ctx. new_method_def( name, callable, flags, doc)
105+ Ok ( vm. ctx. new_method_def( name, callable, flags, doc) )
100106 } ,
101107 PyMethodFlags :: FASTCALL | PyMethodFlags :: KEYWORDS => {
102108 let callable = move |args: FuncArgs , vm: & VirtualMachine | unsafe {
103109 call_fast_function_with_keywords( vm, method, flags, args)
104110 } ;
105- vm. ctx. new_method_def( name, callable, flags, doc)
111+ Ok ( vm. ctx. new_method_def( name, callable, flags, doc) )
106112 } ,
107113 PyMethodFlags :: FASTCALL => {
108- let callable = move |_args : PosArgs , _vm : & VirtualMachine | -> PyResult {
109- todo! ( "METH_FASTCALL without METH_KEYWORDS is not supported yet" )
114+ let callable = move |args : PosArgs , vm : & VirtualMachine | unsafe {
115+ call_fast_function ( vm , method , flags , args )
110116 } ;
111- vm. ctx. new_method_def( name, callable, flags, doc)
117+ Ok ( vm. ctx. new_method_def( name, callable, flags, doc) )
112118 } ,
113119 PyMethodFlags :: O => {
114120 let f = unsafe { method. PyCFunction } ;
@@ -117,17 +123,19 @@ pub(crate) fn build_method_def(
117123 let ret_ptr = unsafe { f( zelf. as_raw( ) . cast_mut( ) , arg. as_raw( ) . cast_mut( ) ) } ;
118124 ret_ptr_to_pyresult( vm, ret_ptr)
119125 } ;
120- vm. ctx. new_method_def( name, callable, flags, doc)
126+ Ok ( vm. ctx. new_method_def( name, callable, flags, doc) )
121127 } else {
122128 let callable = move |arg: PyObjectRef , vm: & VirtualMachine | -> PyResult {
123- let ret_ptr = unsafe { f( std :: ptr:: null_mut( ) , arg. as_raw( ) . cast_mut( ) ) } ;
129+ let ret_ptr = unsafe { f( core :: ptr:: null_mut( ) , arg. as_raw( ) . cast_mut( ) ) } ;
124130 ret_ptr_to_pyresult( vm, ret_ptr)
125131 } ;
126- vm. ctx. new_method_def( name, callable, flags, doc)
132+ Ok ( vm. ctx. new_method_def( name, callable, flags, doc) )
127133 }
128134 } ,
129135 _ => {
130- todo!( "function {name} has unsupported or invalid calling-convention flags: {flags:?}" )
136+ Err ( vm. new_system_error( format!(
137+ "function {name} has unsupported or invalid calling-convention flags: {flags:?}"
138+ ) ) )
131139 } ,
132140 } )
133141}
@@ -202,31 +210,46 @@ unsafe fn call_fast_function_with_keywords(
202210 . unwrap_or_default ( ) ;
203211 let nargs = args. args . len ( ) ;
204212 let mut fastcall_args = args. args ;
205- let mut kwnames_tuple = None ;
206- if !args. kwargs . is_empty ( ) {
213+ let kwnames_tuple = if !args. kwargs . is_empty ( ) {
207214 let mut kwnames = Vec :: with_capacity ( args. kwargs . len ( ) ) ;
208215 for ( k, v) in args. kwargs {
209216 kwnames. push ( vm. ctx . new_str ( k) . into ( ) ) ;
210217 fastcall_args. push ( v) ;
211218 }
212- kwnames_tuple = Some ( vm. ctx . new_tuple ( kwnames) ) ;
213- }
214- let fastcall_arg_ptrs = fastcall_args
215- . iter ( )
216- . map ( |obj| obj. as_object ( ) . as_raw ( ) . cast_mut ( ) )
217- . collect :: < Vec < _ > > ( ) ;
219+ Some ( vm. ctx . new_tuple ( kwnames) )
220+ } else {
221+ None
222+ } ;
218223 let kwnames_ptr = kwnames_tuple
219224 . as_ref ( )
220225 . map ( |tuple| tuple. as_object ( ) . as_raw ( ) . cast_mut ( ) )
221- . unwrap_or ( core:: ptr:: null_mut ( ) ) ;
222- let ret_ptr = unsafe {
223- f (
224- slf_ptr,
225- fastcall_arg_ptrs. as_ptr ( ) ,
226- nargs as isize ,
227- kwnames_ptr,
228- )
229- } ;
226+ . unwrap_or_default ( ) ;
227+ // SAFETY: PyObjectRef is repr(transparent) over a pointer to PyObject, so a
228+ // Vec<PyObjectRef> has a layout-compatible contiguous backing buffer. The
229+ // vector is kept alive for the duration of the call.
230+ let fastcall_arg_ptrs = fastcall_args. as_ptr ( ) . cast :: < * mut PyObject > ( ) ;
231+ let ret_ptr = unsafe { f ( slf_ptr, fastcall_arg_ptrs, nargs as isize , kwnames_ptr) } ;
232+ ret_ptr_to_pyresult ( vm, ret_ptr)
233+ }
234+
235+ unsafe fn call_fast_function (
236+ vm : & VirtualMachine ,
237+ method : PyMethodPointer ,
238+ flags : PyMethodFlags ,
239+ args : PosArgs ,
240+ ) -> PyResult {
241+ let f = unsafe { method. PyCFunctionFast } ;
242+ let mut args: FuncArgs = args. into ( ) ;
243+ let slf = take_self_arg ( & mut args, flags) ;
244+ let slf_ptr = slf
245+ . as_ref ( )
246+ . map ( |obj| obj. as_object ( ) . as_raw ( ) . cast_mut ( ) )
247+ . unwrap_or_default ( ) ;
248+ // SAFETY: PyObjectRef is repr(transparent) over a pointer to PyObject, so a
249+ // Vec<PyObjectRef> has a layout-compatible contiguous backing buffer. The
250+ // vector is kept alive for the duration of the call.
251+ let fastcall_arg_ptrs = args. args . as_mut_ptr ( ) . cast :: < * mut PyObject > ( ) ;
252+ let ret_ptr = unsafe { f ( slf_ptr, fastcall_arg_ptrs, args. args . len ( ) as isize ) } ;
230253 ret_ptr_to_pyresult ( vm, ret_ptr)
231254}
232255
@@ -247,7 +270,7 @@ fn take_self_arg(args: &mut FuncArgs, flags: PyMethodFlags) -> Option<PyObjectRe
247270}
248271
249272#[ unsafe( no_mangle) ]
250- pub extern "C" fn PyCMethod_New (
273+ pub unsafe extern "C" fn PyCMethod_New (
251274 ml : * mut PyMethodDef ,
252275 slf : * mut PyObject ,
253276 _module : * mut PyObject ,
@@ -260,24 +283,27 @@ pub extern "C" fn PyCMethod_New(
260283 ) ;
261284 let ml = unsafe { & * ml } ;
262285 let zelf = unsafe { slf. as_ref ( ) . map ( |obj| obj. to_owned ( ) ) } ;
263- Ok ( build_method_def ( vm, ml, zelf. is_some ( ) )
286+ Ok ( build_method_def ( vm, ml, zelf. is_some ( ) ) ?
264287 . build_function ( vm, zelf)
265288 . into ( ) )
266289 } )
267290}
268291
269292#[ unsafe( no_mangle) ]
270- pub extern "C" fn PyCFunction_New ( ml : * mut PyMethodDef , slf : * mut PyObject ) -> * mut PyObject {
271- PyCMethod_New ( ml, slf, core:: ptr:: null_mut ( ) , core:: ptr:: null_mut ( ) )
293+ pub unsafe extern "C" fn PyCFunction_New (
294+ ml : * mut PyMethodDef ,
295+ slf : * mut PyObject ,
296+ ) -> * mut PyObject {
297+ unsafe { PyCMethod_New ( ml, slf, core:: ptr:: null_mut ( ) , core:: ptr:: null_mut ( ) ) }
272298}
273299
274300#[ unsafe( no_mangle) ]
275- pub extern "C" fn PyCFunction_NewEx (
301+ pub unsafe extern "C" fn PyCFunction_NewEx (
276302 ml : * mut PyMethodDef ,
277303 slf : * mut PyObject ,
278304 module : * mut PyObject ,
279305) -> * mut PyObject {
280- PyCMethod_New ( ml, slf, module, core:: ptr:: null_mut ( ) )
306+ unsafe { PyCMethod_New ( ml, slf, module, core:: ptr:: null_mut ( ) ) }
281307}
282308
283309#[ cfg( test) ]
0 commit comments