Merge pull request #2439 from Skgland/miri

Some cleanup and miri fixes
This commit is contained in:
Mark Thom
2024-07-22 13:40:57 -06:00
committed by GitHub
38 changed files with 747 additions and 840 deletions

View File

@@ -641,10 +641,17 @@ pub(crate) fn shr(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, M
let n1_i = n1.get_num();
let n2_i = n2.get_num();
// FIXME(arithmetic_overflow)
// what should this do for too large n2,
// - logical right shift should probably turn to 0
// - arithmetic right shift should maybe differ for negative numbers
//
// note: negaitve n2 is already handled above
#[allow(arithmetic_overflow)]
if let Ok(n2) = usize::try_from(n2_i) {
Ok(Number::arena_from(n1_i >> n2, arena))
} else {
Ok(Number::arena_from(n1_i >> usize::max_value(), arena))
Ok(Number::arena_from(n1_i >> usize::MAX, arena))
}
}
(Number::Fixnum(n1), Number::Integer(n2)) => {
@@ -654,25 +661,19 @@ pub(crate) fn shr(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, M
match result {
Ok(n2) => Ok(Number::arena_from(n1 >> n2, arena)),
Err(_) => Ok(Number::arena_from(n1 >> usize::max_value(), arena)),
Err(_) => Ok(Number::arena_from(n1 >> usize::MAX, arena)),
}
}
(Number::Integer(n1), Number::Fixnum(n2)) => match usize::try_from(n2.get_num()) {
Ok(n2) => Ok(Number::arena_from(Integer::from(&*n1 >> n2), arena)),
_ => Ok(Number::arena_from(
Integer::from(&*n1 >> usize::max_value()),
arena,
)),
_ => Ok(Number::arena_from(Integer::from(&*n1 >> usize::MAX), arena)),
},
(Number::Integer(n1), Number::Integer(n2)) => {
let result: Result<usize, _> = (&*n2).try_into();
match result {
Ok(n2) => Ok(Number::arena_from(Integer::from(&*n1 >> n2), arena)),
Err(_) => Ok(Number::arena_from(
Integer::from(&*n1 >> usize::max_value()),
arena,
)),
Err(_) => Ok(Number::arena_from(Integer::from(&*n1 >> usize::MAX), arena)),
}
}
(Number::Integer(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)),
@@ -700,7 +701,7 @@ pub(crate) fn shl(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, M
Ok(Number::arena_from(n1_i << n2, arena))
} else {
let n1 = Integer::from(n1_i);
Ok(Number::arena_from(n1 << usize::max_value(), arena))
Ok(Number::arena_from(n1 << usize::MAX, arena))
}
}
(Number::Fixnum(n1), Number::Integer(n2)) => {
@@ -708,22 +709,16 @@ pub(crate) fn shl(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, M
match (&*n2).try_into() as Result<usize, _> {
Ok(n2) => Ok(Number::arena_from(n1 << n2, arena)),
_ => Ok(Number::arena_from(n1 << usize::max_value(), arena)),
_ => Ok(Number::arena_from(n1 << usize::MAX, arena)),
}
}
(Number::Integer(n1), Number::Fixnum(n2)) => match usize::try_from(n2.get_num()) {
Ok(n2) => Ok(Number::arena_from(Integer::from(&*n1 << n2), arena)),
_ => Ok(Number::arena_from(
Integer::from(&*n1 << usize::max_value()),
arena,
)),
_ => Ok(Number::arena_from(Integer::from(&*n1 << usize::MAX), arena)),
},
(Number::Integer(n1), Number::Integer(n2)) => match (&*n2).try_into() as Result<usize, _> {
Ok(n2) => Ok(Number::arena_from(Integer::from(&*n1 << n2), arena)),
_ => Ok(Number::arena_from(
Integer::from(&*n1 << usize::max_value()),
arena,
)),
_ => Ok(Number::arena_from(Integer::from(&*n1 << usize::MAX), arena)),
},
(Number::Integer(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)),
(Number::Fixnum(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)),
@@ -1420,7 +1415,6 @@ mod tests {
use crate::machine::mock_wam::*;
#[test]
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
fn arith_eval_by_metacall_tests() {
let mut wam = MachineState::new();
let mut op_dir = default_op_dir();

View File

@@ -398,7 +398,6 @@ mod tests {
use crate::machine::mock_wam::*;
#[test]
#[cfg_attr(miri, ignore = "blocked on atom_table.rs UB")]
fn copier_tests() {
let mut wam = MockWAM::new();

View File

@@ -369,7 +369,6 @@ mod tests {
use crate::machine::mock_wam::*;
#[test]
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
fn heap_marking_tests() {
let mut wam = MockWAM::new();

View File

@@ -69,8 +69,8 @@ impl TryFrom<HeapCellValue> for Literal {
(ArenaHeaderTag::Rational, n) => {
Ok(Literal::Rational(n))
}
(ArenaHeaderTag::IndexPtr, _ip) => {
Ok(Literal::CodeIndex(CodeIndex::from(cons_ptr)))
(ArenaHeaderTag::IndexPtr, ip) => {
Ok(Literal::CodeIndex(CodeIndex::from(ip)))
}
_ => {
Err(())

View File

@@ -191,7 +191,7 @@ impl Machine {
printer.quoted = true;
printer.max_depth = 1000; // NOTE: set this to 0 for unbounded depth
printer.double_quotes = true;
printer.var_names = var_names.clone();
printer.var_names.clone_from(&var_names);
let outputter = printer.print();
@@ -238,7 +238,7 @@ mod tests {
use crate::machine::{QueryMatch, QueryResolution, Value};
#[test]
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
#[cfg_attr(miri, ignore = "it takes too long to run")]
fn programatic_query() {
let mut machine = Machine::new_lib();
@@ -278,7 +278,7 @@ mod tests {
}
#[test]
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
#[cfg_attr(miri, ignore = "it takes too long to run")]
fn failing_query() {
let mut machine = Machine::new_lib();
let query = String::from(r#"triple("a",P,"b")."#);
@@ -292,7 +292,7 @@ mod tests {
}
#[test]
#[cfg_attr(miri, ignore)]
#[cfg_attr(miri, ignore = "it takes too long to run")]
fn complex_results() {
let mut machine = Machine::new_lib();
machine.load_module_string(
@@ -349,7 +349,7 @@ mod tests {
}
#[test]
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
#[cfg_attr(miri, ignore = "it takes too long to run")]
fn empty_predicate() {
let mut machine = Machine::new_lib();
machine.load_module_string(
@@ -365,7 +365,7 @@ mod tests {
}
#[test]
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
#[cfg_attr(miri, ignore = "it takes too long to run")]
fn list_results() {
let mut machine = Machine::new_lib();
machine.load_module_string(
@@ -394,7 +394,7 @@ mod tests {
}
#[test]
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
#[cfg_attr(miri, ignore = "it takes too long to run")]
fn consult() {
let mut machine = Machine::new_lib();
@@ -453,7 +453,7 @@ mod tests {
}
#[test]
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
#[cfg_attr(miri, ignore = "it takes too long to run")]
fn integration_test() {
let mut machine = Machine::new_lib();
@@ -488,19 +488,15 @@ mod tests {
} else if let Some(result) = block.strip_prefix("result") {
i += 1;
if let Some(Ok(ref last_result)) = last_result {
println!(
"\n\n=====Result No. {}=======\n{}\n===============",
i,
last_result.to_string().trim()
);
assert_eq!(last_result.to_string().trim(), result.to_string().trim(),)
println!("\n\n=====Result No. {i}=======\n{last_result}\n===============");
assert_eq!(last_result.to_string(), result.to_string().trim(),)
}
}
}
}
#[test]
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
#[cfg_attr(miri, ignore = "it takes too long to run")]
fn findall() {
let mut machine = Machine::new_lib();
@@ -533,6 +529,7 @@ mod tests {
}
#[test]
#[cfg_attr(miri, ignore = "it takes too long to run")]
fn dont_return_partial_matches() {
let mut machine = Machine::new_lib();
@@ -556,6 +553,7 @@ mod tests {
}
#[test]
#[cfg_attr(miri, ignore = "it takes too long to run")]
fn dont_return_partial_matches_without_discountiguous() {
let mut machine = Machine::new_lib();
@@ -587,6 +585,7 @@ mod tests {
}
#[test]
#[cfg_attr(miri, ignore = "it takes too long to run")]
fn non_existent_predicate_should_not_cause_panic_when_other_predicates_are_defined() {
let mut machine = Machine::new_lib();
@@ -611,6 +610,7 @@ mod tests {
}
#[test]
#[cfg_attr(miri, ignore = "it takes too long to run")]
fn issue_2341() {
let mut machine = Machine::new_lib();

View File

@@ -9,7 +9,6 @@ use crate::parser::ast::*;
use fxhash::FxBuildHasher;
use indexmap::IndexSet;
pub use ref_thread_local::RefThreadLocal;
use std::collections::VecDeque;
use std::fs::File;
@@ -1176,7 +1175,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
ListingSource::File(filename, path_buf),
)
}
ModuleSource::Library(library) => match LIBRARIES.borrow().get(&*library.as_str()) {
ModuleSource::Library(library) => match libraries::get(&library.as_str()) {
Some(code) => {
if let Some(module) = self.wam_prelude.indices.modules.get(&library) {
if let ListingSource::DynamicallyGenerated = &module.listing_src {
@@ -1257,7 +1256,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
ListingSource::File(filename, path_buf),
)
}
ModuleSource::Library(library) => match LIBRARIES.borrow().get(&*library.as_str()) {
ModuleSource::Library(library) => match libraries::get(&library.as_str()) {
Some(code) => {
if self.wam_prelude.indices.modules.contains_key(&library) {
return self.import_qualified_module(library, exports);

View File

@@ -304,11 +304,15 @@ impl<'a> LoadState<'a> for LiveLoadAndMachineState<'a> {
#[inline(always)]
fn evacuate(mut loader: Loader<'a, Self>) -> Result<Self::Evacuable, SessionError> {
loader
.payload
.load_state
.set_tag(ArenaHeaderTag::InactiveLoadState);
Ok(loader.payload.load_state)
if loader.payload.load_state.get_tag() != ArenaHeaderTag::Dropped {
loader
.payload
.load_state
.set_tag(ArenaHeaderTag::InactiveLoadState);
Ok(loader.payload.load_state)
} else {
unreachable!("we never evacuate after dropping")
}
}
#[inline(always)]
@@ -319,7 +323,7 @@ impl<'a> LoadState<'a> for LiveLoadAndMachineState<'a> {
#[inline(always)]
fn reset_machine(loader: &mut Loader<'a, Self>) {
if loader.payload.load_state.get_tag() != ArenaHeaderTag::Dropped {
loader.payload.load_state.set_tag(ArenaHeaderTag::Dropped);
loader.payload.load_state.drop_payload();
loader.reset_machine();
}
}
@@ -353,7 +357,7 @@ impl<'a> LoadState<'a> for LiveLoadAndMachineState<'a> {
#[inline]
fn err_on_builtin_module_overwrite(module_name: Atom) -> Result<(), SessionError> {
if LIBRARIES.borrow().contains_key(&*module_name.as_str()) {
if libraries::contains(&module_name.as_str()) {
Err(SessionError::CannotOverwriteBuiltInModule(module_name))
} else {
Ok(())
@@ -1757,7 +1761,7 @@ impl Machine {
#[inline]
pub(crate) fn push_load_state_payload(&mut self) {
let payload = arena_alloc!(
let payload: TypedArenaPtr<LiveLoadState> = arena_alloc!(
LoadStatePayload::new(self.code.len(), LiveTermStream::new(ListingSource::User),),
&mut self.machine_st.arena
);
@@ -1784,11 +1788,8 @@ impl Machine {
(HeapCellValueTag::Cons, cons_ptr) => {
match_untyped_arena_ptr!(cons_ptr,
(ArenaHeaderTag::LiveLoadState, payload) => {
unsafe {
std::ptr::drop_in_place(
payload.as_ptr() as *mut LiveLoadState,
);
}
let mut payload = payload;
payload.drop_payload()
}
_ => {}
);

View File

@@ -1,3 +1,5 @@
#![allow(clippy::new_without_default)] // annotating structs annotated with #[bitfield] doesn't work
use crate::parser::ast::*;
use crate::arena::*;
@@ -157,13 +159,6 @@ impl From<CodeIndex> for UntypedArenaPtr {
}
}
impl From<UntypedArenaPtr> for CodeIndex {
#[inline(always)]
fn from(ptr: UntypedArenaPtr) -> CodeIndex {
CodeIndex(TypedArenaPtr::new(ptr.get_ptr() as *mut IndexPtr))
}
}
impl From<TypedArenaPtr<IndexPtr>> for CodeIndex {
#[inline(always)]
fn from(ptr: TypedArenaPtr<IndexPtr>) -> CodeIndex {

View File

@@ -679,15 +679,13 @@ impl MachineState {
indices: &mut IndexStore,
) -> CallResult {
if let Stream::Readline(ptr) = stream {
unsafe {
let readline = ptr.as_ptr().as_mut().unwrap();
readline.set_atoms_for_completion(&self.atom_tbl);
return self.read_term(
stream,
indices,
MachineState::read_term_from_user_input_eof_handler,
);
}
let readline = unsafe { ptr.as_ptr().as_mut() }.unwrap();
readline.set_atoms_for_completion(&self.atom_tbl);
return self.read_term(
stream,
indices,
MachineState::read_term_from_user_input_eof_handler,
);
}
if let Stream::Byte(_) = stream {

View File

@@ -260,7 +260,6 @@ mod tests {
use super::*;
#[test]
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
fn unify_tests() {
let mut wam = MachineState::new();
let mut op_dir = default_op_dir();
@@ -482,7 +481,6 @@ mod tests {
}
#[test]
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
fn test_unify_with_occurs_check() {
let mut wam = MachineState::new();
let mut op_dir = default_op_dir();

View File

@@ -60,6 +60,7 @@ use std::env;
use std::io::Read;
use std::path::PathBuf;
use std::sync::atomic::AtomicBool;
use std::sync::OnceLock;
use self::config::MachineConfig;
use self::parsed_results::*;
@@ -110,10 +111,34 @@ impl LoadContext {
#[inline]
fn current_dir() -> PathBuf {
env::current_dir().unwrap_or(PathBuf::from("./"))
if !cfg!(miri) {
env::current_dir().unwrap_or(PathBuf::from("./"))
} else {
PathBuf::from("./")
}
}
include!(concat!(env!("OUT_DIR"), "/libraries.rs"));
mod libraries {
include!(concat!(env!("OUT_DIR"), "/libraries.rs"));
pub(crate) fn contains(name: &str) -> bool {
LIBRARIES.with(|libs| libs.contains_key(name))
}
pub(crate) fn get(name: &str) -> Option<&'static str> {
LIBRARIES.with(|libs| libs.get(name).copied())
}
#[cfg(test)]
std::thread_local! {
#[allow(dead_code)]
static LIBRARIES2 : IndexMap<&'static str, &'static str> = {
let mut m = IndexMap::new();
m.insert("test", "test2");
m
};
}
}
pub static BREAK_FROM_DISPATCH_LOOP_LOC: usize = 0;
pub static INSTALL_VERIFY_ATTR_INTERRUPT: usize = 1;
@@ -448,8 +473,6 @@ impl Machine {
#[allow(clippy::new_without_default)]
pub fn new(config: MachineConfig) -> Self {
use ref_thread_local::RefThreadLocal;
let args = MachineArgs::new();
let mut machine_st = MachineState::new();
@@ -488,7 +511,8 @@ impl Machine {
bootstrapping_compile(
Stream::from_static_string(
LIBRARIES.borrow()["ops_and_meta_predicates"],
libraries::get("ops_and_meta_predicates")
.expect("library ops_and_meta_predicates should exist"),
&mut wam.machine_st.arena,
),
&mut wam,
@@ -500,7 +524,10 @@ impl Machine {
.unwrap();
bootstrapping_compile(
Stream::from_static_string(LIBRARIES.borrow()["builtins"], &mut wam.machine_st.arena),
Stream::from_static_string(
libraries::get("builtins").expect("library builtins should exist"),
&mut wam.machine_st.arena,
),
&mut wam,
ListingSource::from_file_and_path(atom!("builtins.pl"), lib_path.clone()),
)
@@ -1235,33 +1262,25 @@ impl Machine {
#[inline(always)]
fn run_cleaners(&mut self) -> bool {
use std::sync::Once;
static CLEANER_INIT: OnceLock<(usize, usize)> = OnceLock::new();
static CLEANER_INIT: Once = Once::new();
let (r_c_w_h, r_c_wo_h) = *CLEANER_INIT.get_or_init(|| {
let r_c_w_h_atom = atom!("run_cleaners_with_handling");
let r_c_wo_h_atom = atom!("run_cleaners_without_handling");
let iso_ext = atom!("iso_ext");
static mut RCWH: usize = 0;
static mut RCWOH: usize = 0;
let (r_c_w_h, r_c_wo_h) = unsafe {
CLEANER_INIT.call_once(|| {
let r_c_w_h_atom = atom!("run_cleaners_with_handling");
let r_c_wo_h_atom = atom!("run_cleaners_without_handling");
let iso_ext = atom!("iso_ext");
RCWH = self
.indices
.get_predicate_code_index(r_c_w_h_atom, 0, iso_ext)
.and_then(|item| item.local())
.unwrap();
RCWOH = self
.indices
.get_predicate_code_index(r_c_wo_h_atom, 1, iso_ext)
.and_then(|item| item.local())
.unwrap();
});
(RCWH, RCWOH)
};
let r_c_w_h = self
.indices
.get_predicate_code_index(r_c_w_h_atom, 0, iso_ext)
.and_then(|item| item.local())
.unwrap();
let r_c_wo_h = self
.indices
.get_predicate_code_index(r_c_wo_h_atom, 1, iso_ext)
.and_then(|item| item.local())
.unwrap();
(r_c_w_h, r_c_wo_h)
});
if let Some(&(_, b_cutoff, prev_block)) = self.machine_st.cont_pts.last() {
if self.machine_st.b < b_cutoff {

View File

@@ -3,6 +3,8 @@ use dashu::*;
use ordered_float::OrderedFloat;
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::fmt::Display;
use std::fmt::Write;
pub type QueryResult = Result<QueryResolution, String>;
@@ -13,17 +15,21 @@ pub enum QueryResolution {
Matches(Vec<QueryMatch>),
}
pub fn prolog_value_to_json_string(value: Value) -> String {
pub fn write_prolog_value_as_json<W: Write>(
writer: &mut W,
value: &Value,
) -> Result<(), std::fmt::Error> {
match value {
Value::Integer(i) => format!("{}", i),
Value::Float(f) => format!("{}", f),
Value::Rational(r) => format!("{}", r),
Value::Atom(a) => format!("{}", a.as_str()),
Value::Integer(i) => write!(writer, "{}", i),
Value::Float(f) => write!(writer, "{}", f),
Value::Rational(r) => write!(writer, "{}", r),
Value::Atom(a) => writer.write_str(&a.as_str()),
Value::String(s) => {
if let Err(_e) = serde_json::from_str::<serde_json::Value>(s.as_str()) {
//treat as string literal
//escape double quotes
format!(
write!(
writer,
"\"{}\"",
s.replace('\"', "\\\"")
.replace('\n', "\\n")
@@ -32,60 +38,71 @@ pub fn prolog_value_to_json_string(value: Value) -> String {
)
} else {
//return valid json string
s
writer.write_str(s)
}
}
Value::List(l) => {
let mut string_result = "[".to_string();
for (i, v) in l.iter().enumerate() {
if i > 0 {
string_result.push(',');
writer.write_char('[')?;
if let Some((first, rest)) = l.split_first() {
write_prolog_value_as_json(writer, first)?;
for other in rest {
writer.write_char(',')?;
write_prolog_value_as_json(writer, other)?;
}
string_result.push_str(&prolog_value_to_json_string(v.clone()));
}
string_result.push(']');
string_result
writer.write_char(']')
}
Value::Structure(s, l) => {
let mut string_result = format!("\"{}\":[", s.as_str());
for (i, v) in l.iter().enumerate() {
if i > 0 {
string_result.push(',');
write!(writer, "\"{}\":[", s.as_str())?;
if let Some((first, rest)) = l.split_first() {
write_prolog_value_as_json(writer, first)?;
for other in rest {
writer.write_char(',')?;
write_prolog_value_as_json(writer, other)?;
}
string_result.push_str(&prolog_value_to_json_string(v.clone()));
}
string_result.push(']');
string_result
writer.write_char(']')
}
_ => "null".to_string(),
_ => writer.write_str("null"),
}
}
fn prolog_match_to_json_string(query_match: &QueryMatch) -> String {
let mut string_result = "{".to_string();
for (i, (k, v)) in query_match.bindings.iter().enumerate() {
if i > 0 {
string_result.push(',');
fn write_prolog_match_as_json<W: std::fmt::Write>(
writer: &mut W,
query_match: &QueryMatch,
) -> Result<(), std::fmt::Error> {
writer.write_char('{')?;
let mut iter = query_match.bindings.iter();
if let Some((k, v)) = iter.next() {
write!(writer, "\"{k}\":")?;
write_prolog_value_as_json(writer, v)?;
for (k, v) in iter {
write!(writer, ",\"{k}\":")?;
write_prolog_value_as_json(writer, v)?;
}
string_result.push_str(&format!(
"\"{}\":{}",
k,
prolog_value_to_json_string(v.clone())
));
}
string_result.push('}');
string_result
writer.write_char('}')
}
impl ToString for QueryResolution {
fn to_string(&self) -> String {
impl Display for QueryResolution {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
QueryResolution::True => "true".to_string(),
QueryResolution::False => "false".to_string(),
QueryResolution::True => f.write_str("true"),
QueryResolution::False => f.write_str("false"),
QueryResolution::Matches(matches) => {
let matches_json: Vec<String> =
matches.iter().map(prolog_match_to_json_string).collect();
format!("[{}]", matches_json.join(","))
f.write_char('[')?;
if let Some((first, rest)) = matches.split_first() {
write_prolog_match_as_json(f, first)?;
for other in rest {
f.write_char(',')?;
write_prolog_match_as_json(f, other)?;
}
}
f.write_char(']')
}
}
}

View File

@@ -801,7 +801,7 @@ mod test {
use crate::machine::mock_wam::*;
#[test]
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
#[cfg_attr(miri, ignore = "it takes too long to run")]
fn pstr_iter_tests() {
let mut wam = MockWAM::new();

View File

@@ -15,7 +15,9 @@ impl RawBlockTraits for Stack {
#[inline]
fn align() -> usize {
mem::align_of::<HeapCellValue>()
mem::align_of::<OrFrame>()
.max(mem::align_of::<AndFrame>())
.max(mem::align_of::<HeapCellValue>())
}
}
@@ -281,7 +283,6 @@ mod tests {
use crate::machine::mock_wam::*;
#[test]
#[cfg_attr(miri, ignore)]
fn stack_tests() {
let mut wam = MockWAM::new();

View File

@@ -324,6 +324,9 @@ impl Write for HttpWriteStream {
#[cfg(feature = "http")]
impl HttpWriteStream {
// TODO why is this suddenly dead code and should it be used somewhere?
// Should this be impl Drop for HttpWriteStream?
#[allow(dead_code)]
fn drop(&mut self) {
let headers = unsafe { std::mem::ManuallyDrop::take(&mut self.headers) };
let buffer = unsafe { std::mem::ManuallyDrop::take(&mut self.buffer) };
@@ -452,15 +455,34 @@ impl<T> DerefMut for StreamLayout<T> {
macro_rules! arena_allocated_impl_for_stream {
($stream_type:ty, $stream_tag:ident) => {
impl ArenaAllocated for StreamLayout<$stream_type> {
type PtrToAllocated = TypedArenaPtr<StreamLayout<$stream_type>>;
impl $crate::arena::AllocateInArena<$stream_tag> for StreamLayout<$stream_type> {
fn arena_allocate(self, arena: &mut Arena) -> TypedArenaPtr<$stream_tag> {
$stream_tag::alloc(arena, core::mem::ManuallyDrop::new(self))
}
}
gen_ptr_to_allocated!(StreamLayout<$stream_type>);
impl ArenaAllocated for $stream_tag {
type Payload = core::mem::ManuallyDrop<StreamLayout<$stream_type>>;
#[inline]
fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::$stream_tag
}
unsafe fn dealloc(ptr: std::ptr::NonNull<TypedAllocSlab<Self>>) {
let mut slab = unsafe { Box::from_raw(ptr.as_ptr()) };
match slab.tag() {
ArenaHeaderTag::$stream_tag => {
unsafe { std::mem::ManuallyDrop::drop(slab.payload()) };
}
ArenaHeaderTag::Dropped => {}
_ => {
unreachable!()
}
}
drop(slab);
}
}
};
}
@@ -482,26 +504,26 @@ arena_allocated_impl_for_stream!(StandardErrorStream, StandardErrorStream);
#[derive(Debug, Copy, Clone)]
pub enum Stream {
Byte(TypedArenaPtr<StreamLayout<CharReader<ByteStream>>>),
InputFile(TypedArenaPtr<StreamLayout<CharReader<InputFileStream>>>),
OutputFile(TypedArenaPtr<StreamLayout<OutputFileStream>>),
StaticString(TypedArenaPtr<StreamLayout<StaticStringStream>>),
NamedTcp(TypedArenaPtr<StreamLayout<CharReader<NamedTcpStream>>>),
Byte(TypedArenaPtr<ByteStream>),
InputFile(TypedArenaPtr<InputFileStream>),
OutputFile(TypedArenaPtr<OutputFileStream>),
StaticString(TypedArenaPtr<StaticStringStream>),
NamedTcp(TypedArenaPtr<NamedTcpStream>),
#[cfg(feature = "tls")]
NamedTls(TypedArenaPtr<StreamLayout<CharReader<NamedTlsStream>>>),
NamedTls(TypedArenaPtr<NamedTlsStream>),
#[cfg(feature = "http")]
HttpRead(TypedArenaPtr<StreamLayout<CharReader<HttpReadStream>>>),
HttpRead(TypedArenaPtr<HttpReadStream>),
#[cfg(feature = "http")]
HttpWrite(TypedArenaPtr<StreamLayout<CharReader<HttpWriteStream>>>),
HttpWrite(TypedArenaPtr<HttpWriteStream>),
Null(StreamOptions),
Readline(TypedArenaPtr<StreamLayout<ReadlineStream>>),
StandardOutput(TypedArenaPtr<StreamLayout<StandardOutputStream>>),
StandardError(TypedArenaPtr<StreamLayout<StandardErrorStream>>),
Readline(TypedArenaPtr<ReadlineStream>),
StandardOutput(TypedArenaPtr<StandardOutputStream>),
StandardError(TypedArenaPtr<StandardErrorStream>),
}
impl From<TypedArenaPtr<StreamLayout<ReadlineStream>>> for Stream {
impl From<TypedArenaPtr<ReadlineStream>> for Stream {
#[inline]
fn from(stream: TypedArenaPtr<StreamLayout<ReadlineStream>>) -> Stream {
fn from(stream: TypedArenaPtr<ReadlineStream>) -> Stream {
Stream::Readline(stream)
}
}
@@ -540,29 +562,27 @@ impl Stream {
))
}
pub fn from_tag(tag: ArenaHeaderTag, ptr: *const u8) -> Self {
pub fn from_tag(tag: ArenaHeaderTag, ptr: UntypedArenaPtr) -> Self {
match tag {
ArenaHeaderTag::ByteStream => Stream::Byte(TypedArenaPtr::new(ptr as *mut _)),
ArenaHeaderTag::InputFileStream => Stream::InputFile(TypedArenaPtr::new(ptr as *mut _)),
ArenaHeaderTag::OutputFileStream => {
Stream::OutputFile(TypedArenaPtr::new(ptr as *mut _))
}
ArenaHeaderTag::NamedTcpStream => Stream::NamedTcp(TypedArenaPtr::new(ptr as *mut _)),
ArenaHeaderTag::ByteStream => Stream::Byte(unsafe { ptr.as_typed_ptr() }),
ArenaHeaderTag::InputFileStream => Stream::InputFile(unsafe { ptr.as_typed_ptr() }),
ArenaHeaderTag::OutputFileStream => Stream::OutputFile(unsafe { ptr.as_typed_ptr() }),
ArenaHeaderTag::NamedTcpStream => Stream::NamedTcp(unsafe { ptr.as_typed_ptr() }),
#[cfg(feature = "tls")]
ArenaHeaderTag::NamedTlsStream => Stream::NamedTls(TypedArenaPtr::new(ptr as *mut _)),
ArenaHeaderTag::NamedTlsStream => Stream::NamedTls(unsafe { ptr.as_typed_ptr() }),
#[cfg(feature = "http")]
ArenaHeaderTag::HttpReadStream => Stream::HttpRead(TypedArenaPtr::new(ptr as *mut _)),
ArenaHeaderTag::HttpReadStream => Stream::HttpRead(unsafe { ptr.as_typed_ptr() }),
#[cfg(feature = "http")]
ArenaHeaderTag::HttpWriteStream => Stream::HttpWrite(TypedArenaPtr::new(ptr as *mut _)),
ArenaHeaderTag::ReadlineStream => Stream::Readline(TypedArenaPtr::new(ptr as *mut _)),
ArenaHeaderTag::HttpWriteStream => Stream::HttpWrite(unsafe { ptr.as_typed_ptr() }),
ArenaHeaderTag::ReadlineStream => Stream::Readline(unsafe { ptr.as_typed_ptr() }),
ArenaHeaderTag::StaticStringStream => {
Stream::StaticString(TypedArenaPtr::new(ptr as *mut _))
Stream::StaticString(unsafe { ptr.as_typed_ptr() })
}
ArenaHeaderTag::StandardOutputStream => {
Stream::StandardOutput(TypedArenaPtr::new(ptr as *mut _))
Stream::StandardOutput(unsafe { ptr.as_typed_ptr() })
}
ArenaHeaderTag::StandardErrorStream => {
Stream::StandardError(TypedArenaPtr::new(ptr as *mut _))
Stream::StandardError(unsafe { ptr.as_typed_ptr() })
}
ArenaHeaderTag::Dropped | ArenaHeaderTag::NullStream => {
Stream::Null(StreamOptions::default())
@@ -996,7 +1016,7 @@ impl Stream {
past_end_of_stream,
stream,
..
} = &mut **stream_layout;
} = &mut ***stream_layout;
stream
.get_mut()
@@ -1070,7 +1090,7 @@ impl Stream {
past_end_of_stream,
stream,
..
} = &mut **stream_layout;
} = &mut ***stream_layout;
let cursor_len = stream.get_ref().0.get_ref().len() as u64;
cursor_position(past_end_of_stream, &stream.get_ref().0, cursor_len)
@@ -1080,7 +1100,7 @@ impl Stream {
past_end_of_stream,
stream,
..
} = &mut **stream_layout;
} = &mut ***stream_layout;
let cursor_len = stream.stream.get_ref().len() as u64;
cursor_position(past_end_of_stream, &stream.stream, cursor_len)
@@ -1092,7 +1112,7 @@ impl Stream {
past_end_of_stream,
stream,
..
} = &mut **stream_layout;
} = &mut ***stream_layout;
match stream.get_ref().file.metadata() {
Ok(metadata) => {
@@ -1279,38 +1299,25 @@ impl Stream {
Stream::NamedTls(ref mut tls_stream) => tls_stream.inner_mut().tls_stream.shutdown(),
#[cfg(feature = "http")]
Stream::HttpRead(ref mut http_stream) => {
unsafe {
http_stream.set_tag(ArenaHeaderTag::Dropped);
std::ptr::drop_in_place(&mut http_stream.inner_mut().body_reader as *mut _);
}
http_stream.drop_payload();
Ok(())
}
#[cfg(feature = "http")]
Stream::HttpWrite(ref mut http_stream) => {
http_stream.inner_mut().drop();
unsafe {
http_stream.set_tag(ArenaHeaderTag::Dropped);
std::ptr::drop_in_place(&mut http_stream.inner_mut().buffer as *mut _);
}
Stream::HttpWrite(mut http_stream) => {
http_stream.drop_payload();
Ok(())
}
Stream::InputFile(mut file_stream) => {
// close the stream by dropping the inner File.
unsafe {
file_stream.set_tag(ArenaHeaderTag::Dropped);
std::ptr::drop_in_place(&mut file_stream.inner_mut().file as *mut _);
}
file_stream.drop_payload();
Ok(())
}
Stream::OutputFile(mut file_stream) => {
// close the stream by dropping the inner File.
unsafe {
file_stream.set_tag(ArenaHeaderTag::Dropped);
std::ptr::drop_in_place(&mut file_stream.file as *mut _);
}
file_stream.drop_payload();
Ok(())
}

View File

@@ -39,8 +39,6 @@ use ordered_float::OrderedFloat;
use fxhash::{FxBuildHasher, FxHasher};
use indexmap::IndexSet;
pub(crate) use ref_thread_local::RefThreadLocal;
use std::cell::Cell;
use std::cmp::Ordering;
use std::collections::BTreeSet;
@@ -103,6 +101,8 @@ use warp::hyper::{HeaderMap, Method};
#[cfg(feature = "http")]
use warp::{Buf, Filter};
use super::libraries;
#[cfg(feature = "repl")]
pub(crate) fn get_key() -> KeyEvent {
let key;
@@ -4513,7 +4513,8 @@ impl Machine {
});
let http_listener = HttpListener { incoming: rx };
let http_listener = arena_alloc!(http_listener, &mut self.machine_st.arena);
let http_listener: TypedArenaPtr<HttpListener> =
arena_alloc!(http_listener, &mut self.machine_st.arena);
let addr = self.deref_register(2);
self.machine_st.bind(
@@ -4578,7 +4579,7 @@ impl Machine {
self.indices.streams.insert(stream);
let stream = stream_as_cell!(stream);
let handle = arena_alloc!(request.response, &mut self.machine_st.arena);
let handle: TypedArenaPtr<HttpResponse> = arena_alloc!(request.response, &mut self.machine_st.arena);
self.machine_st.bind(method.as_var().unwrap(), atom_as_cell!(method_atom));
self.machine_st.bind(path.as_var().unwrap(), path_cell);
@@ -6510,32 +6511,33 @@ impl Machine {
format!("{}:{}", socket_atom.as_str(), port)
};
let (tcp_listener, port) = match TcpListener::bind(server_addr).map_err(|e| e.kind()) {
Ok(tcp_listener) => {
let port = tcp_listener.local_addr().map(|addr| addr.port()).ok();
let (tcp_listener, port): (TypedArenaPtr<TcpListener>, _) =
match TcpListener::bind(server_addr).map_err(|e| e.kind()) {
Ok(tcp_listener) => {
let port = tcp_listener.local_addr().map(|addr| addr.port()).ok();
if let Some(port) = port {
(
arena_alloc!(tcp_listener, &mut self.machine_st.arena),
port as usize,
)
} else {
if let Some(port) = port {
(
arena_alloc!(tcp_listener, &mut self.machine_st.arena),
port as usize,
)
} else {
self.machine_st.fail = true;
return Ok(());
}
}
Err(ErrorKind::PermissionDenied) => {
return Err(self.machine_st.open_permission_error(
addr,
atom!("socket_server_open"),
2,
));
}
_ => {
self.machine_st.fail = true;
return Ok(());
}
}
Err(ErrorKind::PermissionDenied) => {
return Err(self.machine_st.open_permission_error(
addr,
atom!("socket_server_open"),
2,
));
}
_ => {
self.machine_st.fail = true;
return Ok(());
}
};
};
let addr = self.deref_register(3);
self.machine_st.bind(
@@ -6729,12 +6731,8 @@ impl Machine {
(HeapCellValueTag::Cons, cons_ptr) => {
match_untyped_arena_ptr!(cons_ptr,
(ArenaHeaderTag::TcpListener, tcp_listener) => {
unsafe {
// dropping closes the instance.
std::ptr::drop_in_place(&mut tcp_listener as *mut _);
}
tcp_listener.drop_payload();
tcp_listener.set_tag(ArenaHeaderTag::Dropped);
return Ok(());
}
_ => {
@@ -7990,10 +7988,7 @@ impl Machine {
pub(crate) fn load_library_as_stream(&mut self) -> CallResult {
let library_name = cell_as_atom!(self.deref_register(1));
use crate::machine::LIBRARIES;
let lib_ref = LIBRARIES.borrow();
let lib = lib_ref.get(&*library_name.as_str());
let lib = libraries::get(&library_name.as_str());
match lib {
Some(library) => {
let lib_stream = Stream::from_static_string(library, &mut self.machine_st.arena);