Skip to content

Commit 3bdcc3b

Browse files
committed
Add per-type vectorcall for builtin constructors
Add vectorcall dispatch in vectorcall_type to check each type's own slots.vectorcall before falling back to PyType::call. Only dispatch when slots.call is None, to avoid misinterpreting callable-instance vectorcalls (e.g. vectorcall_function) as constructor vectorcalls. Clear vectorcall when __init__ or __new__ is overridden in update_slot to ensure subclass correctness. Implement per-type vectorcall for 12 builtin types: - Pattern A (skip args.clone): dict, set, list, bytearray - Pattern B (skip dispatch): int, float, str, bool, tuple, frozenset, bytes, complex
1 parent c578ac0 commit 3bdcc3b

File tree

13 files changed

+234
-3
lines changed

13 files changed

+234
-3
lines changed

crates/vm/src/builtins/bool.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,26 @@ impl Representable for PyBool {
182182
}
183183
}
184184

185+
fn vectorcall_bool(
186+
zelf_obj: &PyObject,
187+
args: Vec<PyObjectRef>,
188+
nargs: usize,
189+
kwnames: Option<&[PyObjectRef]>,
190+
vm: &VirtualMachine,
191+
) -> PyResult {
192+
let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap();
193+
let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames);
194+
PyBool::slot_new(zelf.to_owned(), func_args, vm)
195+
}
196+
185197
pub(crate) fn init(context: &'static Context) {
186198
PyBool::extend_class(context, context.types.bool_type);
199+
context
200+
.types
201+
.bool_type
202+
.slots
203+
.vectorcall
204+
.store(Some(vectorcall_bool));
187205
}
188206

189207
// pub fn not(vm: &VirtualMachine, obj: &PyObject) -> PyResult<bool> {

crates/vm/src/builtins/bytearray.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ use crate::{
2323
},
2424
convert::{ToPyObject, ToPyResult},
2525
function::{
26-
ArgBytesLike, ArgIterable, ArgSize, Either, OptionalArg, OptionalOption, PyComparisonValue,
26+
ArgBytesLike, ArgIterable, ArgSize, Either, FuncArgs, OptionalArg, OptionalOption,
27+
PyComparisonValue,
2728
},
2829
protocol::{
2930
BufferDescriptor, BufferMethods, BufferResizeGuard, PyBuffer, PyIterReturn,
@@ -66,9 +67,29 @@ impl PyPayload for PyByteArray {
6667
}
6768
}
6869

70+
fn vectorcall_bytearray(
71+
zelf_obj: &PyObject,
72+
args: Vec<PyObjectRef>,
73+
nargs: usize,
74+
kwnames: Option<&[PyObjectRef]>,
75+
vm: &VirtualMachine,
76+
) -> PyResult {
77+
let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap();
78+
let obj = PyByteArray::default().into_ref_with_type(vm, zelf.to_owned())?;
79+
let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames);
80+
PyByteArray::slot_init(obj.clone().into(), func_args, vm)?;
81+
Ok(obj.into())
82+
}
83+
6984
/// Fill bytearray class methods dictionary.
7085
pub(crate) fn init(context: &'static Context) {
7186
PyByteArray::extend_class(context, context.types.bytearray_type);
87+
context
88+
.types
89+
.bytearray_type
90+
.slots
91+
.vectorcall
92+
.store(Some(vectorcall_bytearray));
7293
PyByteArrayIterator::extend_class(context, context.types.bytearray_iterator_type);
7394
}
7495

crates/vm/src/builtins/bytes.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,27 @@ impl PyPayload for PyBytes {
8686
}
8787
}
8888

89+
fn vectorcall_bytes(
90+
zelf_obj: &PyObject,
91+
args: Vec<PyObjectRef>,
92+
nargs: usize,
93+
kwnames: Option<&[PyObjectRef]>,
94+
vm: &VirtualMachine,
95+
) -> PyResult {
96+
let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap();
97+
let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames);
98+
PyBytes::slot_new(zelf.to_owned(), func_args, vm)
99+
}
100+
89101
pub(crate) fn init(context: &'static Context) {
90102
PyBytes::extend_class(context, context.types.bytes_type);
91103
PyBytesIterator::extend_class(context, context.types.bytes_iterator_type);
104+
context
105+
.types
106+
.bytes_type
107+
.slots
108+
.vectorcall
109+
.store(Some(vectorcall_bytes));
92110
}
93111

94112
impl Constructor for PyBytes {

crates/vm/src/builtins/complex.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,26 @@ impl PyObjectRef {
129129
}
130130
}
131131

132+
fn vectorcall_complex(
133+
zelf_obj: &PyObject,
134+
args: Vec<PyObjectRef>,
135+
nargs: usize,
136+
kwnames: Option<&[PyObjectRef]>,
137+
vm: &VirtualMachine,
138+
) -> PyResult {
139+
let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap();
140+
let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames);
141+
PyComplex::slot_new(zelf.to_owned(), func_args, vm)
142+
}
143+
132144
pub fn init(context: &'static Context) {
133145
PyComplex::extend_class(context, context.types.complex_type);
146+
context
147+
.types
148+
.complex_type
149+
.slots
150+
.vectorcall
151+
.store(Some(vectorcall_complex));
134152
}
135153

136154
fn to_op_complex(value: &PyObject, vm: &VirtualMachine) -> PyResult<Option<Complex64>> {

crates/vm/src/builtins/dict.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ use crate::{
1515
class::{PyClassDef, PyClassImpl},
1616
common::ascii,
1717
dict_inner::{self, DictKey},
18-
function::{ArgIterable, KwArgs, OptionalArg, PyArithmeticValue::*, PyComparisonValue},
18+
function::{
19+
ArgIterable, FuncArgs, KwArgs, OptionalArg, PyArithmeticValue::*, PyComparisonValue,
20+
},
1921
iter::PyExactSizeIterator,
2022
protocol::{PyIterIter, PyIterReturn, PyMappingMethods, PyNumberMethods, PySequenceMethods},
2123
recursion::ReprGuard,
@@ -1433,8 +1435,28 @@ fn set_inner_number_or(a: &PyObject, b: &PyObject, vm: &VirtualMachine) -> PyRes
14331435
set_inner_number_op(a, b, |a, b| a.union(b, vm), vm)
14341436
}
14351437

1438+
fn vectorcall_dict(
1439+
zelf_obj: &PyObject,
1440+
args: Vec<PyObjectRef>,
1441+
nargs: usize,
1442+
kwnames: Option<&[PyObjectRef]>,
1443+
vm: &VirtualMachine,
1444+
) -> PyResult {
1445+
let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap();
1446+
let obj = PyDict::default().into_ref_with_type(vm, zelf.to_owned())?;
1447+
let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames);
1448+
PyDict::slot_init(obj.clone().into(), func_args, vm)?;
1449+
Ok(obj.into())
1450+
}
1451+
14361452
pub(crate) fn init(context: &'static Context) {
14371453
PyDict::extend_class(context, context.types.dict_type);
1454+
context
1455+
.types
1456+
.dict_type
1457+
.slots
1458+
.vectorcall
1459+
.store(Some(vectorcall_dict));
14381460
PyDictKeys::extend_class(context, context.types.dict_keys_type);
14391461
PyDictKeyIterator::extend_class(context, context.types.dict_keyiterator_type);
14401462
PyDictReverseKeyIterator::extend_class(context, context.types.dict_reversekeyiterator_type);

crates/vm/src/builtins/float.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,20 @@ pub(crate) fn get_value(obj: &PyObject) -> f64 {
525525
obj.downcast_ref::<PyFloat>().unwrap().value
526526
}
527527

528+
fn vectorcall_float(
529+
zelf_obj: &PyObject,
530+
args: Vec<PyObjectRef>,
531+
nargs: usize,
532+
kwnames: Option<&[PyObjectRef]>,
533+
vm: &VirtualMachine,
534+
) -> PyResult {
535+
let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap();
536+
let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames);
537+
PyFloat::slot_new(zelf.to_owned(), func_args, vm)
538+
}
539+
528540
#[rustfmt::skip] // to avoid line splitting
529541
pub fn init(context: &'static Context) {
530542
PyFloat::extend_class(context, context.types.float_type);
543+
context.types.float_type.slots.vectorcall.store(Some(vectorcall_float));
531544
}

crates/vm/src/builtins/int.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,24 @@ pub fn try_to_float(int: &BigInt, vm: &VirtualMachine) -> PyResult<f64> {
791791
.ok_or_else(|| vm.new_overflow_error("int too large to convert to float"))
792792
}
793793

794+
fn vectorcall_int(
795+
zelf_obj: &PyObject,
796+
args: Vec<PyObjectRef>,
797+
nargs: usize,
798+
kwnames: Option<&[PyObjectRef]>,
799+
vm: &VirtualMachine,
800+
) -> PyResult {
801+
let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap();
802+
let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames);
803+
PyInt::slot_new(zelf.to_owned(), func_args, vm)
804+
}
805+
794806
pub(crate) fn init(context: &'static Context) {
795807
PyInt::extend_class(context, context.types.int_type);
808+
context
809+
.types
810+
.int_type
811+
.slots
812+
.vectorcall
813+
.store(Some(vectorcall_int));
796814
}

crates/vm/src/builtins/list.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,9 +768,24 @@ impl IterNext for PyListReverseIterator {
768768
}
769769
}
770770

771+
fn vectorcall_list(
772+
zelf_obj: &PyObject,
773+
args: Vec<PyObjectRef>,
774+
nargs: usize,
775+
kwnames: Option<&[PyObjectRef]>,
776+
vm: &VirtualMachine,
777+
) -> PyResult {
778+
let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap();
779+
let obj = PyList::default().into_ref_with_type(vm, zelf.to_owned())?;
780+
let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames);
781+
PyList::slot_init(obj.clone().into(), func_args, vm)?;
782+
Ok(obj.into())
783+
}
784+
771785
pub fn init(context: &'static Context) {
772786
let list_type = &context.types.list_type;
773787
PyList::extend_class(context, list_type);
788+
list_type.slots.vectorcall.store(Some(vectorcall_list));
774789

775790
PyListIterator::extend_class(context, context.types.list_iterator_type);
776791
PyListReverseIterator::extend_class(context, context.types.list_reverseiterator_type);

crates/vm/src/builtins/set.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1421,8 +1421,48 @@ impl IterNext for PySetIterator {
14211421
}
14221422
}
14231423

1424+
fn vectorcall_set(
1425+
zelf_obj: &PyObject,
1426+
args: Vec<PyObjectRef>,
1427+
nargs: usize,
1428+
kwnames: Option<&[PyObjectRef]>,
1429+
vm: &VirtualMachine,
1430+
) -> PyResult {
1431+
let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap();
1432+
let obj = PySet::default().into_ref_with_type(vm, zelf.to_owned())?;
1433+
let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames);
1434+
PySet::slot_init(obj.clone().into(), func_args, vm)?;
1435+
Ok(obj.into())
1436+
}
1437+
1438+
fn vectorcall_frozenset(
1439+
zelf_obj: &PyObject,
1440+
args: Vec<PyObjectRef>,
1441+
nargs: usize,
1442+
kwnames: Option<&[PyObjectRef]>,
1443+
vm: &VirtualMachine,
1444+
) -> PyResult {
1445+
let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap();
1446+
let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames);
1447+
PyFrozenSet::slot_new(zelf.to_owned(), func_args, vm)
1448+
}
1449+
14241450
pub fn init(context: &'static Context) {
14251451
PySet::extend_class(context, context.types.set_type);
1452+
context
1453+
.types
1454+
.set_type
1455+
.slots
1456+
.vectorcall
1457+
.store(Some(vectorcall_set));
1458+
14261459
PyFrozenSet::extend_class(context, context.types.frozenset_type);
1460+
context
1461+
.types
1462+
.frozenset_type
1463+
.slots
1464+
.vectorcall
1465+
.store(Some(vectorcall_frozenset));
1466+
14271467
PySetIterator::extend_class(context, context.types.set_iterator_type);
14281468
}

crates/vm/src/builtins/str.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1782,8 +1782,25 @@ struct ReplaceArgs {
17821782
count: isize,
17831783
}
17841784

1785+
fn vectorcall_str(
1786+
zelf_obj: &PyObject,
1787+
args: Vec<PyObjectRef>,
1788+
nargs: usize,
1789+
kwnames: Option<&[PyObjectRef]>,
1790+
vm: &VirtualMachine,
1791+
) -> PyResult {
1792+
let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap();
1793+
let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames);
1794+
PyStr::slot_new(zelf.to_owned(), func_args, vm)
1795+
}
1796+
17851797
pub fn init(ctx: &'static Context) {
17861798
PyStr::extend_class(ctx, ctx.types.str_type);
1799+
ctx.types
1800+
.str_type
1801+
.slots
1802+
.vectorcall
1803+
.store(Some(vectorcall_str));
17871804

17881805
PyStrIterator::extend_class(ctx, ctx.types.str_iterator_type);
17891806
}

0 commit comments

Comments
 (0)