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
5 changes: 5 additions & 0 deletions majit/majit-translate/src/annotator/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,11 @@ fn register_builtins() -> HashMap<String, BuiltinAnalyzer> {
"pyre_object.lltype.malloc_typed",
malloc_typed_alloc,
);
analyzer_for(
&mut reg,
"pyre_object.lltype.malloc_typed_managed",
malloc_typed_alloc,
);
// `pyre_object::lltype::malloc_raw` — the raw (non-GC) allocation
// intrinsic (`lltype.malloc(T, flavor='raw')` parity). Recognising it
// as a builtin keeps its `Box::new` / `Box::into_raw` body out of the
Expand Down
4 changes: 4 additions & 0 deletions majit/majit-translate/src/flowspace/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2209,6 +2209,10 @@ impl HostEnv {
"malloc_typed",
HostObject::new_builtin_callable("pyre_object.lltype.malloc_typed"),
);
pyre_object_lltype.module_set(
"malloc_typed_managed",
HostObject::new_builtin_callable("pyre_object.lltype.malloc_typed_managed"),
);
// `pyre_object::lltype::malloc_raw` — the raw (non-GC) allocation
// intrinsic (`lltype.malloc(T, flavor='raw')` parity). Exposed as a
// host builtin so its `Box::new` body is never looked-inside; the
Expand Down
5 changes: 4 additions & 1 deletion majit/majit-translate/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2677,7 +2677,10 @@ pub fn fuse_boxing_alloc(
let is_malloc_typed = |target: &CallTarget| -> bool {
matches!(target, CallTarget::FunctionPath { segments }
if segments.len() >= 2
&& segments[segments.len() - 1] == "malloc_typed"
&& matches!(
segments[segments.len() - 1].as_str(),
"malloc_typed" | "malloc_typed_managed"
)
&& segments[segments.len() - 2] == "lltype")
};

Expand Down
4 changes: 3 additions & 1 deletion majit/majit-translate/src/translator/rtyper/cutover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1565,7 +1565,9 @@ pub(crate) fn populate_call_registry_from_call_graphs(
// `is_known_unported`) so the graph census-Skips to the legacy walker
// instead of silently matching a wrong residual call. Tracked by the
// boxing-lowering epic (#134/#142).
if canonical_strip == ["lltype", "malloc_typed"] {
if canonical_strip == ["lltype", "malloc_typed"]
|| canonical_strip == ["lltype", "malloc_typed_managed"]
{
continue;
}
// `pyre_object::lltype::malloc_raw` is the raw (non-GC) allocation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1695,10 +1695,13 @@ pub fn translate_op(
// `malloc_typed` registration skip).
if segments.len() >= 2
&& segments[segments.len() - 2] == "lltype"
&& segments[segments.len() - 1] == "malloc_typed"
&& matches!(
segments[segments.len() - 1].as_str(),
"malloc_typed" | "malloc_typed_managed"
)
{
return Err(TyperError::message(
"`lltype::malloc_typed` survived fuse_boxing_alloc unfused; \
"`lltype::malloc_typed[_managed]` survived fuse_boxing_alloc unfused; \
only the numeric boxing structs fuse_boxing_alloc rewrites \
(W_Float/W_Int/W_Complex/W_Long) have a NewWithVtable \
lowering; no general malloc->new lowering ported"
Expand Down
45 changes: 24 additions & 21 deletions pyre/pyre-interpreter/src/_structseq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
//! f1=v1, ...)"` rendering.

use indexmap::IndexMap;
use std::cell::RefCell;
use std::sync::{Mutex, OnceLock};

use pyre_object::PyObjectRef;

Expand All @@ -39,7 +39,7 @@ use crate::PyError;
struct StructSeqDescr {
name: String,
/// Field names in positional order. Names starting with `_` are
/// CPython's "unnamed" placeholders (`_structseq.py:67-69`).
/// unnamed placeholders (`_structseq.py:67-69`).
fields: Vec<String>,
/// Named-only fields stored in the instance `__dict__` rather than the
/// tuple body (`_structseq.py:31-37` — the `obj.__dict__[name]` arm).
Expand All @@ -52,12 +52,13 @@ struct StructSeqDescr {
extra_fields: Vec<String>,
}

thread_local! {
/// `class_ptr → StructSeqDescr`. Pyre keys by the subclass type
/// pointer because the GetSetProperty descriptor only carries a
/// `name` slot (`typedef.rs:174`), not the owning class.
static STRUCTSEQ_REGISTRY: RefCell<IndexMap<usize, StructSeqDescr>> =
RefCell::new(IndexMap::new());
/// `class_ptr → StructSeqDescr`. Pyre keys by the subclass type
/// pointer because the GetSetProperty descriptor only carries a
/// `name` slot (`typedef.rs:174`), not the owning class.
static STRUCTSEQ_REGISTRY: OnceLock<Mutex<IndexMap<usize, StructSeqDescr>>> = OnceLock::new();

fn structseq_registry() -> &'static Mutex<IndexMap<usize, StructSeqDescr>> {
STRUCTSEQ_REGISTRY.get_or_init(|| Mutex::new(IndexMap::new()))
}

/// `lib_pypy/_structseq.py:31-37 structseqfield.__get__` —
Expand Down Expand Up @@ -94,10 +95,12 @@ fn structseq_field_get(args: &[PyObjectRef]) -> Result<PyObjectRef, PyError> {
}
// `_structseq.py:31-37` — an extra (dict-backed) field shadows a
// same-named positional slot, so resolve those first.
let resolved = STRUCTSEQ_REGISTRY.with(|r| {
let map = r.borrow();
let resolved = {
let map = structseq_registry().lock().unwrap();
let Some(entry) = map.get(&(cls as usize)) else {
return Resolved::Missing;
return Err(PyError::attribute_error(format!(
"structseq object has no field {name}"
)));
};
if entry.extra_fields.iter().any(|n| n == &name) {
Resolved::Extra
Expand All @@ -106,7 +109,7 @@ fn structseq_field_get(args: &[PyObjectRef]) -> Result<PyObjectRef, PyError> {
} else {
Resolved::Missing
}
});
};
match resolved {
Resolved::Extra => {
let w_dict = crate::baseobjspace::getdict(inst);
Expand Down Expand Up @@ -137,12 +140,12 @@ fn structseq_repr(args: &[PyObjectRef]) -> Result<PyObjectRef, PyError> {
return Err(PyError::type_error("structseq __repr__ missing self"));
}
let cls = unsafe { (*inst).w_class };
let (name, fields) = STRUCTSEQ_REGISTRY.with(|r| -> (String, Vec<String>) {
let map = r.borrow();
let (name, fields) = {
let map = structseq_registry().lock().unwrap();
map.get(&(cls as usize))
.map(|d| (d.name.clone(), d.fields.clone()))
.unwrap_or_default()
});
};
let n = unsafe { pyre_object::w_tuple_len(inst) };
let mut parts: Vec<String> = Vec::with_capacity(n);
for i in 0..n {
Expand Down Expand Up @@ -227,12 +230,12 @@ fn structseq_descr_new(args: &[PyObjectRef]) -> Result<PyObjectRef, PyError> {
let cls = args[0];
let n_seq = read_class_int(cls, "n_sequence_fields").unwrap_or(0) as usize;
let n_fields = read_class_int(cls, "n_fields").unwrap_or(n_seq as i64) as usize;
let (name, extra_names) = STRUCTSEQ_REGISTRY.with(|r| {
let map = r.borrow();
let (name, extra_names) = {
let map = structseq_registry().lock().unwrap();
map.get(&(cls as usize))
.map(|d| (d.name.clone(), d.extra_fields.clone()))
.unwrap_or_else(|| ("structseq".to_string(), Vec::new()))
});
};

// `_structseq.py:95-101` — the optional second arg is a dict supplying
// values for the named-only extra fields.
Expand Down Expand Up @@ -523,16 +526,16 @@ fn make_struct_seq_impl(
unsafe { pyre_object::typeobject::w_type_set_hasdict(cls, true) };
}

STRUCTSEQ_REGISTRY.with(|r| {
r.borrow_mut().insert(
{
structseq_registry().lock().unwrap().insert(
cls as usize,
StructSeqDescr {
name: name.to_string(),
fields: owned_names,
extra_fields: owned_extra,
},
);
});
}

cls
}
Loading
Loading