inline metacalls

This commit is contained in:
Mark Thom
2022-07-12 22:39:50 -06:00
parent c7e1f5d568
commit 1ffbf63d20
44 changed files with 2952 additions and 1414 deletions

View File

@@ -10,7 +10,7 @@ use crate::heap_iter::*;
use crate::heap_print::*;
use crate::instructions::*;
use crate::machine;
use crate::machine::{Machine, VERIFY_ATTR_INTERRUPT_LOC};
use crate::machine::{Machine, VERIFY_ATTR_INTERRUPT_LOC, get_structure_index};
use crate::machine::code_walker::*;
use crate::machine::copier::*;
use crate::machine::heap::*;
@@ -29,22 +29,27 @@ use crate::types::*;
use ordered_float::OrderedFloat;
use fxhash::{FxBuildHasher, FxHasher};
use indexmap::IndexSet;
use ref_thread_local::{RefThreadLocal, ref_thread_local};
use std::cell::Cell;
use std::cmp::Ordering;
use std::collections::BTreeSet;
use std::convert::TryFrom;
use std::env;
use std::fs;
use std::hash::{BuildHasher, BuildHasherDefault};
use std::io::{ErrorKind, Read, Write};
use std::iter::{once, FromIterator};
use std::mem;
use std::net::{TcpListener, TcpStream};
use std::num::NonZeroU32;
use std::ops::Sub;
use std::str::FromStr;
use std::process;
use std::rc::Rc;
use std::str::FromStr;
use chrono::{offset::Local, DateTime};
use cpu_time::ProcessTime;
@@ -173,6 +178,16 @@ impl BrentAlgState {
CycleSearchResult::NotList(self.num_steps(), heap[self.hare])
};
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(heap[s])
.get_name_and_arity();
return if name == atom!("[]") && arity == 0 {
CycleSearchResult::ProperList(self.num_steps())
} else {
CycleSearchResult::NotList(self.num_steps(), heap[self.hare])
};
}
(HeapCellValueTag::Lis, l) => {
return CycleSearchResult::UntouchedList(self.num_steps(), l);
}
@@ -439,6 +454,30 @@ impl BrentAlgState {
}
impl MachineState {
#[inline]
pub(crate) fn variable_set<S: BuildHasher>(
&mut self,
seen_set: &mut IndexSet<HeapCellValue, S>,
value: HeapCellValue,
) {
let mut iter = stackful_preorder_iter(&mut self.heap, value);
while let Some(value) = iter.next() {
let value = unmark_cell_bits!(value);
if value.is_var() {
let value = unmark_cell_bits!(heap_bound_store(
iter.heap,
heap_bound_deref(iter.heap, value)
));
if value.is_var() {
seen_set.insert(value);
}
}
}
}
fn skip_max_list_cycle(&mut self, lam: usize) {
fn step(heap: &[HeapCellValue], mut value: HeapCellValue) -> usize {
loop {
@@ -820,6 +859,16 @@ impl MachineState {
None
}
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
if arity == 0 {
Some(AtomOrString::Atom(name))
} else {
None
}
}
(HeapCellValueTag::Char, c) => {
Some(AtomOrString::String(c.to_string()))
}
@@ -924,6 +973,289 @@ impl MachineState {
}
impl Machine {
#[inline(always)]
pub(crate) fn call_inline(
&mut self,
arity: usize,
call_at_index: impl Fn(&mut Machine, Atom, usize, IndexPtr) -> CallResult,
) -> CallResult {
let arity = arity - 1;
let goal = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
let load_registers = |machine_st: &mut MachineState, goal: HeapCellValue| -> Option<PredicateKey> {
read_heap_cell!(goal,
(HeapCellValueTag::Str, s) => {
let (name, goal_arity) = cell_as_atom_cell!(machine_st.heap[s])
.get_name_and_arity();
if goal_arity > 0 {
for idx in (1 .. arity + 1).rev() {
machine_st.registers[idx + goal_arity] = machine_st.registers[idx + 1];
}
} else {
for idx in 1 .. arity + 1 {
machine_st.registers[idx] = machine_st.registers[idx + 1];
}
}
for idx in 1 .. goal_arity + 1 {
machine_st.registers[idx] = machine_st.heap[s+idx];
}
Some((name, goal_arity))
}
_ => {
unreachable!()
}
)
};
read_heap_cell!(goal,
(HeapCellValueTag::Str, s) => {
let goal_arity = cell_as_atom_cell!(self.machine_st.heap[s]).get_arity();
if self.machine_st.heap.len() > s + goal_arity + 1 {
let index_cell = self.machine_st.heap[s+goal_arity+1];
if let Some(code_index) = get_structure_index(index_cell) {
if code_index.is_undefined() || code_index.is_dynamic_undefined() {
self.machine_st.fail = true;
return Ok(());
}
match load_registers(&mut self.machine_st, goal) {
Some((name, goal_arity)) => {
let arity = goal_arity + arity;
self.machine_st.neck_cut();
return call_at_index(self, name, arity, code_index.get());
}
None => {
}
}
}
}
}
_ => {
}
);
self.machine_st.fail = true;
Ok(())
}
#[inline(always)]
pub(crate) fn compile_inline_or_expanded_goal(&mut self) -> CallResult {
let goal = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
let module_name = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[4]));
// supp_vars are the supplementary variables generated by
// complete_partial_goal prior to goal_expansion.
let mut supp_vars = IndexSet::with_hasher(FxBuildHasher::default());
self.machine_st.variable_set(&mut supp_vars, self.machine_st.registers[2]);
struct GoalAnalysisResult {
is_simple_goal: bool,
goal: HeapCellValue,
key: PredicateKey,
expanded_vars: IndexSet<HeapCellValue, BuildHasherDefault<FxHasher>>,
supp_vars: IndexSet<HeapCellValue, BuildHasherDefault<FxHasher>>,
}
let result = read_heap_cell!(goal,
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
.get_name_and_arity();
let mut expanded_vars = IndexSet::with_hasher(FxBuildHasher::default());
// fill expanded_vars with variables of the partial
// goal pre-completion by complete_partial_goal.
for idx in s + 1 .. s + arity - supp_vars.len() + 1 {
self.machine_st.variable_set(&mut expanded_vars, self.machine_st.heap[idx]);
}
let is_simple_goal = if arity >= supp_vars.len() {
// post_supp_args are the arguments to the
// post-expansion complete goal gathered from the
// final supp_vars.len() arguments. they must
// agree in supp_vars in order of entry of
// insertion as well as the previous
// supp_vars.len() argument's variables being
// disjoint from them. if they are not, the
// expanded goal are not simple.
let post_supp_args = self.machine_st.heap[s+arity-supp_vars.len()+1 .. s+arity+1]
.iter()
.cloned();
post_supp_args
.zip(supp_vars.iter())
.all(|(arg_term, supp_var)| {
let arg_term = self.machine_st.store(self.machine_st.deref(arg_term));
if arg_term.is_var() && supp_var.is_var() {
return arg_term == *supp_var;
}
false
}) && expanded_vars.intersection(&supp_vars).next().is_none()
} else {
false
};
let goal = if is_simple_goal {
let h = self.machine_st.heap.len();
let arity = arity - supp_vars.len();
for idx in 0 .. arity + 1 {
let value = self.machine_st.heap[s + idx];
self.machine_st.heap.push(value);
}
self.machine_st.heap[h] = atom_as_cell!(name, arity);
str_loc_as_cell!(h)
} else {
goal
};
GoalAnalysisResult {
is_simple_goal,
goal,
key: (name, arity),
expanded_vars,
supp_vars
}
}
(HeapCellValueTag::Atom, (name, arity)) => {
debug_assert_eq!(arity, 0);
let h = self.machine_st.heap.len();
self.machine_st.heap.push(goal);
GoalAnalysisResult {
is_simple_goal: true,
goal: str_loc_as_cell!(h),
key: (name, 0),
expanded_vars: IndexSet::with_hasher(FxBuildHasher::default()),
supp_vars,
}
}
(HeapCellValueTag::Char, c) => {
let name = self.machine_st.atom_tbl.build_with(&c.to_string());
let h = self.machine_st.heap.len();
self.machine_st.heap.push(atom_as_cell!(name));
GoalAnalysisResult {
is_simple_goal: true,
goal: str_loc_as_cell!(h),
key: (name, 0),
expanded_vars: IndexSet::with_hasher(FxBuildHasher::default()),
supp_vars,
}
}
_ => {
self.machine_st.fail = true;
return Ok(());
}
);
if result.key.0 == atom!(":") {
self.machine_st.fail = true;
return Ok(());
}
let expanded_term = if result.is_simple_goal {
let idx = self.get_or_insert_qualified_code_index(module_name, result.key);
self.machine_st.heap.push(untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx)));
result.goal
} else {
// all supp_vars must appear later!
let vars = IndexSet::<HeapCellValue, BuildHasherDefault<FxHasher>>::from_iter(
result.expanded_vars.difference(&result.supp_vars).cloned()
);
let vars: Vec<_> = vars
.union(&result.supp_vars) // difference + union does not cancel.
.map(|v| Term::Var(Cell::default(), Rc::new(format!("_{}", v.get_value()))))
.collect();
let helper_clause_loc = self.code.len();
match self.compile_standalone_clause(temp_v!(1), &vars) {
Err(e) => {
let err = self.machine_st.session_error(e);
let stub = functor_stub(atom!("call"), result.key.1);
return Err(self.machine_st.error_form(err, stub));
}
Ok(()) => {
let h = self.machine_st.heap.len();
self.machine_st.heap.push(atom_as_cell!(atom!("$aux"), 0));
for value in result.expanded_vars.difference(&result.supp_vars).cloned() {
self.machine_st.heap.push(value);
}
let anon_str_arity = self.machine_st.heap.len() - h - 1;
self.machine_st.heap[h] = atom_as_cell!(atom!("$aux"), anon_str_arity);
let idx = CodeIndex::new(
IndexPtr::index(helper_clause_loc),
&mut self.machine_st.arena,
);
self.machine_st.heap.push(untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx)));
str_loc_as_cell!(h)
}
}
};
let truncated_goal = self.machine_st.registers[3];
unify!(&mut self.machine_st, expanded_term, truncated_goal);
Ok(())
}
#[inline(always)]
pub(crate) fn is_expanded_or_inlined(&mut self) {
let (_module_loc, qualified_goal) = self.machine_st.strip_module(
self.machine_st.registers[1],
empty_list_as_cell!(),
);
if HeapCellValueTag::Str == qualified_goal.get_tag() {
let s = qualified_goal.get_value();
let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
.get_name_and_arity();
if name == atom!("$call") {
return;
}
if self.machine_st.heap.len() > s + 1 + arity {
let idx_cell = self.machine_st.heap[s + 1 + arity];
if HeapCellValueTag::Cons == idx_cell.get_tag() {
match_untyped_arena_ptr!(cell_as_untyped_arena_ptr!(idx_cell),
(ArenaHeaderTag::IndexPtr, _ip) => {
return;
}
_ => {
}
);
}
}
}
self.machine_st.fail = true;
}
#[inline(always)]
pub(crate) fn prepare_call_clause(&mut self, arity: usize) -> CallResult {
let (module_loc, qualified_goal) = self.machine_st.strip_module(
@@ -1391,6 +1723,19 @@ impl Machine {
unify!(self.machine_st, self.machine_st.registers[2], list_loc_as_cell!(h));
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
.get_name_and_arity();
if arity == 0 {
self.machine_st.unify_complete_string(
name,
self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
);
} else {
self.machine_st.fail = true;
}
}
(HeapCellValueTag::Atom, (name, arity)) => {
if arity == 0 {
self.machine_st.unify_complete_string(
@@ -1454,6 +1799,20 @@ impl Machine {
self.machine_st.fail = true;
}
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
.get_name_and_arity();
if arity == 0 {
let iter = name.chars()
.map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64)));
let h = iter_to_heap_list(&mut self.machine_st.heap, iter);
unify!(self.machine_st, heap_loc_as_cell!(h), self.machine_st.registers[2]);
} else {
self.machine_st.fail = true;
}
}
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
let stub_gen = || functor_stub(atom!("atom_codes"), 2);
@@ -1482,6 +1841,17 @@ impl Machine {
let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
let len: i64 = read_heap_cell!(a1,
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
.get_name_and_arity();
if arity == 0 {
name.chars().count() as i64
} else {
self.machine_st.fail = true;
return;
}
}
(HeapCellValueTag::Atom, (name, arity)) => {
if arity == 0 {
name.chars().count() as i64
@@ -2019,6 +2389,13 @@ impl Machine {
(HeapCellValueTag::Atom, (name, _arity)) => {
name.as_char().unwrap()
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
name.as_char().unwrap()
}
(HeapCellValueTag::Char, c) => {
c
}
@@ -2080,6 +2457,13 @@ impl Machine {
(HeapCellValueTag::Atom, (name, _arity)) => {
name.as_char().unwrap()
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
name.as_char().unwrap()
}
_ => {
unreachable!()
}
@@ -2985,7 +3369,7 @@ impl Machine {
}
#[inline(always)]
pub(crate) fn delete_head_attribute(&mut self) {
pub(crate) fn delete_head_attribute(&mut self) {
let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
debug_assert_eq!(addr.get_tag(), HeapCellValueTag::AttrVar);
@@ -3016,18 +3400,48 @@ impl Machine {
&mut self,
narity: usize,
) -> Result<(Atom, PredicateKey), MachineStub> {
let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(
self.machine_st.registers[1 + narity]
)));
let module_name = self.machine_st.store(self.machine_st.deref(
self.machine_st.registers[1]
));
let module_name = read_heap_cell!(module_name,
(HeapCellValueTag::Atom, (name, _arity)) => {
debug_assert_eq!(_arity, 0);
name
}
(HeapCellValueTag::Str, s) => {
let (module_name, _arity) = cell_as_atom_cell!(self.machine_st.heap[s])
.get_name_and_arity();
debug_assert_eq!(_arity, 0);
module_name
}
_ if module_name.is_var() => {
atom!("user")
}
_ => {
unreachable!()
}
);
let goal = self.machine_st.store(self.machine_st.deref(
self.machine_st.registers[2 + narity]
self.machine_st.registers[2]
));
let (name, arity, s) = self.machine_st.setup_call_n_init_goal_info(goal, narity)?;
for i in (arity + 1..arity + narity + 1).rev() {
self.machine_st.registers[i] = self.machine_st.registers[i - arity];
match arity.cmp(&2) {
Ordering::Less => {
for i in arity + 1..arity + narity + 1 {
self.machine_st.registers[i] = self.machine_st.registers[i + 2 - arity];
}
}
Ordering::Greater => {
for i in (arity + 1..arity + narity + 1).rev() {
self.machine_st.registers[i] = self.machine_st.registers[i + 2 - arity];
}
}
Ordering::Equal => {}
}
for i in 1..arity + 1 {
@@ -3122,6 +3536,9 @@ impl Machine {
(HeapCellValueTag::Atom, (name, _arity)) => {
name
}
(HeapCellValueTag::Str, s) => {
cell_as_atom!(self.machine_st.heap[s])
}
(HeapCellValueTag::Char, c) => {
self.machine_st.atom_tbl.build_with(&c.to_string())
}
@@ -3544,6 +3961,9 @@ impl Machine {
(HeapCellValueTag::Atom, (name, _arity)) => {
name
}
(HeapCellValueTag::Str, s) => {
cell_as_atom!(self.machine_st.heap[s])
}
_ => {
unreachable!()
}
@@ -3906,7 +4326,7 @@ impl Machine {
let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
.get_name_and_arity();
let ct = ClauseType::from(name, arity);
let ct = ClauseType::from(name, arity, &mut self.machine_st.arena);
if ct.is_inlined() || ct.is_builtin() {
true
@@ -3917,10 +4337,10 @@ impl Machine {
module_name,
)
.map(|index| index.get())
.unwrap_or(IndexPtr::DynamicUndefined);
.unwrap_or(IndexPtr::dynamic_undefined());
match index {
IndexPtr::DynamicUndefined | IndexPtr::Undefined => false,
match index.tag() {
IndexPtrTag::DynamicUndefined | IndexPtrTag::Undefined => false,
_ => true,
}
}
@@ -3928,7 +4348,7 @@ impl Machine {
(HeapCellValueTag::Atom, (name, arity)) => {
debug_assert_eq!(arity, 0);
let ct = ClauseType::from(name, 0);
let ct = ClauseType::from(name, 0, &mut self.machine_st.arena);
if ct.is_inlined() || ct.is_builtin() {
true
@@ -3939,10 +4359,10 @@ impl Machine {
module_name,
)
.map(|index| index.get())
.unwrap_or(IndexPtr::DynamicUndefined);
.unwrap_or(IndexPtr::dynamic_undefined());
match index {
IndexPtr::DynamicUndefined => false,
match index.tag() {
IndexPtrTag::DynamicUndefined => false,
_ => true,
}
}
@@ -4208,7 +4628,9 @@ impl Machine {
LOC_INIT.call_once(|| {
if let Some(builtins) = self.indices.modules.get(&atom!("builtins")) {
match builtins.code_dir.get(&(atom!("staggered_sc"), 2)).map(|cell| cell.get()) {
Some(IndexPtr::Index(p)) => {
Some(ip) if ip.tag() == IndexPtrTag::Index => {
let p = ip.p() as usize;
match &self.code[p] {
&Instruction::TryMeElse(o) => {
SEMICOLON_SECOND_BRANCH_LOC = p + o;
@@ -4253,30 +4675,40 @@ impl Machine {
pub(crate) fn next_ep(&mut self) {
let first_arg = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
let next_ep_atom = |machine_st: &mut MachineState, name, arity| {
debug_assert_eq!(name, atom!("first"));
debug_assert_eq!(arity, 0);
if machine_st.e == 0 {
machine_st.fail = true;
return;
}
let and_frame = machine_st.stack.index_and_frame(machine_st.e);
let cp = and_frame.prelude.cp - 1;
let e = and_frame.prelude.e;
let e = Fixnum::build_with(i64::try_from(e).unwrap());
let p = str_loc_as_cell!(machine_st.heap.len());
machine_st.heap.extend(functor!(atom!("dir_entry"), [fixnum(cp)]));
machine_st.unify_fixnum(e, machine_st.registers[2]);
if !machine_st.fail {
unify!(machine_st, p, machine_st.registers[3]);
}
};
read_heap_cell!(first_arg,
(HeapCellValueTag::Atom, (name, arity)) => {
debug_assert_eq!(name, atom!("first"));
debug_assert_eq!(arity, 0);
next_ep_atom(&mut self.machine_st, name, arity);
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
.get_name_and_arity();
if self.machine_st.e == 0 {
self.machine_st.fail = true;
return;
}
let and_frame = self.machine_st.stack.index_and_frame(self.machine_st.e);
let cp = and_frame.prelude.cp - 1;
let e = and_frame.prelude.e;
let e = Fixnum::build_with(i64::try_from(e).unwrap());
let p = str_loc_as_cell!(self.machine_st.heap.len());
self.machine_st.heap.extend(functor!(atom!("dir_entry"), [fixnum(cp)]));
self.machine_st.unify_fixnum(e, self.machine_st.registers[2]);
if !self.machine_st.fail {
unify!(self.machine_st, p, self.machine_st.registers[3]);
}
next_ep_atom(&mut self.machine_st, name, arity);
}
(HeapCellValueTag::Fixnum, n) => {
let e = n.get_num() as usize;
@@ -4346,6 +4778,13 @@ impl Machine {
debug_assert_eq!(arity, 0);
self.machine_st.fail = non_quoted_token(name.as_str().chars());
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
self.machine_st.fail = non_quoted_token(name.as_str().chars());
}
_ => {
self.machine_st.fail = true;
}
@@ -4480,6 +4919,13 @@ impl Machine {
debug_assert_eq!(arity, 0);
name
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
name
}
_ => {
self.machine_st.atom_tbl.build_with(&match Number::try_from(port) {
Ok(Number::Fixnum(n)) => n.get_num().to_string(),
@@ -5011,26 +5457,9 @@ impl Machine {
return;
}
let mut seen_set = IndexSet::new();
let mut seen_set = IndexSet::with_hasher(FxBuildHasher::default());
{
let mut iter = stackful_preorder_iter(&mut self.machine_st.heap, stored_v);
while let Some(value) = iter.next() {
let value = unmark_cell_bits!(value);
if value.is_var() {
let value = unmark_cell_bits!(heap_bound_store(
iter.heap,
heap_bound_deref(iter.heap, value)
));
if value.is_var() {
seen_set.insert(value);
}
}
}
}
self.machine_st.variable_set(&mut seen_set, stored_v);
let outcome = heap_loc_as_cell!(
iter_to_heap_list(&mut self.machine_st.heap, seen_set.into_iter())
@@ -5271,9 +5700,15 @@ impl Machine {
};
let result = printer.print().result();
let chars = put_complete_string(&mut self.machine_st.heap, &result, &mut self.machine_st.atom_tbl);
let chars = put_complete_string(
&mut self.machine_st.heap,
&result,
&mut self.machine_st.atom_tbl,
);
let result_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
let result_addr = self.machine_st.store(self.machine_st.deref(
self.machine_st.registers[1]
));
if let Some(var) = result_addr.as_var() {
self.machine_st.bind(var, chars);