Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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