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
22 changes: 22 additions & 0 deletions majit/majit-backend-dynasm/src/x86/assembler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5393,6 +5393,28 @@ impl<'a> Assembler386<'a> {
// `AbstractFailDescr` (`history.py:132 _attrs_`) receives the
// canonical copy. Must follow the `meta_descr` stamp above.
descr_fd.set_rd_locs(rd_locs);
// `regalloc.py:496-499 consider_guard_value` — every upstream backend
// stamps the per-value counter while laying the guard out, so
// `store_hash` (`compile.py:826-829`, gated on `status == 0`) leaves it
// alone and `must_compile` hashes the (guard, failing value) pair
// instead of the guard alone. Without it a guard whose failing value
// never repeats still accumulates in one bucket and compiles another
// bridge every `trace_eagerness` failures, without bound. The index is
// a fail-arg position because `must_compile_with_values` reads the value
// back out of `fail_values`.
if op.opcode == majit_ir::OpCode::GuardValue
&& let Some(fa) = op.getfailargs()
{
let arg0 = op.arg(0).to_opref();
if let Some(idx) = fa.iter().position(|r| r.to_opref() == arg0) {
let type_tag = match descr_fd.fail_arg_types().get(idx) {
Some(majit_ir::Type::Ref) => majit_backend::STATUS_TY_REF,
Some(majit_ir::Type::Float) => majit_backend::STATUS_TY_FLOAT,
_ => majit_backend::STATUS_TY_INT,
};
descr_fd.make_a_counter_per_value(idx as u32, type_tag);
}
}
if crate::majit_log_enabled() {
eprintln!(
"[dynasm] guard-token-slots: fail_index={} rd_locs={:?}",
Expand Down
14 changes: 12 additions & 2 deletions majit/majit-backend-wasm/src/failguard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,10 @@ pub struct CompiledWasmLoop {
/// module lives as long as the source loop it attaches to, so its cells are
/// freed when this loop drops. Appended by `compile_bridge`.
pub _bridge_owned_cells: RefCell<Vec<Box<[u32]>>>,
/// `(descr identity, table slot)` for every label published by a bridge
/// chained onto this loop. The bridge module lives as long as its source
/// loop, so `Drop` retracts entries that still name that bridge's slot.
pub bridge_owned_label_targets: RefCell<Vec<(usize, u32)>>,
/// Set when `compile_bridge` accepts a self-recursive `CallAssemblerR`
/// bridge (`PYRE_WASM_CA`) for this loop. While set, `compile_bridge`
/// declines chaining any FURTHER bridge into this recursion (the guard
Expand Down Expand Up @@ -733,10 +737,16 @@ impl Drop for CompiledWasmLoop {
// survive the old loop's drop.
let mut reg = LABEL_TARGETS.lock().unwrap();
if let Some(map) = reg.as_mut() {
for &id in &self.label_descrs {
for (id, func_handle) in self
.label_descrs
.iter()
.copied()
.map(|id| (id, self.func_handle.get()))
.chain(self.bridge_owned_label_targets.get_mut().iter().copied())
{
if id != 0
&& let Some(t) = map.get(&id)
&& t.func_handle == self.func_handle.get()
&& t.func_handle == func_handle
{
map.remove(&id);
crate::BRIDGE_DIAG[22].fetch_add(1, std::sync::atomic::Ordering::Relaxed);
Expand Down
277 changes: 164 additions & 113 deletions majit/majit-backend-wasm/src/lib.rs

Large diffs are not rendered by default.

83 changes: 61 additions & 22 deletions majit/majit-metainterp/src/optimizeopt/optimizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -817,9 +817,14 @@ impl Optimizer {
VirtualStateInfo::VArray { descr, items, .. } => {
let imported_items = items
.iter()
.map(|item_info| {
let r = Self::import_virtual_state_value(item_info, ctx);
ctx.materialize_operand_at(r)
.map(|item_info| match item_info {
Some(item_info) => {
let item_ref = Self::import_virtual_state_value(item_info, ctx);
ctx.materialize_operand_at(item_ref)
}
// virtualstate.py:272-280: absent fieldstate remains
// an unwritten virtual-array slot on import.
None => Operand::None,
})
.collect();
ctx.set_ptr_info(
Expand Down Expand Up @@ -869,8 +874,17 @@ impl Optimizer {
fields
.iter()
.map(|(field_idx, field_info)| {
let r = Self::import_virtual_state_value(field_info, ctx);
(*field_idx, ctx.materialize_operand_at(r))
let field = match field_info {
Some(field_info) => {
let field_ref =
Self::import_virtual_state_value(field_info, ctx);
ctx.materialize_operand_at(field_ref)
}
// virtualstate.py:328-354: retain the
// dense unwritten element-field slot.
None => Operand::None,
};
(*field_idx, field)
})
.collect()
})
Expand Down Expand Up @@ -1296,15 +1310,20 @@ impl Optimizer {
let (opref, head_box) = ctx.reserve_virtual_box(majit_ir::Type::Ref);
let imported_items = items
.iter()
.map(|item_info| {
let r = Self::import_virtual_state_from_label_args_recurse(
item_info,
imported_label_args,
label_slot,
ctx,
walk_visited,
);
ctx.materialize_operand_at(r)
.map(|item_info| match item_info {
Some(item_info) => {
let item_ref = Self::import_virtual_state_from_label_args_recurse(
item_info,
imported_label_args,
label_slot,
ctx,
walk_visited,
);
ctx.materialize_operand_at(item_ref)
}
// virtualstate.py:272-280: absent fieldstate remains
// an unwritten virtual-array slot on import.
None => Operand::None,
})
.collect();
ctx.set_ptr_info(
Expand Down Expand Up @@ -1372,14 +1391,23 @@ impl Optimizer {
fields
.iter()
.map(|(field_idx, field_info)| {
let r = Self::import_virtual_state_from_label_args_recurse(
field_info,
imported_label_args,
label_slot,
ctx,
walk_visited,
);
(*field_idx, ctx.materialize_operand_at(r))
let field = match field_info {
Some(field_info) => {
let field_ref =
Self::import_virtual_state_from_label_args_recurse(
field_info,
imported_label_args,
label_slot,
ctx,
walk_visited,
);
ctx.materialize_operand_at(field_ref)
}
// virtualstate.py:328-354: retain the
// dense unwritten element-field slot.
None => Operand::None,
};
(*field_idx, field)
})
.collect()
})
Expand Down Expand Up @@ -2505,6 +2533,17 @@ impl Optimizer {
// unbound terminal that fails `write_forwarded`'s bound-
// precondition assert.
ctx.bind_input_resops(ops);
// unroll.py:188 — the bridge iterator's fresh inputargs must enter
// optimization without forwarding. This is deliberately a
// debug-only invariant, matching the upstream assertion without
// adding release-build work.
debug_assert!(
!self.building_bridge
|| crate::optimizeopt::unroll::UnrollOptimizer::check_no_forwarding(
&ctx,
&ctx.inputargs,
)
);
// Phase 1 emit ops: single source of truth for cross-phase OpRef →
// `op.type_` lookup (history.py:220 parity).
ctx.phase1_emit_ops = std::mem::take(&mut self.phase1_emit_ops);
Expand Down
18 changes: 11 additions & 7 deletions majit/majit-metainterp/src/optimizeopt/unroll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,9 @@ fn callee_rca_virtual_state_summary(
}
crate::optimizeopt::virtualstate::VirtualStateInfo::VArray { items, .. } => {
for (idx, child) in items.iter().enumerate() {
walk(format!("{prefix}[{idx}]"), child, out, seen);
if let Some(child) = child {
walk(format!("{prefix}[{idx}]"), child, out, seen);
}
}
}
crate::optimizeopt::virtualstate::VirtualStateInfo::VArrayStruct {
Expand All @@ -141,12 +143,14 @@ fn callee_rca_virtual_state_summary(
} => {
for (elem_idx, fields) in element_fields.iter().enumerate() {
for (field_idx, child) in fields {
walk(
format!("{prefix}[{elem_idx}].{field_idx}"),
child,
out,
seen,
);
if let Some(child) = child {
walk(
format!("{prefix}[{elem_idx}].{field_idx}"),
child,
out,
seen,
);
}
}
}
}
Expand Down
Loading
Loading