Skip to content

Commit 1a6d38e

Browse files
committed
feat(jit): spec-driven family 5 6 array map mutations and iterators
1 parent 880c47d commit 1a6d38e

2 files changed

Lines changed: 118 additions & 138 deletions

File tree

src/vm/jit/builtin_spec.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,67 @@ pub(crate) const MAP_HAS_SPEC: BuiltinSpec = BuiltinSpec {
426426
needs_failure_exit: false,
427427
};
428428

429+
// ── Family 5: array/map mutations ───────────────────────────────────
430+
431+
/// `array.push(value)` — owned mutation, returns the mutated array.
432+
pub(crate) const ARRAY_PUSH_SPEC: BuiltinSpec = BuiltinSpec {
433+
name: "array_push",
434+
arity: 2,
435+
inputs: &[
436+
InputRepr::Any, // value (popped second)
437+
InputRepr::Tagged, // array (popped first, must be owned Tagged)
438+
],
439+
output: OutputKind::Tagged(ValueType::Array),
440+
effect: BuiltinEffect::OwnedMutation,
441+
needs_failure_exit: false,
442+
};
443+
444+
/// `map.set(key, value)` — owned mutation, returns the mutated map.
445+
pub(crate) const MAP_SET_SPEC: BuiltinSpec = BuiltinSpec {
446+
name: "map_set",
447+
arity: 3,
448+
inputs: &[
449+
InputRepr::Any, // value (popped third)
450+
InputRepr::Any, // key (popped second)
451+
InputRepr::Tagged, // map (popped first, must be owned Tagged)
452+
],
453+
output: OutputKind::Tagged(ValueType::Map),
454+
effect: BuiltinEffect::OwnedMutation,
455+
needs_failure_exit: false,
456+
};
457+
458+
// ── Family 6: map iterators ─────────────────────────────────────────
459+
460+
/// `map_iter_next(slot)` — advance iterator, bool result.
461+
pub(crate) const MAP_ITER_NEXT_SPEC: BuiltinSpec = BuiltinSpec {
462+
name: "map_iter_next",
463+
arity: 1,
464+
inputs: &[InputRepr::Int], // slot
465+
output: OutputKind::Bool,
466+
effect: BuiltinEffect::Pure,
467+
needs_failure_exit: false,
468+
};
469+
470+
/// `map_iter_take_key(slot)` — take current key, tagged result.
471+
pub(crate) const MAP_ITER_TAKE_KEY_SPEC: BuiltinSpec = BuiltinSpec {
472+
name: "map_iter_take_key",
473+
arity: 1,
474+
inputs: &[InputRepr::Int], // slot
475+
output: OutputKind::TaggedUnknown,
476+
effect: BuiltinEffect::Pure,
477+
needs_failure_exit: false,
478+
};
479+
480+
/// `map_iter_take_value(slot)` — take current value, tagged result.
481+
pub(crate) const MAP_ITER_TAKE_VALUE_SPEC: BuiltinSpec = BuiltinSpec {
482+
name: "map_iter_take_value",
483+
arity: 1,
484+
inputs: &[InputRepr::Int], // slot
485+
output: OutputKind::TaggedUnknown,
486+
effect: BuiltinEffect::Pure,
487+
needs_failure_exit: false,
488+
};
489+
429490
/// Look up the spec for a specialized builtin kind, if one exists.
430491
///
431492
/// Returns `None` for builtins not yet covered by the spec-driven
@@ -468,6 +529,13 @@ pub(crate) fn spec_for(
468529
super::recorder::SpecializedBuiltinKind::ArrayGet => Some(&ARRAY_GET_SPEC),
469530
super::recorder::SpecializedBuiltinKind::MapGet => Some(&MAP_GET_SPEC),
470531
super::recorder::SpecializedBuiltinKind::MapHas => Some(&MAP_HAS_SPEC),
532+
super::recorder::SpecializedBuiltinKind::ArrayPush => Some(&ARRAY_PUSH_SPEC),
533+
super::recorder::SpecializedBuiltinKind::MapSet => Some(&MAP_SET_SPEC),
534+
super::recorder::SpecializedBuiltinKind::MapIterNext => Some(&MAP_ITER_NEXT_SPEC),
535+
super::recorder::SpecializedBuiltinKind::MapIterTakeKey => Some(&MAP_ITER_TAKE_KEY_SPEC),
536+
super::recorder::SpecializedBuiltinKind::MapIterTakeValue => {
537+
Some(&MAP_ITER_TAKE_VALUE_SPEC)
538+
}
471539
_ => None,
472540
}
473541
}

src/vm/jit/recorder.rs

Lines changed: 50 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -3425,7 +3425,12 @@ fn analyze_specialized_builtin_call(
34253425
| SpecializedBuiltinKind::RegexReplace
34263426
| SpecializedBuiltinKind::ArrayGet
34273427
| SpecializedBuiltinKind::MapGet
3428-
| SpecializedBuiltinKind::MapHas => {
3428+
| SpecializedBuiltinKind::MapHas
3429+
| SpecializedBuiltinKind::ArrayPush
3430+
| SpecializedBuiltinKind::MapSet
3431+
| SpecializedBuiltinKind::MapIterNext
3432+
| SpecializedBuiltinKind::MapIterTakeKey
3433+
| SpecializedBuiltinKind::MapIterTakeValue => {
34293434
unreachable!("spec-covered builtins are handled by the spec-driven path")
34303435
}
34313436
SpecializedBuiltinKind::TypeOfKnown(_) => {
@@ -3460,34 +3465,6 @@ fn analyze_specialized_builtin_call(
34603465
frame.push(ValueInfo::tagged_typed(ValueType::Array));
34613466
Ok("array_new")
34623467
}
3463-
SpecializedBuiltinKind::ArrayPush => {
3464-
let _ = frame.pop()?;
3465-
let _ = frame.pop()?;
3466-
frame.push(ValueInfo::tagged_typed(ValueType::Array));
3467-
Ok("array_push")
3468-
}
3469-
SpecializedBuiltinKind::MapSet => {
3470-
let _ = frame.pop()?;
3471-
let _ = frame.pop()?;
3472-
let _ = frame.pop()?;
3473-
frame.push(ValueInfo::tagged_typed(ValueType::Map));
3474-
Ok("map_set")
3475-
}
3476-
SpecializedBuiltinKind::MapIterNext => {
3477-
let _ = frame.pop()?;
3478-
frame.push(ValueInfo::bool(None));
3479-
Ok("map_iter_next")
3480-
}
3481-
SpecializedBuiltinKind::MapIterTakeKey => {
3482-
let _ = frame.pop()?;
3483-
frame.push(ValueInfo::tagged());
3484-
Ok("map_iter_take_key")
3485-
}
3486-
SpecializedBuiltinKind::MapIterTakeValue => {
3487-
let _ = frame.pop()?;
3488-
frame.push(ValueInfo::tagged());
3489-
Ok("map_iter_take_value")
3490-
}
34913468
}
34923469
}
34933470

@@ -3528,7 +3505,12 @@ fn emit_specialized_builtin_call(
35283505
| SpecializedBuiltinKind::RegexReplace
35293506
| SpecializedBuiltinKind::ArrayGet
35303507
| SpecializedBuiltinKind::MapGet
3531-
| SpecializedBuiltinKind::MapHas => {
3508+
| SpecializedBuiltinKind::MapHas
3509+
| SpecializedBuiltinKind::ArrayPush
3510+
| SpecializedBuiltinKind::MapSet
3511+
| SpecializedBuiltinKind::MapIterNext
3512+
| SpecializedBuiltinKind::MapIterTakeKey
3513+
| SpecializedBuiltinKind::MapIterTakeValue => {
35323514
unreachable!("spec-covered builtins are handled by the spec-driven path")
35333515
}
35343516
SpecializedBuiltinKind::TypeOfKnown(value_type) => {
@@ -3580,114 +3562,6 @@ fn emit_specialized_builtin_call(
35803562
.map_err(|err| TraceRecordError::InvalidIr(err.to_string()))?;
35813563
Ok(("array_new", out))
35823564
}
3583-
SpecializedBuiltinKind::ArrayPush => {
3584-
let value = frame.pop()?;
3585-
let array = frame.pop()?;
3586-
if array.info.repr != SsaValueRepr::Tagged {
3587-
return Err(TraceRecordError::TypeMismatch {
3588-
expected: "owned tagged array",
3589-
actual: array.info.repr,
3590-
});
3591-
}
3592-
let out = builder
3593-
.append_value_inst(
3594-
block,
3595-
ip,
3596-
SsaValueRepr::Tagged,
3597-
SsaInstKind::ArrayPush {
3598-
array: array.value.id,
3599-
value: value.value.id,
3600-
},
3601-
)
3602-
.map(|value| SymbolicValue {
3603-
value,
3604-
info: ValueInfo::tagged_typed(ValueType::Array),
3605-
})
3606-
.map_err(|err| TraceRecordError::InvalidIr(err.to_string()))?;
3607-
Ok(("array_push", out))
3608-
}
3609-
SpecializedBuiltinKind::MapSet => {
3610-
let value = frame.pop()?;
3611-
let key = frame.pop()?;
3612-
let map = frame.pop()?;
3613-
if map.info.repr != SsaValueRepr::Tagged {
3614-
return Err(TraceRecordError::TypeMismatch {
3615-
expected: "owned tagged map",
3616-
actual: map.info.repr,
3617-
});
3618-
}
3619-
let out = builder
3620-
.append_value_inst(
3621-
block,
3622-
ip,
3623-
SsaValueRepr::Tagged,
3624-
SsaInstKind::MapSet {
3625-
map: map.value.id,
3626-
key: key.value.id,
3627-
value: value.value.id,
3628-
},
3629-
)
3630-
.map(|value| SymbolicValue {
3631-
value,
3632-
info: ValueInfo::tagged_typed(ValueType::Map),
3633-
})
3634-
.map_err(|err| TraceRecordError::InvalidIr(err.to_string()))?;
3635-
Ok(("map_set", out))
3636-
}
3637-
SpecializedBuiltinKind::MapIterNext => {
3638-
let slot = ensure_int(builder, block, ip, frame.pop()?)?;
3639-
let out = builder
3640-
.append_value_inst(
3641-
block,
3642-
ip,
3643-
SsaValueRepr::Bool,
3644-
SsaInstKind::MapIterNext {
3645-
slot: slot.value.id,
3646-
},
3647-
)
3648-
.map(|value| SymbolicValue {
3649-
value,
3650-
info: ValueInfo::bool(None),
3651-
})
3652-
.map_err(|err| TraceRecordError::InvalidIr(err.to_string()))?;
3653-
Ok(("map_iter_next", out))
3654-
}
3655-
SpecializedBuiltinKind::MapIterTakeKey => {
3656-
let slot = ensure_int(builder, block, ip, frame.pop()?)?;
3657-
let out = builder
3658-
.append_value_inst(
3659-
block,
3660-
ip,
3661-
SsaValueRepr::Tagged,
3662-
SsaInstKind::MapIterTakeKey {
3663-
slot: slot.value.id,
3664-
},
3665-
)
3666-
.map(|value| SymbolicValue {
3667-
value,
3668-
info: ValueInfo::tagged(),
3669-
})
3670-
.map_err(|err| TraceRecordError::InvalidIr(err.to_string()))?;
3671-
Ok(("map_iter_take_key", out))
3672-
}
3673-
SpecializedBuiltinKind::MapIterTakeValue => {
3674-
let slot = ensure_int(builder, block, ip, frame.pop()?)?;
3675-
let out = builder
3676-
.append_value_inst(
3677-
block,
3678-
ip,
3679-
SsaValueRepr::Tagged,
3680-
SsaInstKind::MapIterTakeValue {
3681-
slot: slot.value.id,
3682-
},
3683-
)
3684-
.map(|value| SymbolicValue {
3685-
value,
3686-
info: ValueInfo::tagged(),
3687-
})
3688-
.map_err(|err| TraceRecordError::InvalidIr(err.to_string()))?;
3689-
Ok(("map_iter_take_value", out))
3690-
}
36913565
}
36923566
}
36933567

@@ -3923,6 +3797,44 @@ fn emit_spec_driven_builtin(
39233797
ValueInfo::bool(None),
39243798
spec.name,
39253799
),
3800+
SpecializedBuiltinKind::ArrayPush => (
3801+
SsaInstKind::ArrayPush {
3802+
array: popped[1].value.id,
3803+
value: popped[0].value.id,
3804+
},
3805+
ValueInfo::tagged_typed(ValueType::Array),
3806+
spec.name,
3807+
),
3808+
SpecializedBuiltinKind::MapSet => (
3809+
SsaInstKind::MapSet {
3810+
map: popped[2].value.id,
3811+
key: popped[1].value.id,
3812+
value: popped[0].value.id,
3813+
},
3814+
ValueInfo::tagged_typed(ValueType::Map),
3815+
spec.name,
3816+
),
3817+
SpecializedBuiltinKind::MapIterNext => (
3818+
SsaInstKind::MapIterNext {
3819+
slot: popped[0].value.id,
3820+
},
3821+
ValueInfo::bool(None),
3822+
spec.name,
3823+
),
3824+
SpecializedBuiltinKind::MapIterTakeKey => (
3825+
SsaInstKind::MapIterTakeKey {
3826+
slot: popped[0].value.id,
3827+
},
3828+
ValueInfo::tagged(),
3829+
spec.name,
3830+
),
3831+
SpecializedBuiltinKind::MapIterTakeValue => (
3832+
SsaInstKind::MapIterTakeValue {
3833+
slot: popped[0].value.id,
3834+
},
3835+
ValueInfo::tagged(),
3836+
spec.name,
3837+
),
39263838
SpecializedBuiltinKind::ArraySet => {
39273839
let value = &popped[0];
39283840
let index = &popped[1];

0 commit comments

Comments
 (0)