Skip to content

Commit 01459ec

Browse files
committed
Fix vectorcall compatibility with LocalsPlus API
Update vectorcall dispatch functions to use localsplus stack accessors instead of direct stack field access. Add stack_truncate method to LocalsPlus. Update vectorcall fast path in function.rs to use datastack and fastlocals_mut().
1 parent 91f6a12 commit 01459ec

File tree

2 files changed

+38
-15
lines changed

2 files changed

+38
-15
lines changed

crates/vm/src/builtins/function.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1307,26 +1307,33 @@ pub(crate) fn vectorcall_function(
13071307
zelf.builtins.clone(),
13081308
zelf.closure.as_ref().map_or(&[], |c| c.as_slice()),
13091309
Some(zelf.to_owned().into()),
1310+
true, // Always use datastack (is_simple excludes gen/coro)
13101311
vm,
13111312
)
13121313
.into_ref(&vm.ctx);
13131314

13141315
{
1315-
let fastlocals = unsafe { frame.fastlocals.borrow_mut() };
1316+
let fastlocals = unsafe { frame.fastlocals_mut() };
13161317
for (slot, arg) in fastlocals.iter_mut().zip(args.drain(..nargs)) {
13171318
*slot = Some(arg);
13181319
}
13191320
}
13201321

13211322
if let Some(cell2arg) = code.cell2arg.as_deref() {
1322-
let fastlocals = unsafe { frame.fastlocals.borrow_mut() };
1323+
let fastlocals = unsafe { frame.fastlocals_mut() };
13231324
for (cell_idx, arg_idx) in cell2arg.iter().enumerate().filter(|(_, i)| **i != -1) {
13241325
let x = fastlocals[*arg_idx as usize].take();
13251326
frame.set_cell_contents(cell_idx, x);
13261327
}
13271328
}
13281329

1329-
return vm.run_frame(frame);
1330+
let result = vm.run_frame(frame.clone());
1331+
unsafe {
1332+
if let Some(base) = frame.materialize_localsplus() {
1333+
vm.datastack_pop(base);
1334+
}
1335+
}
1336+
return result;
13301337
}
13311338

13321339
// SLOW PATH: construct FuncArgs from owned Vec and delegate to invoke()

crates/vm/src/frame.rs

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,14 @@ impl LocalsPlus {
380380
data.swap(base + a, base + b);
381381
}
382382

383+
/// Truncate the stack to `new_len` elements, dropping excess values.
384+
fn stack_truncate(&mut self, new_len: usize) {
385+
debug_assert!(new_len <= self.stack_top as usize);
386+
while self.stack_top as usize > new_len {
387+
let _ = self.stack_pop();
388+
}
389+
}
390+
383391
/// Clear the stack, dropping all values.
384392
fn stack_clear(&mut self) {
385393
while self.stack_top > 0 {
@@ -6050,13 +6058,15 @@ impl ExecutingFrame<'_> {
60506058
#[inline]
60516059
fn execute_call_vectorcall(&mut self, nargs: u32, vm: &VirtualMachine) -> FrameResult {
60526060
let nargs_usize = nargs as usize;
6053-
let stack_len = self.stack.len();
6061+
let stack_len = self.localsplus.stack_len();
60546062
let callable_idx = stack_len - nargs_usize - 2;
60556063
let self_or_null_idx = stack_len - nargs_usize - 1;
60566064
let args_start = stack_len - nargs_usize;
60576065

60586066
// Check if callable has vectorcall slot
6059-
let has_vectorcall = self.stack[callable_idx]
6067+
let has_vectorcall = self
6068+
.localsplus
6069+
.stack_index(callable_idx)
60606070
.as_ref()
60616071
.is_some_and(|sr| sr.as_object().class().slots.vectorcall.load().is_some());
60626072

@@ -6067,7 +6077,9 @@ impl ExecutingFrame<'_> {
60676077
}
60686078

60696079
// Build args slice: [self_or_null?, arg1, ..., argN]
6070-
let self_or_null = self.stack[self_or_null_idx]
6080+
let self_or_null = self
6081+
.localsplus
6082+
.stack_index_mut(self_or_null_idx)
60716083
.take()
60726084
.map(|sr| sr.to_pyobj());
60736085
let has_self = self_or_null.is_some();
@@ -6082,12 +6094,12 @@ impl ExecutingFrame<'_> {
60826094
args_vec.push(self_val);
60836095
}
60846096
for stack_idx in args_start..stack_len {
6085-
let val = self.stack[stack_idx].take().unwrap().to_pyobj();
6097+
let val = self.localsplus.stack_index_mut(stack_idx).take().unwrap().to_pyobj();
60866098
args_vec.push(val);
60876099
}
60886100

6089-
let callable_obj = self.stack[callable_idx].take().unwrap().to_pyobj();
6090-
self.stack.truncate(callable_idx);
6101+
let callable_obj = self.localsplus.stack_index_mut(callable_idx).take().unwrap().to_pyobj();
6102+
self.localsplus.stack_truncate(callable_idx);
60916103

60926104
let result = callable_obj.vectorcall(args_vec, effective_nargs, None, vm)?;
60936105
self.push_value(result);
@@ -6106,13 +6118,15 @@ impl ExecutingFrame<'_> {
61066118
.expect("kwarg names should be tuple");
61076119
let kw_count = kwarg_names_tuple.len();
61086120

6109-
let stack_len = self.stack.len();
6121+
let stack_len = self.localsplus.stack_len();
61106122
let callable_idx = stack_len - nargs_usize - 2;
61116123
let self_or_null_idx = stack_len - nargs_usize - 1;
61126124
let args_start = stack_len - nargs_usize;
61136125

61146126
// Check if callable has vectorcall slot
6115-
let has_vectorcall = self.stack[callable_idx]
6127+
let has_vectorcall = self
6128+
.localsplus
6129+
.stack_index(callable_idx)
61166130
.as_ref()
61176131
.is_some_and(|sr| sr.as_object().class().slots.vectorcall.load().is_some());
61186132

@@ -6143,7 +6157,9 @@ impl ExecutingFrame<'_> {
61436157
}
61446158

61456159
// Build args: [self?, pos_arg1, ..., pos_argM, kw_val1, ..., kw_valK]
6146-
let self_or_null = self.stack[self_or_null_idx]
6160+
let self_or_null = self
6161+
.localsplus
6162+
.stack_index_mut(self_or_null_idx)
61476163
.take()
61486164
.map(|sr| sr.to_pyobj());
61496165
let has_self = self_or_null.is_some();
@@ -6158,12 +6174,12 @@ impl ExecutingFrame<'_> {
61586174
args_vec.push(self_val);
61596175
}
61606176
for stack_idx in args_start..stack_len {
6161-
let val = self.stack[stack_idx].take().unwrap().to_pyobj();
6177+
let val = self.localsplus.stack_index_mut(stack_idx).take().unwrap().to_pyobj();
61626178
args_vec.push(val);
61636179
}
61646180

6165-
let callable_obj = self.stack[callable_idx].take().unwrap().to_pyobj();
6166-
self.stack.truncate(callable_idx);
6181+
let callable_obj = self.localsplus.stack_index_mut(callable_idx).take().unwrap().to_pyobj();
6182+
self.localsplus.stack_truncate(callable_idx);
61676183

61686184
let kwnames = kwarg_names_tuple.as_slice();
61696185
let result = callable_obj.vectorcall(args_vec, effective_nargs, Some(kwnames), vm)?;

0 commit comments

Comments
 (0)