make Fixnum::build_with harder to accidentally misuse

change trait bound order for better
This commit is contained in:
Bennet Bleßmann
2025-01-22 21:10:44 +01:00
committed by Mark Thom
parent 87ca083cfa
commit cbdd0fbf15
19 changed files with 422 additions and 223 deletions

View File

@@ -784,7 +784,9 @@ mod tests {
_ => { unreachable!() } _ => { unreachable!() }
); );
let fixnum_b_cell = fixnum_as_cell!(Fixnum::build_with(1 << 54)); let fixnum_b_cell = fixnum_as_cell!(
Fixnum::build_with_checked(1i64 << 54).expect("1 << 54 fits in Fixnum")
);
assert_eq!(fixnum_b_cell.get_tag(), HeapCellValueTag::Fixnum); assert_eq!(fixnum_b_cell.get_tag(), HeapCellValueTag::Fixnum);
@@ -793,41 +795,29 @@ mod tests {
None => unreachable!(), None => unreachable!(),
} }
if Fixnum::build_with_checked(1 << 56).is_ok() { Fixnum::build_with_checked(1i64 << 56).expect_err("1 << 56 is too large for fixnum");
unreachable!()
}
if Fixnum::build_with_checked(i64::MAX).is_ok() { Fixnum::build_with_checked(i64::MAX).expect_err("i64::MAX is too large for Fixnum");
unreachable!() Fixnum::build_with_checked(i64::MIN).expect_err("i64::MIN is too small for Fixnum");
} assert_eq!(
Fixnum::build_with_checked(-1i64)
.expect("-1 fits in fixnum")
.get_num(),
-1
);
if Fixnum::build_with_checked(i64::MIN).is_ok() { Fixnum::build_with_checked((1i64 << 55) - 1)
unreachable!() .expect("(1 << 55) - 1 is the largest value that fits in Fixnum");
}
match Fixnum::build_with_checked(-1) { Fixnum::build_with_checked(-(1i64 << 55))
Ok(n) => assert_eq!(n.get_num(), -1), .expect("-(1 << 55) is the smallest value that fits in fixnum");
_ => unreachable!(), Fixnum::build_with_checked(-(1i64 << 55) - 1)
} .expect_err("-(1<<55) - 1 is too small for Fixnum");
match Fixnum::build_with_checked((1 << 55) - 1) { assert_eq!(
Ok(n) => assert_eq!(n.get_num(), (1 << 55) - 1), -Fixnum::build_with_checked(-1i64).expect("-1 fits in Fixnum"),
_ => unreachable!(), Fixnum::build_with(1)
} );
match Fixnum::build_with_checked(-(1 << 55)) {
Ok(n) => assert_eq!(n.get_num(), -(1 << 55)),
_ => unreachable!(),
}
if Fixnum::build_with_checked(-(1 << 55) - 1).is_ok() {
unreachable!()
}
match Fixnum::build_with_checked(-1) {
Ok(n) => assert_eq!(-n, Fixnum::build_with(1)),
_ => unreachable!(),
}
// float // float

View File

@@ -358,9 +358,8 @@ impl<'a> ArithmeticEvaluator<'a> {
pub(crate) fn rnd_i(n: &'_ Number, arena: &mut Arena) -> Result<Number, EvalError> { pub(crate) fn rnd_i(n: &'_ Number, arena: &mut Arena) -> Result<Number, EvalError> {
match n { match n {
&Number::Integer(i) => { &Number::Integer(i) => {
let result = (&*i).try_into(); if let Ok(value) = Fixnum::build_with_checked(&*i) {
if let Ok(value) = result { Ok(Number::Fixnum(value))
Ok(fixnum!(Number, value, arena))
} else { } else {
Ok(*n) Ok(*n)
} }
@@ -369,11 +368,14 @@ pub(crate) fn rnd_i(n: &'_ Number, arena: &mut Arena) -> Result<Number, EvalErro
&Number::Float(f) => { &Number::Float(f) => {
let f = f.floor(); let f = f.floor();
const I64_MIN_TO_F: OrderedFloat<f64> = OrderedFloat(i64::MIN as f64); const FIXNUM_MIN_TO_F: OrderedFloat<f64> = OrderedFloat(Fixnum::MIN as f64);
const I64_MAX_TO_F: OrderedFloat<f64> = OrderedFloat(i64::MAX as f64); const FIXNUM_MAX_TO_F: OrderedFloat<f64> = OrderedFloat(Fixnum::MAX as f64);
if I64_MIN_TO_F <= f && f <= I64_MAX_TO_F { if (FIXNUM_MIN_TO_F..=FIXNUM_MAX_TO_F).contains(&f) {
Ok(fixnum!(Number, f.into_inner() as i64, arena)) Ok(Number::Fixnum(
// Safety: We checked that the value is in range
unsafe { Fixnum::build_with_unchecked(f.into_inner() as i64) },
))
} else { } else {
Ok(Number::Integer(arena_alloc!( Ok(Number::Integer(arena_alloc!(
Integer::try_from(classify_float(f.0)?).unwrap_or_else(|_| { Integer::try_from(classify_float(f.0)?).unwrap_or_else(|_| {
@@ -386,8 +388,8 @@ pub(crate) fn rnd_i(n: &'_ Number, arena: &mut Arena) -> Result<Number, EvalErro
Number::Rational(ref r) => { Number::Rational(ref r) => {
let floor = r.floor(); let floor = r.floor();
if let Ok(value) = (&floor).try_into() { if let Ok(value) = Fixnum::build_with_checked(&floor) {
Ok(fixnum!(Number, value, arena)) Ok(Number::Fixnum(value))
} else { } else {
Ok(Number::Integer(arena_alloc!(floor, arena))) Ok(Number::Integer(arena_alloc!(floor, arena)))
} }

View File

@@ -697,14 +697,14 @@ impl ArenaFrom<isize> for Number {
impl ArenaFrom<u32> for Number { impl ArenaFrom<u32> for Number {
#[inline] #[inline]
fn arena_from(value: u32, _arena: &mut Arena) -> Number { fn arena_from(value: u32, _arena: &mut Arena) -> Number {
Number::Fixnum(Fixnum::build_with(value as i64)) Number::Fixnum(Fixnum::build_with(value))
} }
} }
impl ArenaFrom<i32> for Number { impl ArenaFrom<i32> for Number {
#[inline] #[inline]
fn arena_from(value: i32, _arena: &mut Arena) -> Number { fn arena_from(value: i32, _arena: &mut Arena) -> Number {
Number::Fixnum(Fixnum::build_with(value as i64)) Number::Fixnum(Fixnum::build_with(value))
} }
} }

View File

@@ -78,7 +78,7 @@ macro_rules! build_functor {
$res_len:expr, $res_len:expr,
[$($subfunctor:expr),*]) => ({ [$($subfunctor:expr),*]) => ({
build_functor!([$($dt($($value),*)),*], build_functor!([$($dt($($value),*)),*],
[$($res, )* FunctorElement::Cell(fixnum_as_cell!(Fixnum::build_with($e as i64)))], [$($res, )* FunctorElement::Cell(fixnum_as_cell!(/*FIXME this is not safe*/ unsafe{Fixnum::build_with_unchecked($e as i64)}))],
1 + $res_len, 1 + $res_len,
[$($subfunctor),*]) [$($subfunctor),*])
}); });

View File

@@ -1500,7 +1500,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.state_stack.push(TokenOrRedirect::NumberFocus( self.state_stack.push(TokenOrRedirect::NumberFocus(
max_depth, max_depth,
NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(port as i64))), NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(port))),
None, None,
)); ));
self.state_stack.push(TokenOrRedirect::Comma); self.state_stack.push(TokenOrRedirect::Comma);
@@ -1527,7 +1527,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
TokenOrRedirect::NumberFocus( TokenOrRedirect::NumberFocus(
max_depth, max_depth,
NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(idx_ptr_p))), NumberFocus::Unfocused(Number::Fixnum(
/* FIXME this is not safe */
unsafe { Fixnum::build_with_unchecked(idx_ptr_p) },
)),
None, None,
) )
}; };

View File

@@ -1104,11 +1104,7 @@ pub(crate) fn constant_key_alternatives(constant: Literal) -> Option<Literal> {
_ => return None, _ => return None,
}; };
if let Ok(n) = n.try_into() { Fixnum::build_with_checked(n).map(Literal::Fixnum).ok()
Fixnum::build_with_checked(n).map(Literal::Fixnum).ok()
} else {
None
}
} }
#[derive(Debug)] #[derive(Debug)]

View File

@@ -198,11 +198,10 @@ pub(crate) fn neg(n: Number, arena: &mut Arena) -> Number {
pub(crate) fn abs(n: Number, arena: &mut Arena) -> Number { pub(crate) fn abs(n: Number, arena: &mut Arena) -> Number {
match n { match n {
Number::Fixnum(n) => { Number::Fixnum(n) => {
if let Some(n) = n.get_num().checked_abs() { if let Some(n) = n.checked_abs() {
fixnum!(Number, n, arena) Number::Fixnum(n)
} else { } else {
let arena_int = Integer::from(n.get_num()); Number::arena_from(Integer::from(Fixnum::MAX + 1), arena)
Number::arena_from(arena_int.abs(), arena)
} }
} }
Number::Integer(n) => { Number::Integer(n) => {
@@ -1105,7 +1104,7 @@ pub(crate) fn round(num: Number, arena: &mut Arena) -> Result<Number, MachineStu
pub(crate) fn bitwise_complement(n1: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> { pub(crate) fn bitwise_complement(n1: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
match n1 { match n1 {
Number::Fixnum(n) => Ok(Number::Fixnum(Fixnum::build_with(!n.get_num()))), Number::Fixnum(n) => Ok(Number::Fixnum(!n)),
Number::Integer(n1) => Ok(Number::arena_from(Integer::from(!&*n1), arena)), Number::Integer(n1) => Ok(Number::arena_from(Integer::from(!&*n1), arena)),
_ => { _ => {
let stub_gen = || { let stub_gen = || {

View File

@@ -120,9 +120,21 @@ impl MachineState {
and_frame[i] = self.registers[i]; and_frame[i] = self.registers[i];
} }
and_frame[arity + 1] = fixnum_as_cell!(Fixnum::build_with(self.b0 as i64)); and_frame[arity + 1] =
and_frame[arity + 2] = fixnum_as_cell!(Fixnum::build_with(self.num_of_args as i64)); fixnum_as_cell!(
and_frame[arity + 3] = fixnum_as_cell!(Fixnum::build_with(self.attr_var_init.cp as i64)); /* FIXME this is not safe */
unsafe { Fixnum::build_with_unchecked(self.b0 as i64) }
);
and_frame[arity + 2] =
fixnum_as_cell!(
/* FIXME this is not safe */
unsafe { Fixnum::build_with_unchecked(self.num_of_args as i64) }
);
and_frame[arity + 3] =
fixnum_as_cell!(
/* FIXME this is not safe */
unsafe { Fixnum::build_with_unchecked(self.attr_var_init.cp as i64) }
);
self.verify_attributes()?; self.verify_attributes()?;

View File

@@ -1021,9 +1021,13 @@ impl Machine {
match self.find_living_dynamic_else(p + next_i) { match self.find_living_dynamic_else(p + next_i) {
Some(_) => { Some(_) => {
self.machine_st.registers self.machine_st.registers
[self.machine_st.num_of_args + 1] = fixnum_as_cell!( [self.machine_st.num_of_args + 1] =
Fixnum::build_with(self.machine_st.cc as i64) fixnum_as_cell!(unsafe {
); /* FIXME this is not safe */
Fixnum::build_with_unchecked(
self.machine_st.cc as i64,
)
});
self.machine_st.num_of_args += 1; self.machine_st.num_of_args += 1;
self.try_me_else(next_i); self.try_me_else(next_i);
@@ -1042,10 +1046,11 @@ impl Machine {
.prelude .prelude
.num_cells; .num_cells;
self.machine_st.cc = cell_as_fixnum!( self.machine_st.cc = unsafe {
self.machine_st.stack self.machine_st.stack
[stack_loc!(OrFrame, self.machine_st.b, n - 1)] [stack_loc!(OrFrame, self.machine_st.b, n - 1)]
) .to_fixnum_or_cut_point_unchecked()
}
.get_num() .get_num()
as usize; as usize;
@@ -1095,7 +1100,12 @@ impl Machine {
Some(_) => { Some(_) => {
self.machine_st.registers self.machine_st.registers
[self.machine_st.num_of_args + 1] = fixnum_as_cell!( [self.machine_st.num_of_args + 1] = fixnum_as_cell!(
Fixnum::build_with(self.machine_st.cc as i64) /* FIXME this is not safe */
unsafe {
Fixnum::build_with_unchecked(
self.machine_st.cc as i64,
)
}
); );
self.machine_st.num_of_args += 1; self.machine_st.num_of_args += 1;
@@ -1115,10 +1125,11 @@ impl Machine {
.prelude .prelude
.num_cells; .num_cells;
self.machine_st.cc = cell_as_fixnum!( self.machine_st.cc = unsafe {
self.machine_st.stack self.machine_st.stack
[stack_loc!(OrFrame, self.machine_st.b, n - 1)] [stack_loc!(OrFrame, self.machine_st.b, n - 1)]
) .to_fixnum_or_cut_point_unchecked()
}
.get_num() .get_num()
as usize; as usize;
@@ -1174,7 +1185,10 @@ impl Machine {
&Instruction::GetLevel(r) => { &Instruction::GetLevel(r) => {
let b0 = self.machine_st.b0; let b0 = self.machine_st.b0;
self.machine_st[r] = fixnum_as_cell!(Fixnum::as_cutpoint(b0 as i64)); self.machine_st[r] = fixnum_as_cell!(
/* FIXME this is not safe */
unsafe { Fixnum::build_with_unchecked(b0 as i64) }.as_cutpoint()
);
self.machine_st.p += 1; self.machine_st.p += 1;
} }
&Instruction::GetPrevLevel(r) => { &Instruction::GetPrevLevel(r) => {
@@ -1185,12 +1199,18 @@ impl Machine {
.prelude .prelude
.b; .b;
self.machine_st[r] = fixnum_as_cell!(Fixnum::as_cutpoint(prev_b as i64)); self.machine_st[r] = fixnum_as_cell!(
/* FIXME this is not safe */
unsafe { Fixnum::build_with_unchecked(prev_b as i64) }.as_cutpoint()
);
self.machine_st.p += 1; self.machine_st.p += 1;
} }
&Instruction::GetCutPoint(r) => { &Instruction::GetCutPoint(r) => {
self.machine_st[r] = self.machine_st[r] =
fixnum_as_cell!(Fixnum::as_cutpoint(self.machine_st.b as i64)); fixnum_as_cell!(/* FIXME this is not safe */ unsafe {
Fixnum::build_with_unchecked(self.machine_st.b as i64)
}
.as_cutpoint());
self.machine_st.p += 1; self.machine_st.p += 1;
} }
&Instruction::Cut(r) => { &Instruction::Cut(r) => {
@@ -3150,10 +3170,14 @@ impl Machine {
match self.find_living_dynamic(oi, ii + 1) { match self.find_living_dynamic(oi, ii + 1) {
Some(_) => { Some(_) => {
self.machine_st.registers self.machine_st.registers
[self.machine_st.num_of_args + 1] = [self.machine_st.num_of_args + 1] = fixnum_as_cell!(
fixnum_as_cell!(Fixnum::build_with( /* FIXME this is not safe */
self.machine_st.cc as i64 unsafe {
)); Fixnum::build_with_unchecked(
self.machine_st.cc as i64,
)
}
);
self.machine_st.num_of_args += 1; self.machine_st.num_of_args += 1;
self.indexed_try(offset); self.indexed_try(offset);
@@ -3175,10 +3199,11 @@ impl Machine {
.prelude .prelude
.num_cells; .num_cells;
self.machine_st.cc = cell_as_fixnum!( self.machine_st.cc = unsafe {
self.machine_st.stack self.machine_st.stack
[stack_loc!(OrFrame, b, n - 1)] [stack_loc!(OrFrame, b, n - 1)]
) .to_fixnum_or_cut_point_unchecked()
}
.get_num() .get_num()
as usize; as usize;
@@ -5256,8 +5281,11 @@ impl Machine {
.machine_st .machine_st
.store(self.machine_st.deref(self.machine_st.registers[5])); .store(self.machine_st.deref(self.machine_st.registers[5]));
self.machine_st self.machine_st.unify_fixnum(
.unify_fixnum(Fixnum::build_with(n as i64), r); /* FIXME this is not safe */
unsafe { Fixnum::build_with_unchecked(n as i64) },
r,
);
} }
self.machine_st.call_at_index(2, p); self.machine_st.call_at_index(2, p);
@@ -5299,8 +5327,11 @@ impl Machine {
.machine_st .machine_st
.store(self.machine_st.deref(self.machine_st.registers[5])); .store(self.machine_st.deref(self.machine_st.registers[5]));
self.machine_st self.machine_st.unify_fixnum(
.unify_fixnum(Fixnum::build_with(n as i64), r); /* FIXME this is not safe */
unsafe { Fixnum::build_with_unchecked(n as i64) },
r,
);
} }
self.machine_st.execute_at_index(2, p); self.machine_st.execute_at_index(2, p);

View File

@@ -2344,7 +2344,9 @@ impl Machine {
MetaSpec::Either => atom_as_cell!(atom!("?")), MetaSpec::Either => atom_as_cell!(atom!("?")),
MetaSpec::Colon => atom_as_cell!(atom!(":")), MetaSpec::Colon => atom_as_cell!(atom!(":")),
MetaSpec::RequiresExpansionWithArgument(ref arg_num) => { MetaSpec::RequiresExpansionWithArgument(ref arg_num) => {
fixnum_as_cell!(Fixnum::build_with(*arg_num as i64)) fixnum_as_cell!(/* FIXME this is not safe */ unsafe {
Fixnum::build_with_unchecked(*arg_num as i64)
})
} }
}); });
} }

View File

@@ -1003,7 +1003,10 @@ impl MachineState {
arity: HeapCellValue, arity: HeapCellValue,
) -> (Atom, usize) { ) -> (Atom, usize) {
let name = cell_as_atom!(self.store(self.deref(name))); let name = cell_as_atom!(self.store(self.deref(name)));
let arity = cell_as_fixnum!(self.store(self.deref(arity))); let arity = unsafe {
self.store(self.deref(arity))
.to_fixnum_or_cut_point_unchecked()
};
(name, usize::try_from(arity.get_num()).unwrap()) (name, usize::try_from(arity.get_num()).unwrap())
} }

View File

@@ -940,7 +940,7 @@ impl MachineState {
/* /*
if pstr_atom.len() > offset as usize { if pstr_atom.len() > offset as usize {
self.heap.push(pstr_offset_as_cell!(h)); self.heap.push(pstr_offset_as_cell!(h));
self.heap.push(fixnum_as_cell!(Fixnum::build_with(offset))); self.heap.push(fixnum_as_cell!(Fixnum::build_with_unchecked(offset as i64)));
unify_fn!(*self, pstr_loc_as_cell!(h_len), a3); unify_fn!(*self, pstr_loc_as_cell!(h_len), a3);
} else { } else {
@@ -973,13 +973,13 @@ impl MachineState {
if n == 1 { if n == 1 {
self.unify_char(c, self.store(self.deref(self.registers[3]))); self.unify_char(c, self.store(self.deref(self.registers[3])));
} else if n == 2 { } else if n == 2 {
let offset = c.len_utf8() as i64; let offset = c.len_utf8();
let h_len = self.heap.len(); let h_len = self.heap.len();
if cstr_atom.len() > offset as usize { if cstr_atom.len() > offset{
self.heap.push(atom_as_cstr_cell!(cstr_atom)); self.heap.push(atom_as_cstr_cell!(cstr_atom));
self.heap.push(pstr_offset_as_cell!(h_len)); self.heap.push(pstr_offset_as_cell!(h_len));
self.heap.push(fixnum_as_cell!(Fixnum::build_with(offset))); self.heap.push(fixnum_as_cell!(Fixnum::build_with_unchecked(offset as i64)));
unify_fn!(*self, pstr_loc_as_cell!(h_len+1), self.registers[3]); unify_fn!(*self, pstr_loc_as_cell!(h_len+1), self.registers[3]);
} else { } else {
@@ -1027,7 +1027,11 @@ impl MachineState {
if !self.fail { if !self.fail {
let a3 = self.store(self.deref(self.registers[3])); let a3 = self.store(self.deref(self.registers[3]));
self.unify_fixnum(Fixnum::build_with(arity as i64), a3); self.unify_fixnum(
/* FIXME this is not safe */
unsafe { Fixnum::build_with_unchecked(arity as i64) },
a3,
);
} }
} }

View File

@@ -1161,8 +1161,10 @@ impl Machine {
let (idx, arity) = if self.machine_st.effective_block() > prev_block { let (idx, arity) = if self.machine_st.effective_block() > prev_block {
(r_c_w_h, 0) (r_c_w_h, 0)
} else { } else {
self.machine_st.registers[1] = self.machine_st.registers[1] = fixnum_as_cell!(
fixnum_as_cell!(Fixnum::build_with(b_cutoff as i64)); /* FIXME this is not safe */
unsafe { Fixnum::build_with_unchecked(b_cutoff as i64) }
);
(r_c_wo_h, 1) (r_c_wo_h, 1)
}; };

View File

@@ -578,9 +578,11 @@ impl MachineState {
while lh_offset + 4 < self.lifted_heap.cell_len() { while lh_offset + 4 < self.lifted_heap.cell_len() {
let cell_threshold = let cell_threshold =
cell_as_fixnum!(self.lifted_heap[lh_offset + 3]).get_num() as usize; unsafe { self.lifted_heap[lh_offset + 3].to_fixnum_or_cut_point_unchecked() }
.get_num() as usize;
let pstr_upper_threshold = let pstr_upper_threshold =
cell_as_fixnum!(self.lifted_heap[lh_offset + 4]).get_num() as usize; unsafe { self.lifted_heap[lh_offset + 4].to_fixnum_or_cut_point_unchecked() }
.get_num() as usize;
for idx in lh_offset..cell_threshold { for idx in lh_offset..cell_threshold {
section.push_cell(self.lifted_heap[idx] + offset); section.push_cell(self.lifted_heap[idx] + offset);
@@ -740,7 +742,11 @@ impl MachineState {
// self.heap.pop_cell(); // self.heap.pop_cell();
let target_n = self.store(self.deref(self.registers[1])); let target_n = self.store(self.deref(self.registers[1]));
self.unify_fixnum(Fixnum::build_with(brent_st.num_steps() as i64), target_n); self.unify_fixnum(
/* FIXME this is not safe */
unsafe { Fixnum::build_with_unchecked(brent_st.num_steps() as i64) },
target_n,
);
if !self.fail { if !self.fail {
unify!(self, self.registers[4], self.heap[prev_hare]); unify!(self, self.registers[4], self.heap[prev_hare]);
@@ -749,7 +755,10 @@ impl MachineState {
fn finalize_skip_max_list(&mut self, n: i64, value: HeapCellValue) { fn finalize_skip_max_list(&mut self, n: i64, value: HeapCellValue) {
let target_n = self.store(self.deref(self.registers[1])); let target_n = self.store(self.deref(self.registers[1]));
self.unify_fixnum(Fixnum::build_with(n), target_n); self.unify_fixnum(
/* FIXME this is not safe */ unsafe { Fixnum::build_with_unchecked(n) },
target_n,
);
if !self.fail { if !self.fail {
let xs = self.registers[4]; let xs = self.registers[4];
@@ -881,7 +890,11 @@ impl MachineState {
let value = self.store(self.deref(value)); let value = self.store(self.deref(value));
self.block = self.b; self.block = self.b;
self.unify_fixnum(Fixnum::build_with(self.block as i64), value); self.unify_fixnum(
/* FIXME this is not safe */
unsafe { Fixnum::build_with_unchecked(self.block as i64) },
value,
);
self.block self.block
} }
@@ -959,7 +972,7 @@ impl MachineState {
let mut tokens = vec![]; let mut tokens = vec![];
match lexer.next_number_token() { match lexer.next_number_token() {
Ok(token @ Token::Literal(Literal::Atom(atom!("-")) | Literal::Char('-'))) => { Ok(token @ Token::Literal(Literal::Atom(atom!("-")))) => {
tokens.push(token); tokens.push(token);
if let Ok(token) = lexer.next_number_token() { if let Ok(token) = lexer.next_number_token() {
@@ -1051,7 +1064,10 @@ impl MachineState {
for index in s + 2..s + 2 + num_cells { for index in s + 2..s + 2 + num_cells {
if let HeapCellValueTag::CutPoint = self.heap[index].get_tag() { if let HeapCellValueTag::CutPoint = self.heap[index].get_tag() {
// adjust cut point to occur after call_continuation. // adjust cut point to occur after call_continuation.
and_frame[index - (s + 1)] = fixnum_as_cell!(Fixnum::as_cutpoint(self.b as i64)); and_frame[index - (s + 1)] = fixnum_as_cell!(
/* FIXME this is not safe */
unsafe { Fixnum::build_with_unchecked(self.b as i64) }.as_cutpoint()
);
} else { } else {
and_frame[index - (s + 1)] = self.heap[index]; and_frame[index - (s + 1)] = self.heap[index];
} }
@@ -2332,7 +2348,7 @@ impl Machine {
(HeapCellValueTag::Char, c) => { (HeapCellValueTag::Char, c) => {
let h = self.machine_st.heap.len(); let h = self.machine_st.heap.len();
self.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(c as i64))); self.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(u32::from(c))));
self.machine_st.heap.push(empty_list_as_cell!()); self.machine_st.heap.push(empty_list_as_cell!());
unify!(self.machine_st, list_loc_as_cell!(h), self.machine_st.registers[2]); unify!(self.machine_st, list_loc_as_cell!(h), self.machine_st.registers[2]);
@@ -2342,7 +2358,7 @@ impl Machine {
debug_assert_eq!(arity, 0); debug_assert_eq!(arity, 0);
let name = name.as_str(); let name = name.as_str();
let iter = name.chars().map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64))); let iter = name.chars().map(|c| fixnum_as_cell!(Fixnum::build_with(c)));
let list_cell = resource_error_call_result!( let list_cell = resource_error_call_result!(
self.machine_st, self.machine_st,
@@ -2439,7 +2455,10 @@ impl Machine {
); );
let a2 = self.deref_register(2); let a2 = self.deref_register(2);
self.machine_st.unify_fixnum(Fixnum::build_with(len), a2); self.machine_st.unify_fixnum(
/* FIXME this is not safe */ unsafe { Fixnum::build_with_unchecked(len) },
a2,
);
} }
#[inline(always)] #[inline(always)]
@@ -2593,7 +2612,7 @@ impl Machine {
Ok(Number::Integer(n)) => { Ok(Number::Integer(n)) => {
let result: Result<u8, _> = (&*n).try_into(); let result: Result<u8, _> = (&*n).try_into();
if let Ok(value) = result { if let Ok(value) = result {
fixnum_as_cell!(Fixnum::build_with(value as i64)) fixnum_as_cell!(Fixnum::build_with(value))
} else { } else {
let err = self.machine_st.type_error(ValidType::InByte, addr); let err = self.machine_st.type_error(ValidType::InByte, addr);
return Err(self.machine_st.error_form(err, stub_gen())); return Err(self.machine_st.error_form(err, stub_gen()));
@@ -2601,7 +2620,7 @@ impl Machine {
} }
Ok(Number::Fixnum(n)) => { Ok(Number::Fixnum(n)) => {
if let Ok(nb) = u8::try_from(n.get_num()) { if let Ok(nb) = u8::try_from(n.get_num()) {
fixnum_as_cell!(Fixnum::build_with(nb as i64)) fixnum_as_cell!(Fixnum::build_with(nb))
} else { } else {
let err = self.machine_st.type_error(ValidType::InByte, addr); let err = self.machine_st.type_error(ValidType::InByte, addr);
return Err(self.machine_st.error_form(err, stub_gen())); return Err(self.machine_st.error_form(err, stub_gen()));
@@ -2617,8 +2636,7 @@ impl Machine {
loop { loop {
match stream.peek_byte().map_err(|e| e.kind()) { match stream.peek_byte().map_err(|e| e.kind()) {
Ok(b) => { Ok(b) => {
self.machine_st self.machine_st.unify_fixnum(Fixnum::build_with(b), addr);
.unify_fixnum(Fixnum::build_with(b as i64), addr);
break; break;
} }
Err(ErrorKind::PermissionDenied) => { Err(ErrorKind::PermissionDenied) => {
@@ -2783,10 +2801,8 @@ impl Machine {
Ok(Number::Integer(n)) => { Ok(Number::Integer(n)) => {
let n: u32 = (&*n).try_into().unwrap(); let n: u32 = (&*n).try_into().unwrap();
let n = std::char::from_u32(n).map(|_| n); if std::char::from_u32(n).is_some() {
fixnum_as_cell!(Fixnum::build_with(n))
if let Some(n) = n {
fixnum_as_cell!(Fixnum::build_with(n as i64))
} else { } else {
let err = self.machine_st.representation_error(RepFlag::InCharacterCode); let err = self.machine_st.representation_error(RepFlag::InCharacterCode);
return Err(self.machine_st.error_form(err, stub_gen())); return Err(self.machine_st.error_form(err, stub_gen()));
@@ -2798,7 +2814,7 @@ impl Machine {
.and_then(|n| std::char::from_u32(n).map(|_| n)); .and_then(|n| std::char::from_u32(n).map(|_| n));
if let Some(n) = n { if let Some(n) = n {
fixnum_as_cell!(Fixnum::build_with(n as i64)) fixnum_as_cell!(Fixnum::build_with(n))
} else { } else {
let err = self.machine_st.representation_error(RepFlag::InCharacterCode); let err = self.machine_st.representation_error(RepFlag::InCharacterCode);
return Err(self.machine_st.error_form(err, stub_gen())); return Err(self.machine_st.error_form(err, stub_gen()));
@@ -2818,7 +2834,7 @@ impl Machine {
match result.map(|result| result.map_err(|e| e.kind())) { match result.map(|result| result.map_err(|e| e.kind())) {
Some(Ok(c)) => { Some(Ok(c)) => {
self.machine_st self.machine_st
.unify_fixnum(Fixnum::build_with(c as i64), addr); .unify_fixnum(Fixnum::build_with(u32::from(c)), addr);
break; break;
} }
Some(Err(ErrorKind::PermissionDenied)) => { Some(Err(ErrorKind::PermissionDenied)) => {
@@ -2896,7 +2912,7 @@ impl Machine {
let codes = string let codes = string
.trim() .trim()
.chars() .chars()
.map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64))); .map(|c| fixnum_as_cell!(Fixnum::build_with(u32::from(c))));
let list_cell = step_or_resource_error!( let list_cell = step_or_resource_error!(
self.machine_st, self.machine_st,
@@ -2939,7 +2955,9 @@ impl Machine {
#[inline(always)] #[inline(always)]
pub(crate) fn lifted_heap_length(&mut self) { pub(crate) fn lifted_heap_length(&mut self) {
let a1 = self.machine_st.registers[1]; let a1 = self.machine_st.registers[1];
let lh_len = Fixnum::build_with(self.machine_st.lifted_heap.cell_len() as i64); /* FIXME this is not safe */
let lh_len =
unsafe { Fixnum::build_with_unchecked(self.machine_st.lifted_heap.cell_len() as i64) };
self.machine_st.unify_fixnum(lh_len, a1); self.machine_st.unify_fixnum(lh_len, a1);
} }
@@ -3002,7 +3020,7 @@ impl Machine {
); );
self.machine_st self.machine_st
.unify_fixnum(Fixnum::build_with(c as i64), a2); .unify_fixnum(Fixnum::build_with(u32::from(c)), a2);
Ok(()) Ok(())
} }
@@ -3132,7 +3150,7 @@ impl Machine {
#[inline(always)] #[inline(always)]
pub(crate) fn check_cut_point(&mut self) { pub(crate) fn check_cut_point(&mut self) {
let addr = self.deref_register(1); let addr = self.deref_register(1);
let old_b = cell_as_fixnum!(addr).get_num() as usize; let old_b = unsafe { addr.to_fixnum_or_cut_point_unchecked() }.get_num() as usize;
let prev_b = self let prev_b = self
.machine_st .machine_st
@@ -3442,7 +3460,7 @@ impl Machine {
let n: Result<u8, _> = (&*n).try_into(); let n: Result<u8, _> = (&*n).try_into();
if let Ok(value) = n { if let Ok(value) = n {
fixnum_as_cell!(Fixnum::build_with(value as i64)) fixnum_as_cell!(Fixnum::build_with(value))
} else { } else {
let err = self.machine_st.type_error(ValidType::InByte, addr); let err = self.machine_st.type_error(ValidType::InByte, addr);
return Err(self.machine_st.error_form(err, stub_gen())); return Err(self.machine_st.error_form(err, stub_gen()));
@@ -3450,7 +3468,7 @@ impl Machine {
} }
Ok(Number::Fixnum(n)) => { Ok(Number::Fixnum(n)) => {
if let Ok(nb) = u8::try_from(n.get_num()) { if let Ok(nb) = u8::try_from(n.get_num()) {
fixnum_as_cell!(Fixnum::build_with(nb as i64)) fixnum_as_cell!(Fixnum::build_with(nb))
} else { } else {
let err = self.machine_st.type_error(ValidType::InByte, addr); let err = self.machine_st.type_error(ValidType::InByte, addr);
return Err(self.machine_st.error_form(err, stub_gen())); return Err(self.machine_st.error_form(err, stub_gen()));
@@ -3467,8 +3485,7 @@ impl Machine {
match stream.read(&mut b) { match stream.read(&mut b) {
Ok(1) => { Ok(1) => {
self.machine_st self.machine_st.unify_fixnum(Fixnum::build_with(b[0]), addr);
.unify_fixnum(Fixnum::build_with(b[0] as i64), addr);
} }
_ => { _ => {
stream.set_past_end_of_stream(true); stream.set_past_end_of_stream(true);
@@ -3693,7 +3710,7 @@ impl Machine {
let n = std::char::from_u32(n); let n = std::char::from_u32(n);
if let Some(n) = n { if let Some(n) = n {
fixnum_as_cell!(Fixnum::build_with(n as i64)) fixnum_as_cell!(Fixnum::build_with(u32::from(n)))
} else { } else {
let err = self let err = self
.machine_st .machine_st
@@ -3737,7 +3754,7 @@ impl Machine {
match result { match result {
Some(Ok(c)) => { Some(Ok(c)) => {
self.machine_st self.machine_st
.unify_fixnum(Fixnum::build_with(c as i64), addr); .unify_fixnum(Fixnum::build_with(u32::from(c)), addr);
break; break;
} }
_ => { _ => {
@@ -3916,7 +3933,8 @@ impl Machine {
#[inline(always)] #[inline(always)]
pub(crate) fn copy_to_lifted_heap(&mut self) { pub(crate) fn copy_to_lifted_heap(&mut self) {
let lh_offset = cell_as_fixnum!(self.deref_register(1)).get_num() as usize; let lh_offset =
unsafe { self.deref_register(1).to_fixnum_or_cut_point_unchecked() }.get_num() as usize;
let copy_target = self.machine_st.registers[2]; let copy_target = self.machine_st.registers[2];
let FindallCopyInfo { let FindallCopyInfo {
offset: old_threshold, offset: old_threshold,
@@ -3935,11 +3953,14 @@ impl Machine {
self.machine_st.lifted_heap[idx] -= self.machine_st.heap.cell_len() + lh_offset; self.machine_st.lifted_heap[idx] -= self.machine_st.heap.cell_len() + lh_offset;
} }
self.machine_st.lifted_heap[old_threshold + 1] = self.machine_st.lifted_heap[old_threshold + 1] = fixnum_as_cell!(
fixnum_as_cell!(Fixnum::build_with(pstr_threshold as i64)); /* FIXME this is not safe */
self.machine_st.lifted_heap[old_threshold + 2] = fixnum_as_cell!(Fixnum::build_with( unsafe { Fixnum::build_with_unchecked(pstr_threshold as i64) }
self.machine_st.lifted_heap.cell_len() as i64 );
)); self.machine_st.lifted_heap[old_threshold + 2] =
fixnum_as_cell!(/* FIXME this is not safe */ unsafe {
Fixnum::build_with_unchecked(self.machine_st.lifted_heap.cell_len() as i64)
});
let mut pstr_threshold = heap_index!(pstr_threshold); let mut pstr_threshold = heap_index!(pstr_threshold);
@@ -3958,7 +3979,8 @@ impl Machine {
pub(crate) fn lookup_db_ref(&mut self) { pub(crate) fn lookup_db_ref(&mut self) {
let module_name = self.deref_register(1); let module_name = self.deref_register(1);
let name = cell_as_atom!(self.deref_register(2)); let name = cell_as_atom!(self.deref_register(2));
let arity = cell_as_fixnum!(self.deref_register(3)).get_num() as usize; let arity =
unsafe { self.deref_register(3).to_fixnum_or_cut_point_unchecked() }.get_num() as usize;
let module_name = read_heap_cell!(module_name, let module_name = read_heap_cell!(module_name,
(HeapCellValueTag::Atom, (module_name, _arity)) => { (HeapCellValueTag::Atom, (module_name, _arity)) => {
@@ -4285,7 +4307,12 @@ impl Machine {
return; return;
} }
let value = self.rng.gen_range(lower..upper); let value = self.rng.gen_range(lower..upper);
Number::Fixnum(Fixnum::build_with(value)) // Safety:
// - lower and uper bounds are Fixnum values
// - value is inbetween lower and upper
// - fixnums value range has no gaps
// so value is also a valid Fixnum value
Number::Fixnum(unsafe { Fixnum::build_with_unchecked(value) })
} }
(Ok(Number::Fixnum(lower)), Ok(Number::Integer(upper))) => { (Ok(Number::Fixnum(lower)), Ok(Number::Integer(upper))) => {
let lower = Integer::from(lower); let lower = Integer::from(lower);
@@ -4463,7 +4490,7 @@ impl Machine {
// status code // status code
let status = resp.status().as_u16(); let status = resp.status().as_u16();
self.machine_st self.machine_st
.unify_fixnum(Fixnum::build_with(status as i64), address_status); .unify_fixnum(Fixnum::build_with(status), address_status);
// headers // headers
let mut headers: Vec<HeapCellValue> = vec![]; let mut headers: Vec<HeapCellValue> = vec![];
@@ -5010,9 +5037,12 @@ impl Machine {
{ {
Ok(result) => { Ok(result) => {
match result { match result {
Value::Int(n) => self Value::Int(n) => self.machine_st.unify_fixnum(
.machine_st Fixnum::build_with_checked(n).unwrap_or_else(|_| {
.unify_fixnum(Fixnum::build_with(n), return_value), todo!("handle integer values that don't fit in fixnum")
}),
return_value,
),
Value::Float(n) => { Value::Float(n) => {
let n = float_alloc!(n, self.machine_st.arena); let n = float_alloc!(n, self.machine_st.arena);
self.machine_st.unify_f64(n, return_value) self.machine_st.unify_f64(n, return_value)
@@ -5060,7 +5090,16 @@ impl Machine {
for val in args { for val in args {
expanded_args.push(match val { expanded_args.push(match val {
Value::Int(n) => fixnum_as_cell!(Fixnum::build_with(n)), Value::Int(n) => {
if let Ok(fixnum) = Fixnum::build_with_checked(n) {
fixnum_as_cell!(fixnum)
} else {
integer_as_cell!(Number::Integer(arena_alloc!(
Integer::from(n),
&mut self.machine_st.arena
)))
}
}
Value::Float(n) => HeapCellValue::from(float_alloc!(n, self.machine_st.arena)), Value::Float(n) => HeapCellValue::from(float_alloc!(n, self.machine_st.arena)),
Value::CString(cstr) => atom_as_cell!(AtomTable::build_with( Value::CString(cstr) => atom_as_cell!(AtomTable::build_with(
&self.machine_st.atom_tbl, &self.machine_st.atom_tbl,
@@ -5413,7 +5452,11 @@ impl Machine {
#[inline(always)] #[inline(always)]
pub(crate) fn get_attr_var_queue_delimiter(&mut self) { pub(crate) fn get_attr_var_queue_delimiter(&mut self) {
let addr = self.deref_register(1); let addr = self.deref_register(1);
let value = Fixnum::build_with(self.machine_st.attr_var_init.attr_var_queue.len() as i64);
/* FIXME this is not safe */
let value = unsafe {
Fixnum::build_with_unchecked(self.machine_st.attr_var_init.attr_var_queue.len() as i64)
};
self.machine_st.unify_fixnum(value, addr); self.machine_st.unify_fixnum(value, addr);
} }
@@ -5682,7 +5725,7 @@ impl Machine {
#[inline(always)] #[inline(always)]
pub(crate) fn get_continuation_chunk(&mut self) { pub(crate) fn get_continuation_chunk(&mut self) {
let e = self.deref_register(1); let e = self.deref_register(1);
let e = cell_as_fixnum!(e).get_num() as usize; let e = unsafe { e.to_fixnum_or_cut_point_unchecked() }.get_num() as usize;
let h = self.machine_st.heap.cell_len(); let h = self.machine_st.heap.cell_len();
let p_functor_cell = self.deref_register(2); let p_functor_cell = self.deref_register(2);
@@ -5736,8 +5779,12 @@ impl Machine {
#[inline(always)] #[inline(always)]
pub(crate) fn get_lifted_heap_from_offset_diff(&mut self) { pub(crate) fn get_lifted_heap_from_offset_diff(&mut self) {
let lh_offset = self.machine_st.registers[1]; let lh_offset = self.machine_st.registers[1];
let lh_offset = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(lh_offset))) let lh_offset = unsafe {
.get_num() as usize; self.machine_st
.store(self.machine_st.deref(lh_offset))
.to_fixnum_or_cut_point_unchecked()
}
.get_num() as usize;
if lh_offset >= self.machine_st.lifted_heap.cell_len() { if lh_offset >= self.machine_st.lifted_heap.cell_len() {
let solutions = self.machine_st.registers[2]; let solutions = self.machine_st.registers[2];
@@ -5765,8 +5812,12 @@ impl Machine {
#[inline(always)] #[inline(always)]
pub(crate) fn get_lifted_heap_from_offset(&mut self) { pub(crate) fn get_lifted_heap_from_offset(&mut self) {
let lh_offset = self.machine_st.registers[1]; let lh_offset = self.machine_st.registers[1];
let lh_offset = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(lh_offset))) let lh_offset = unsafe {
.get_num() as usize; self.machine_st
.store(self.machine_st.deref(lh_offset))
.to_fixnum_or_cut_point_unchecked()
}
.get_num() as usize;
if lh_offset >= self.machine_st.lifted_heap.cell_len() { if lh_offset >= self.machine_st.lifted_heap.cell_len() {
let solutions = self.machine_st.registers[2]; let solutions = self.machine_st.registers[2];
@@ -5888,7 +5939,7 @@ impl Machine {
} }
}; };
let bp = cell_as_fixnum!(a1).get_num() as usize; let bp = unsafe { a1.to_fixnum_or_cut_point_unchecked() }.get_num() as usize;
let a3 = self.deref_register(3); let a3 = self.deref_register(3);
let count = self.machine_st.cwil.add_limit(n, bp).clone(); let count = self.machine_st.cwil.add_limit(n, bp).clone();
@@ -5899,9 +5950,11 @@ impl Machine {
#[inline(always)] #[inline(always)]
pub(crate) fn inference_count(&mut self, count_var: HeapCellValue, count: Integer) { pub(crate) fn inference_count(&mut self, count_var: HeapCellValue, count: Integer) {
if let Ok(value) = <&Integer as TryInto<i64>>::try_into(&count) { if let Some(value) = <&Integer as TryInto<i64>>::try_into(&count)
self.machine_st .ok()
.unify_fixnum(Fixnum::build_with(value), count_var); .and_then(|i| Fixnum::build_with_checked(i).ok())
{
self.machine_st.unify_fixnum(value, count_var);
} else { } else {
let count = arena_alloc!(count, &mut self.machine_st.arena); let count = arena_alloc!(count, &mut self.machine_st.arena);
self.machine_st.unify_big_int(count, count_var); self.machine_st.unify_big_int(count, count_var);
@@ -6028,7 +6081,8 @@ impl Machine {
#[inline(always)] #[inline(always)]
pub(crate) fn remove_call_policy_check(&mut self) { pub(crate) fn remove_call_policy_check(&mut self) {
let bp = cell_as_fixnum!(self.deref_register(1)).get_num() as usize; let bp =
unsafe { self.deref_register(1).to_fixnum_or_cut_point_unchecked() }.get_num() as usize;
if bp == self.machine_st.b && self.machine_st.cwil.is_empty() { if bp == self.machine_st.b && self.machine_st.cwil.is_empty() {
self.machine_st.cwil.reset(); self.machine_st.cwil.reset();
@@ -6040,12 +6094,10 @@ impl Machine {
let a1 = self.deref_register(1); let a1 = self.deref_register(1);
let a2 = self.deref_register(2); let a2 = self.deref_register(2);
let block = cell_as_fixnum!(a1).get_num() as usize; let block = unsafe { a1.to_fixnum_or_cut_point_unchecked() }.get_num() as usize;
let count = self.machine_st.cwil.remove_limit(block).clone(); let count = self.machine_st.cwil.remove_limit(block).clone();
let result = count.clone().try_into(); if let Ok(value) = Fixnum::build_with_checked(&count) {
self.machine_st.unify_fixnum(value, a2);
if let Ok(value) = result {
self.machine_st.unify_fixnum(Fixnum::build_with(value), a2);
} else { } else {
let count = arena_alloc!(count.clone(), &mut self.machine_st.arena); let count = arena_alloc!(count.clone(), &mut self.machine_st.arena);
self.machine_st.unify_big_int(count, a2); self.machine_st.unify_big_int(count, a2);
@@ -6063,18 +6115,23 @@ impl Machine {
self.machine_st.registers[i] = self.machine_st.stack[stack_loc!(AndFrame, e, i)]; self.machine_st.registers[i] = self.machine_st.stack[stack_loc!(AndFrame, e, i)];
} }
self.machine_st.b0 = cell_as_fixnum!( self.machine_st.b0 = unsafe {
self.machine_st.stack[stack_loc!(AndFrame, e, frame_len - 2)] self.machine_st.stack[stack_loc!(AndFrame, e, frame_len - 2)]
) .to_fixnum_or_cut_point_unchecked()
}
.get_num() as usize; .get_num() as usize;
self.machine_st.num_of_args = cell_as_fixnum!( self.machine_st.num_of_args = unsafe {
self.machine_st.stack[stack_loc!(AndFrame, e, frame_len - 1)] self.machine_st.stack[stack_loc!(AndFrame, e, frame_len - 1)]
) .to_fixnum_or_cut_point_unchecked()
}
.get_num() as usize; .get_num() as usize;
let p = cell_as_fixnum!(self.machine_st.stack[stack_loc!(AndFrame, e, frame_len)]).get_num() let p = unsafe {
as usize; self.machine_st.stack[stack_loc!(AndFrame, e, frame_len)]
.to_fixnum_or_cut_point_unchecked()
}
.get_num() as usize;
self.machine_st.deallocate(); self.machine_st.deallocate();
self.machine_st.p = p; self.machine_st.p = p;
@@ -6191,7 +6248,7 @@ impl Machine {
let a1 = self.deref_register(1); let a1 = self.deref_register(1);
let a2 = self.deref_register(2); let a2 = self.deref_register(2);
let bp = cell_as_fixnum!(a2).get_num() as usize; let bp = unsafe { a2.to_fixnum_or_cut_point_unchecked() }.get_num() as usize;
let prev_b = self let prev_b = self
.machine_st .machine_st
.stack .stack
@@ -6214,7 +6271,7 @@ impl Machine {
#[inline(always)] #[inline(always)]
pub(crate) fn clean_up_block(&mut self) { pub(crate) fn clean_up_block(&mut self) {
let nb = self.deref_register(1); let nb = self.deref_register(1);
let nb = cell_as_fixnum!(nb).get_num() as usize; let nb = unsafe { nb.to_fixnum_or_cut_point_unchecked() }.get_num() as usize;
let b = self.machine_st.b; let b = self.machine_st.b;
@@ -6270,7 +6327,9 @@ impl Machine {
#[inline(always)] #[inline(always)]
pub(crate) fn get_current_block(&mut self) { pub(crate) fn get_current_block(&mut self) {
let addr = self.machine_st.registers[1]; let addr = self.machine_st.registers[1];
let block = Fixnum::build_with(self.machine_st.block as i64);
/* FIXME this is not safe */
let block = unsafe { Fixnum::build_with_unchecked(self.machine_st.block as i64) };
self.machine_st.unify_fixnum(block, addr); self.machine_st.unify_fixnum(block, addr);
} }
@@ -6278,21 +6337,27 @@ impl Machine {
#[inline(always)] #[inline(always)]
pub(crate) fn get_current_scc_block(&mut self) { pub(crate) fn get_current_scc_block(&mut self) {
let addr = self.machine_st.registers[1]; let addr = self.machine_st.registers[1];
let block = Fixnum::build_with(self.machine_st.scc_block as i64);
/* FIXME this is not safe */
let block = unsafe { Fixnum::build_with_unchecked(self.machine_st.scc_block as i64) };
self.machine_st.unify_fixnum(block, addr); self.machine_st.unify_fixnum(block, addr);
} }
#[inline(always)] #[inline(always)]
pub(crate) fn get_b_value(&mut self) { pub(crate) fn get_b_value(&mut self) {
let n = Fixnum::as_cutpoint(i64::try_from(self.machine_st.b).unwrap()); /* FIXME this is not safe */
let n = unsafe { Fixnum::build_with_unchecked(i64::try_from(self.machine_st.b).unwrap()) }
.as_cutpoint();
self.machine_st self.machine_st
.unify_fixnum(n, self.machine_st.registers[1]); .unify_fixnum(n, self.machine_st.registers[1]);
} }
#[inline(always)] #[inline(always)]
pub(crate) fn get_cut_point(&mut self) { pub(crate) fn get_cut_point(&mut self) {
let n = Fixnum::as_cutpoint(i64::try_from(self.machine_st.b0).unwrap()); /* FIXME this is not safe */
let n = unsafe { Fixnum::build_with_unchecked(i64::try_from(self.machine_st.b0).unwrap()) }
.as_cutpoint();
self.machine_st self.machine_st
.unify_fixnum(n, self.machine_st.registers[1]); .unify_fixnum(n, self.machine_st.registers[1]);
} }
@@ -6314,7 +6379,7 @@ impl Machine {
let cp = and_frame.prelude.cp - 1; let cp = and_frame.prelude.cp - 1;
let e = and_frame.prelude.e; let e = and_frame.prelude.e;
let e = Fixnum::build_with(i64::try_from(e).unwrap()); let e = Fixnum::build_with_checked(e).unwrap();
machine_st.unify_fixnum(e, machine_st.registers[2]); machine_st.unify_fixnum(e, machine_st.registers[2]);
@@ -6363,7 +6428,7 @@ impl Machine {
writer(&mut self.machine_st.heap) writer(&mut self.machine_st.heap)
); );
let e = Fixnum::build_with(i64::try_from(and_frame.prelude.e).unwrap()); let e = Fixnum::build_with_checked(and_frame.prelude.e).unwrap();
self.machine_st.unify_fixnum(e, self.machine_st.registers[2]); self.machine_st.unify_fixnum(e, self.machine_st.registers[2]);
if !self.machine_st.fail { if !self.machine_st.fail {
@@ -6787,10 +6852,7 @@ impl Machine {
let port = tcp_listener.local_addr().map(|addr| addr.port()).ok(); let port = tcp_listener.local_addr().map(|addr| addr.port()).ok();
if let Some(port) = port { if let Some(port) = port {
( (arena_alloc!(tcp_listener, &mut self.machine_st.arena), port)
arena_alloc!(tcp_listener, &mut self.machine_st.arena),
port as usize,
)
} else { } else {
self.machine_st.fail = true; self.machine_st.fail = true;
return Ok(()); return Ok(());
@@ -6817,7 +6879,7 @@ impl Machine {
if had_zero_port { if had_zero_port {
self.machine_st self.machine_st
.unify_fixnum(Fixnum::build_with(port as i64), self.deref_register(2)); .unify_fixnum(Fixnum::build_with(port), self.deref_register(2));
} }
Ok(()) Ok(())
@@ -7266,7 +7328,8 @@ impl Machine {
#[inline(always)] #[inline(always)]
pub(crate) fn term_variables_under_max_depth(&mut self) { pub(crate) fn term_variables_under_max_depth(&mut self) {
// Term, MaxDepth, VarList // Term, MaxDepth, VarList
let max_depth = cell_as_fixnum!(self.deref_register(2)).get_num() as usize; let max_depth =
unsafe { self.deref_register(2).to_fixnum_or_cut_point_unchecked() }.get_num() as usize;
self.machine_st.term_variables_under_max_depth( self.machine_st.term_variables_under_max_depth(
self.machine_st.registers[1], self.machine_st.registers[1],
@@ -7278,7 +7341,7 @@ impl Machine {
#[inline(always)] #[inline(always)]
pub(crate) fn truncate_lifted_heap_to(&mut self) { pub(crate) fn truncate_lifted_heap_to(&mut self) {
let a1 = self.deref_register(1); let a1 = self.deref_register(1);
let lh_offset = cell_as_fixnum!(a1).get_num() as usize; let lh_offset = unsafe { a1.to_fixnum_or_cut_point_unchecked() }.get_num() as usize;
self.machine_st.lifted_heap.truncate(lh_offset); self.machine_st.lifted_heap.truncate(lh_offset);
} }
@@ -7561,7 +7624,7 @@ impl Machine {
} }
} }
let byte = Fixnum::build_with(bytes[0] as i64); let byte = Fixnum::build_with(bytes[0]);
self.machine_st.unify_fixnum(byte, arg); self.machine_st.unify_fixnum(byte, arg);
} }
@@ -7587,7 +7650,7 @@ impl Machine {
context_len, context_len,
finalized_context finalized_context
.iter() .iter()
.map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) .map(|b| fixnum_as_cell!(Fixnum::build_with(*b)))
) )
) )
} }
@@ -7604,7 +7667,7 @@ impl Machine {
context_len, context_len,
finalized_context finalized_context
.iter() .iter()
.map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) .map(|b| fixnum_as_cell!(Fixnum::build_with(*b)))
) )
) )
} }
@@ -7621,7 +7684,7 @@ impl Machine {
context_len, context_len,
finalized_context finalized_context
.iter() .iter()
.map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) .map(|b| fixnum_as_cell!(Fixnum::build_with(*b)))
) )
) )
} }
@@ -7638,7 +7701,7 @@ impl Machine {
context_len, context_len,
finalized_context finalized_context
.iter() .iter()
.map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), .map(|b| fixnum_as_cell!(Fixnum::build_with(*b))),
) )
) )
} }
@@ -7655,7 +7718,7 @@ impl Machine {
context_len, context_len,
finalized_context finalized_context
.iter() .iter()
.map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), .map(|b| fixnum_as_cell!(Fixnum::build_with(*b))),
) )
) )
} }
@@ -7672,7 +7735,7 @@ impl Machine {
context_len, context_len,
finalized_context finalized_context
.iter() .iter()
.map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), .map(|b| fixnum_as_cell!(Fixnum::build_with(*b))),
) )
) )
} }
@@ -7689,7 +7752,7 @@ impl Machine {
context_len, context_len,
finalized_context finalized_context
.iter() .iter()
.map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) .map(|b| fixnum_as_cell!(Fixnum::build_with(*b)))
) )
) )
} }
@@ -7714,7 +7777,7 @@ impl Machine {
ints.as_ref().len(), ints.as_ref().len(),
ints.as_ref() ints.as_ref()
.iter() .iter()
.map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) .map(|b| fixnum_as_cell!(Fixnum::build_with(*b)))
) )
) )
} }
@@ -7754,7 +7817,7 @@ impl Machine {
tag.as_ref().len(), tag.as_ref().len(),
tag.as_ref() tag.as_ref()
.iter() .iter()
.map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) .map(|b| fixnum_as_cell!(Fixnum::build_with(*b)))
) )
); );
@@ -7825,7 +7888,7 @@ impl Machine {
bytes.len(), bytes.len(),
bytes bytes
.iter() .iter()
.map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) .map(|b| fixnum_as_cell!(Fixnum::build_with(*b)))
) )
) )
}; };
@@ -7881,7 +7944,7 @@ impl Machine {
bytes.len(), bytes.len(),
bytes bytes
.iter() .iter()
.map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) .map(|b| fixnum_as_cell!(Fixnum::build_with(*b)))
) )
) )
}; };
@@ -7928,7 +7991,7 @@ impl Machine {
tag.as_ref().len(), tag.as_ref().len(),
tag.as_ref() tag.as_ref()
.iter() .iter()
.map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) .map(|b| fixnum_as_cell!(Fixnum::build_with(*b)))
) )
); );
@@ -8068,7 +8131,7 @@ impl Machine {
sig.as_ref().len(), sig.as_ref().len(),
sig.as_ref() sig.as_ref()
.iter() .iter()
.map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) .map(|b| fixnum_as_cell!(Fixnum::build_with(*b)))
) )
); );
@@ -8482,7 +8545,7 @@ impl Machine {
let number = self.deref_register(1); let number = self.deref_register(1);
let pop_count = integer_as_cell!(match Number::try_from(number) { let pop_count = integer_as_cell!(match Number::try_from(number) {
Ok(Number::Fixnum(n)) => { Ok(Number::Fixnum(n)) => {
Number::Fixnum(Fixnum::build_with(n.get_num().count_ones() as i64)) Number::Fixnum(Fixnum::build_with(n.get_num().count_ones()))
} }
Ok(Number::Integer(n)) => { Ok(Number::Integer(n)) => {
let value: usize = if n.sign() == Sign::Positive { let value: usize = if n.sign() == Sign::Positive {

View File

@@ -14,12 +14,6 @@ macro_rules! fixnum_as_cell {
}; };
} }
macro_rules! cell_as_fixnum {
($cell:expr) => {
Fixnum::from_bytes($cell.into_bytes())
};
}
macro_rules! integer_as_cell { macro_rules! integer_as_cell {
($n: expr) => {{ ($n: expr) => {{
match $n { match $n {

View File

@@ -11,7 +11,10 @@ use std::cell::{Cell, Ref, RefCell, RefMut};
use std::fmt; use std::fmt;
use std::hash::Hash; use std::hash::Hash;
use std::hash::Hasher; use std::hash::Hasher;
use std::i64;
use std::io::{Error as IOError, ErrorKind}; use std::io::{Error as IOError, ErrorKind};
use std::ops::Not;
use std::ops::RangeInclusive;
use std::ops::{Deref, Neg}; use std::ops::{Deref, Neg};
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
@@ -550,9 +553,90 @@ pub struct Fixnum {
tag: B6, tag: B6,
} }
mod private {
use dashu::Integer;
pub(crate) trait FitsInFixnumSeal {}
pub(crate) trait MightNotFitInFixnumSeal {}
macro_rules! impl_fits_in_fixnum {
($t:ty) => {
impl $crate::parser::ast::private::FitsInFixnumSeal for $t {}
impl $crate::parser::ast::FitsInFixnum for $t {
fn into_i56(self) -> i64 {
self.into()
}
}
};
}
impl_fits_in_fixnum!(u8);
impl_fits_in_fixnum!(i8);
impl_fits_in_fixnum!(u16);
impl_fits_in_fixnum!(i16);
impl_fits_in_fixnum!(u32);
impl_fits_in_fixnum!(i32);
impl FitsInFixnumSeal for char {}
impl super::FitsInFixnum for char {
fn into_i56(self) -> i64 {
u32::from(self) as i64
}
}
impl MightNotFitInFixnumSeal for i64 {}
impl MightNotFitInFixnumSeal for &Integer {}
impl MightNotFitInFixnumSeal for Integer {}
impl MightNotFitInFixnumSeal for usize {}
}
#[allow(private_bounds)]
pub trait FitsInFixnum: private::FitsInFixnumSeal {
fn into_i56(self) -> i64;
}
#[allow(private_bounds)]
pub trait MightNotFitInFixnum: private::MightNotFitInFixnumSeal {
fn try_into_i56(self) -> Option<i64>;
}
impl<T> MightNotFitInFixnum for T
where
T: private::MightNotFitInFixnumSeal + TryInto<i64>,
{
fn try_into_i56(self) -> Option<i64> {
let val = self.try_into().ok()?;
if Fixnum::RANGE.contains(&val) {
Some(val)
} else {
None
}
}
}
impl Fixnum { impl Fixnum {
pub(crate) const MIN: i64 = -(1 << 55);
pub(crate) const MAX: i64 = (1 << 55) - 1;
const RANGE: RangeInclusive<i64> = Self::MIN..=Self::MAX;
// if you have a type that is not guaranteed to fit use `Fixnum::build_with_checked` or `Fixnum::build_with_unchecked` instead
#[inline] #[inline]
pub fn build_with(num: i64) -> Self { pub fn build_with(num: impl FitsInFixnum) -> Self {
// Safety: FitsInFixnum is only implemented by types that only have valid values
// and FitsInFixnumSeal ensures no one outside this crate can violate that
unsafe { Self::build_with_unchecked(num.into_i56()) }
}
#[inline]
pub unsafe fn build_with_unchecked(num: i64) -> Self {
debug_assert!(
Self::RANGE.contains(&num),
"{num} should be in the range {}..={}",
Self::MIN,
Self::MAX
);
Fixnum::new() Fixnum::new()
.with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 56) - 1)) .with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 56) - 1))
.with_tag(HeapCellValueTag::Fixnum as u8) .with_tag(HeapCellValueTag::Fixnum as u8)
@@ -561,12 +645,8 @@ impl Fixnum {
} }
#[inline] #[inline]
pub fn as_cutpoint(num: i64) -> Self { pub fn as_cutpoint(self) -> Self {
Fixnum::new() self.with_tag(HeapCellValueTag::CutPoint as u8)
.with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 56) - 1))
.with_tag(HeapCellValueTag::CutPoint as u8)
.with_m(false)
.with_f(false)
} }
#[inline] #[inline]
@@ -575,20 +655,14 @@ impl Fixnum {
HeapCellValueTag::from_bytes(self.tag()).unwrap() HeapCellValueTag::from_bytes(self.tag()).unwrap()
} }
// if you have a type that is guaranteed to fit use `Fixnum::build_with` instead
#[inline] #[inline]
pub fn build_with_checked(num: i64) -> Result<Self, OutOfBounds> { pub fn build_with_checked(num: impl MightNotFitInFixnum) -> Result<Self, OutOfBounds> {
const UPPER_BOUND: i64 = (1 << 55) - 1; Ok(unsafe {
const LOWER_BOUND: i64 = -(1 << 55); // Safety: all MightNotFitInFixnum impls return None when the value is out-of-bounds
// and MightNotFitInFixnumSeal ensures no one outside this crate can violate that
if (LOWER_BOUND..=UPPER_BOUND).contains(&num) { Self::build_with_unchecked(num.try_into_i56().ok_or(OutOfBounds {})?)
Ok(Fixnum::new() })
.with_m(false)
.with_f(false)
.with_tag(HeapCellValueTag::Fixnum as u8)
.with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 56) - 1)))
} else {
Err(OutOfBounds {})
}
} }
#[inline] #[inline]
@@ -598,6 +672,10 @@ impl Fixnum {
debug_assert!(!overflowed); debug_assert!(!overflowed);
n n
} }
pub fn checked_abs(self) -> Option<Self> {
Self::build_with_checked(self.get_num().abs()).ok()
}
} }
impl Neg for Fixnum { impl Neg for Fixnum {
@@ -605,7 +683,18 @@ impl Neg for Fixnum {
#[inline] #[inline]
fn neg(self) -> Self::Output { fn neg(self) -> Self::Output {
Fixnum::build_with(-self.get_num()) // Safety: the truncating behaviour is correct
unsafe { Self::build_with_unchecked(-self.get_num()) }
}
}
impl Not for Fixnum {
type Output = Self;
#[inline]
fn not(self) -> Self::Output {
// Safety: the truncating behaviour is correct
unsafe { Self::build_with_unchecked(!self.get_num()) }
} }
} }

View File

@@ -1,9 +1,7 @@
use crate::arena::F64Ptr;
use crate::arena::TypedArenaPtr;
use crate::arena::*; use crate::arena::*;
use crate::atom_table::*; use crate::atom_table::*;
pub use crate::machine::machine_state::*; pub use crate::machine::machine_state::*;
use crate::offset_table::F64Ptr;
use crate::parser::ast::*; use crate::parser::ast::*;
use crate::parser::char_reader::*; use crate::parser::char_reader::*;
use crate::parser::dashu::Integer; use crate::parser::dashu::Integer;
@@ -662,15 +660,15 @@ impl<'a, R: CharRead> Lexer<'a, R> {
} }
} }
fn vacate_with_float(&mut self, mut token: String) -> Result<Token, ParserError> { fn vacate_with_float(&mut self, mut token: String) -> Result<Number, ParserError> {
self.return_char(token.pop().unwrap()); self.return_char(token.pop().unwrap());
let n = parse_float_lossy(&token)?; let n = parse_float_lossy(&token)?;
Ok(Token::Literal(Literal::from(float_alloc!( Ok(Number::Float(float_alloc!(
n, n,
self.machine_st.arena self.machine_st.arena
)))) )))
} }
fn skip_underscore_in_number(&mut self) -> Result<char, ParserError> { fn skip_underscore_in_number(&mut self) -> Result<char, ParserError> {
@@ -797,7 +795,8 @@ impl<'a, R: CharRead> Lexer<'a, R> {
} }
let n = parse_float_lossy(&token)?; let n = parse_float_lossy(&token)?;
Ok(Token::Literal(Literal::from(float_alloc!(
Ok(NumberToken::Number(Number::Float(float_alloc!(
n, n,
self.machine_st.arena self.machine_st.arena
)))) ))))
@@ -806,7 +805,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
} }
} else { } else {
let n = parse_float_lossy(&token)?; let n = parse_float_lossy(&token)?;
Ok(Token::Literal(Literal::from(float_alloc!( Ok(NumberToken::Number(Number::Float(float_alloc!(
n, n,
self.machine_st.arena self.machine_st.arena
)))) ))))
@@ -859,7 +858,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
} }
self.get_single_quoted_char() self.get_single_quoted_char()
.map(|c| NumberToken::Number(Number::Fixnum(Fixnum::build_with(c as i64)))) .map(|c| NumberToken::Number(Number::Fixnum(Fixnum::build_with(c))))
.or_else(|err| { .or_else(|err| {
match err { match err {
ParserError::UnexpectedChar('\'', ..) => {} ParserError::UnexpectedChar('\'', ..) => {}

View File

@@ -389,7 +389,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
Cell::default(), Cell::default(),
Box::new(Term::Literal( Box::new(Term::Literal(
Cell::default(), Cell::default(),
Literal::Fixnum(Fixnum::build_with(c as i64)), Literal::Fixnum(Fixnum::build_with(c)),
)), )),
Box::new(list), Box::new(list),
); );
@@ -963,12 +963,12 @@ impl<'a, R: CharRead> Parser<'a, R> {
Token::Literal(Literal::Rational(n)) => { Token::Literal(Literal::Rational(n)) => {
self.negate_number(n, negate_rat_rc, |r, _| Literal::Rational(r)) self.negate_number(n, negate_rat_rc, |r, _| Literal::Rational(r))
} }
Token::Literal(Literal::Float(n)) if n.as_ptr().is_infinite() => { Token::Literal(Literal::Float(n)) if n.as_ptr().is_infinite() => {
return Err(ParserError::InfiniteFloat( return Err(ParserError::InfiniteFloat(
self.lexer.line_num, self.lexer.line_num,
self.lexer.col_num, self.lexer.col_num,
)); ));
} }
Token::Literal(Literal::Float(n)) => self.negate_number( Token::Literal(Literal::Float(n)) => self.negate_number(
**n.as_ptr(), **n.as_ptr(),
|n, _| -n, |n, _| -n,

View File

@@ -588,6 +588,16 @@ impl HeapCellValue {
} }
} }
// FIXME: someone that knows this better should check if this can be split into `to_fixnum_unchecked` and `to_cut_point_unchecked` assuming thats always unambigusly knowable
#[inline]
pub unsafe fn to_fixnum_or_cut_point_unchecked(self) -> Fixnum {
debug_assert!(matches!(
self.get_tag(),
HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint
));
Fixnum::from_bytes(self.into_bytes())
}
#[inline] #[inline]
pub fn from_ptr_addr(ptr_bytes: usize) -> Self { pub fn from_ptr_addr(ptr_bytes: usize) -> Self {
HeapCellValue::from_bytes((ptr_bytes as u64).to_ne_bytes()) HeapCellValue::from_bytes((ptr_bytes as u64).to_ne_bytes())