Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
289 changes: 289 additions & 0 deletions pyre/pyre-interpreter/src/pyframe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2630,6 +2630,295 @@
)
}

/// `typedef.py _make_descr_typecheck_wrapper` around `PyFrame::fget_f_code`.
///
/// `GetSetProperty` binds this as its `fget` for `f_code`.
pub fn descr_typecheck_fget_f_code(args: &[PyObjectRef]) -> Result<PyObjectRef, crate::PyError> {
let f = args.get(1).copied().unwrap_or(pyre_object::PY_NULL) as *mut PyFrame;
if f.is_null() {
return Ok(pyre_object::w_none());
}
Ok(unsafe { &*f }.fget_f_code())
}

/// `typedef.py _make_descr_typecheck_wrapper` around `PyFrame::get_w_globals`.
///
/// `GetSetProperty` binds this as its `fget` for `f_globals`.
pub fn descr_typecheck_get_w_globals(args: &[PyObjectRef]) -> Result<PyObjectRef, crate::PyError> {
let f = args.get(1).copied().unwrap_or(pyre_object::PY_NULL) as *mut PyFrame;
if f.is_null() {
return Ok(pyre_object::w_none());
}
let w = unsafe { &*f }.get_w_globals();
Ok(if w.is_null() {
pyre_object::w_none()
} else {
w
})
}

/// `typedef.py _make_descr_typecheck_wrapper` around `PyFrame::fget_f_back`.
///
/// `GetSetProperty` binds this as its `fget` for `f_back`.
pub fn descr_typecheck_fget_f_back(args: &[PyObjectRef]) -> Result<PyObjectRef, crate::PyError> {
let f = args.get(1).copied().unwrap_or(pyre_object::PY_NULL) as *mut PyFrame;
if f.is_null() {
return Ok(pyre_object::w_none());
}
let back = unsafe { &*f }.fget_f_back();
Ok(if back.is_null() {
pyre_object::w_none()
} else {
// Exposing the frame to app level: mark escaped so the JIT
// materialises it (pyframe.py:176), mirroring `_getframe`.

Check warning on line 2673 in pyre/pyre-interpreter/src/pyframe.rs

View workflow job for this annotation

GitHub Actions / pre-commit

Cite upstream by symbol

`pyframe.py:176` names a line number. Drop the `:LINE` and name the symbol, or add `allow-line-citation` to record that the number was deliberate.
unsafe { (*back).mark_as_escaped() };
back as pyre_object::PyObjectRef
})
}

/// `typedef.py _make_descr_typecheck_wrapper` around `PyFrame::get_generator`.
///
/// `GetSetProperty` binds this as its `fget` for `f_generator`.
pub fn descr_typecheck_get_generator(args: &[PyObjectRef]) -> Result<PyObjectRef, crate::PyError> {
let f = args.get(1).copied().unwrap_or(pyre_object::PY_NULL) as *mut PyFrame;
if f.is_null() {
return Ok(pyre_object::w_none());
}
let owner = unsafe { &*f }.get_generator();
Ok(if owner.is_null() {
pyre_object::w_none()
} else {
owner
})
}

/// `typedef.py _make_descr_typecheck_wrapper` around `PyFrame::fget_f_lasti`.
///
/// `GetSetProperty` binds this as its `fget` for `f_lasti`.
///
///
/// pyre stores `last_instr` as an instruction-unit index (increments
/// by 1 per instruction); CPython's `f_lasti` is a byte offset
/// (2 bytes per code unit). Report the byte-offset form (× 2) so
/// `dis` / `code.co_positions()` consumers that do `f_lasti // 2`
/// recover the right instruction — the same adaptation `tb_lasti`
/// uses (`typedef.rs` tb_lasti getter).
///
/// A negative `last_instr` means the frame has not run an instruction, and
/// that is not a coordinate this getter can hand out: `frame_lasti_get_impl`
/// turns only a negative `_PyInterpreterFrame_LASTI` into `-1`, and the
/// pointer is not negative there. Frame setup consumes the
/// compiler-inserted prologue, so the pointer rests on the first `RESUME`
/// -- `code->_co_firsttraceable` -- which is what the `call` event reports:
/// 0 for a plain function, 2 past a closure's `COPY_FREE_VARS`, 4 past a
/// generator's `RETURN_GENERATOR` / `POP_TOP`. Handing out `-1` instead
/// named a coordinate no frame ever executes. `pyframe.py fget_f_lasti`
/// returns `last_instr` unscaled and stops there, so both adaptations live
/// here rather than in [`PyFrame::fget_f_lasti`].
///
/// A generator is the one shape whose not-yet-started frame rests somewhere
/// else: `RETURN_GENERATOR` is what built the generator, so the frame it
/// left behind sits on the instruction after it until the first resumption
/// walks on to the `RESUME`. Only the generator's own started flag
/// separates the two, and the frame is reachable from Python in both states
/// through `gi_frame`.
///
/// That flag is read through the back-reference, which is cleared when the
/// generator is collected (`generator_finalize`) and when a generator that
/// never ran finishes. A frame that outlives its generator therefore
/// cannot say which of the two it rests on, and the sentinel stands: the
/// `RESUME` would be the coordinate for a frame still at its `call` event,
/// which this one is not.
///
/// The flag alone does not separate a first `send` from a first `throw`,
/// which marks the generator started and then injects before the `RESUME`
/// is reached -- that frame is still on the instruction after
/// `RETURN_GENERATOR`. Nothing reads it there: the trace events that
/// would are not emitted for an injection into a generator that never ran,
/// and the frame is unlinked by the time the call returns. Whatever
/// starts emitting them owns that distinction.
///
/// `-1` is left for a code object with no `RESUME` too, where that index
/// runs past the end and the frame starts no line either.
pub fn descr_typecheck_fget_f_lasti(args: &[PyObjectRef]) -> Result<PyObjectRef, crate::PyError> {
let f = args.get(1).copied().unwrap_or(pyre_object::PY_NULL) as *mut PyFrame;
if f.is_null() {
return Ok(pyre_object::w_none());
}
let frame = unsafe { &*f };
let lasti = frame.fget_f_lasti();
let lasti = if lasti < 0 {
let code = frame.code();
let owner = frame.get_generator();
let index = match crate::pycode::after_return_generator_index(code) {
Some(after_return_generator) => (!owner.is_null()).then(|| {
if unsafe { pyre_object::generator::w_generator_is_started(owner) } {
crate::pycode::first_traceable_index(code)
} else {
after_return_generator
}
}),
None => Some(crate::pycode::first_traceable_index(code)),
};
match index {
Some(index) if index < code.instructions.len() => index as i64,
_ => -1,
}
} else {
lasti as i64
};
Ok(pyre_object::w_int_new(if lasti < 0 {
-1
} else {
lasti * 2
}))
}

/// `typedef.py _make_descr_typecheck_wrapper` around `PyFrame::fget_f_builtins`.
///
/// `GetSetProperty` binds this as its `fget` for `f_builtins`.
pub fn descr_typecheck_fget_f_builtins(
args: &[PyObjectRef],
) -> Result<PyObjectRef, crate::PyError> {
let f = args.get(1).copied().unwrap_or(pyre_object::PY_NULL) as *mut PyFrame;
if f.is_null() {
return Ok(pyre_object::w_none());
}
let w = unsafe { &*f }.fget_f_builtins();
Ok(if w.is_null() {
pyre_object::w_none()
} else {
w
})
}

/// `typedef.py _make_descr_typecheck_wrapper` around `PyFrame::fget_f_lineno`.
///
/// `GetSetProperty` binds this as its `fget` for `f_lineno`.
pub fn descr_typecheck_fget_f_lineno(args: &[PyObjectRef]) -> Result<PyObjectRef, crate::PyError> {
let f = args.get(1).copied().unwrap_or(pyre_object::PY_NULL) as *mut PyFrame;
if f.is_null() {
return Ok(pyre_object::w_none());
}
Ok(unsafe { &*f }.fget_f_lineno())
}

/// `typedef.py _make_descr_typecheck_wrapper` around `PyFrame::fset_f_lineno`.
///
/// `GetSetProperty` binds this as its `fset` for `f_lineno`.
pub fn descr_typecheck_fset_f_lineno(args: &[PyObjectRef]) -> Result<PyObjectRef, crate::PyError> {
let f = args.get(1).copied().unwrap_or(pyre_object::PY_NULL) as *mut PyFrame;
if f.is_null() {
return Ok(pyre_object::w_none());
}
// `int_w` reaches `__index__`, which is application-level Python.
let anchor = unsafe { crate::eval::FrameAnchor::from_raw(f) };
let new_lineno = crate::baseobjspace::int_w(args[2])
.map_err(|_| crate::PyError::value_error("lineno must be an integer"))?;
unsafe { &mut *anchor.live() }.fset_f_lineno(new_lineno as isize)?;
Ok(pyre_object::w_none())
}

/// `typedef.py _make_descr_typecheck_wrapper` around `PyFrame::fget_f_trace`.
///
/// `GetSetProperty` binds this as its `fget` for `f_trace`.
pub fn descr_typecheck_fget_f_trace(args: &[PyObjectRef]) -> Result<PyObjectRef, crate::PyError> {
let f = args.get(1).copied().unwrap_or(pyre_object::PY_NULL) as *mut PyFrame;
if f.is_null() {
return Ok(pyre_object::w_none());
}
let w = unsafe { &*f }.fget_f_trace();
Ok(if w.is_null() {
pyre_object::w_none()
} else {
w
})
}

/// `typedef.py _make_descr_typecheck_wrapper` around `PyFrame::fset_f_trace`.
///
/// `GetSetProperty` binds this as its `fset` for `f_trace`.
pub fn descr_typecheck_fset_f_trace(args: &[PyObjectRef]) -> Result<PyObjectRef, crate::PyError> {
let f = args.get(1).copied().unwrap_or(pyre_object::PY_NULL) as *mut PyFrame;
if !f.is_null() {
unsafe { &mut *f }.fset_f_trace(args[2]);
}
Ok(pyre_object::w_none())
}

/// `typedef.py _make_descr_typecheck_wrapper` around `PyFrame::fdel_f_trace`.
///
/// `GetSetProperty` binds this as its `fdel` for `f_trace`.
pub fn descr_typecheck_fdel_f_trace(args: &[PyObjectRef]) -> Result<PyObjectRef, crate::PyError> {
let f = args.get(1).copied().unwrap_or(pyre_object::PY_NULL) as *mut PyFrame;
if !f.is_null() {
unsafe { &mut *f }.fdel_f_trace();
}
Ok(pyre_object::w_none())
}

/// `typedef.py _make_descr_typecheck_wrapper` around `PyFrame::fget_f_trace_lines`.
///
/// `GetSetProperty` binds this as its `fget` for `f_trace_lines`.
pub fn descr_typecheck_fget_f_trace_lines(
args: &[PyObjectRef],
) -> Result<PyObjectRef, crate::PyError> {
let f = args.get(1).copied().unwrap_or(pyre_object::PY_NULL) as *mut PyFrame;
if f.is_null() {
return Ok(pyre_object::w_none());
}
Ok(pyre_object::w_bool_from(
unsafe { &*f }.fget_f_trace_lines(),
))
}

/// `typedef.py _make_descr_typecheck_wrapper` around `PyFrame::fset_f_trace_lines`.
///
/// `GetSetProperty` binds this as its `fset` for `f_trace_lines`.
pub fn descr_typecheck_fset_f_trace_lines(
args: &[PyObjectRef],
) -> Result<PyObjectRef, crate::PyError> {
let f = args.get(1).copied().unwrap_or(pyre_object::PY_NULL) as *mut PyFrame;
if !f.is_null() {
// `is_true` reaches `__bool__` / `__len__`.
let anchor = unsafe { crate::eval::FrameAnchor::from_raw(f) };
let v = crate::baseobjspace::is_true(args[2])?;
unsafe { &mut *anchor.live() }.fset_f_trace_lines(v);
}
Ok(pyre_object::w_none())
}

/// `typedef.py _make_descr_typecheck_wrapper` around `PyFrame::fget_f_trace_opcodes`.
///
/// `GetSetProperty` binds this as its `fget` for `f_trace_opcodes`.
pub fn descr_typecheck_fget_f_trace_opcodes(
args: &[PyObjectRef],
) -> Result<PyObjectRef, crate::PyError> {
let f = args.get(1).copied().unwrap_or(pyre_object::PY_NULL) as *mut PyFrame;
if f.is_null() {
return Ok(pyre_object::w_none());
}
Ok(pyre_object::w_bool_from(
unsafe { &*f }.fget_f_trace_opcodes(),
))
}

/// `typedef.py _make_descr_typecheck_wrapper` around `PyFrame::fset_f_trace_opcodes`.
///
/// `GetSetProperty` binds this as its `fset` for `f_trace_opcodes`.
pub fn descr_typecheck_fset_f_trace_opcodes(
args: &[PyObjectRef],
) -> Result<PyObjectRef, crate::PyError> {
let f = args.get(1).copied().unwrap_or(pyre_object::PY_NULL) as *mut PyFrame;
if !f.is_null() {
// `is_true` reaches `__bool__` / `__len__`.
let anchor = unsafe { crate::eval::FrameAnchor::from_raw(f) };
let v = crate::baseobjspace::is_true(args[2])?;
unsafe { &mut *anchor.live() }.fset_f_trace_opcodes(v);
}
Ok(pyre_object::w_none())
}

impl PyFrame {
/// pyframe.py getdebug → self.debugdata
#[inline]
Expand Down
Loading
Loading