rust-lang / miri

An interpreter for Rust's mid-level intermediate representation
Apache License 2.0
4.6k stars 347 forks source link

optimize zst to not require an actual allocation #19

Closed oli-obk closed 8 years ago

oli-obk commented 8 years ago

I'm not sure, but I think simply reserving a single allocation to be used for all zst should work (pointers to different zst values will compare equal, but comparing pointers to different types is probably forbidden anyway).

solson commented 8 years ago

pointers to different zst values will compare equal, but comparing pointers to different types is probably forbidden anyway

I'm worried about allowing this from a correctness standpoint. They could be the same type:

let x = ();
let y = 1;
let z = ();
assert_eq!(&x as *const (), &z as *const ());

This (probably) fails in rustc and currently does in miri but wouldn't with the suggested change. I'm not sure what is or should be guaranteed here.

@ubsan Any thoughts?


On the other hand, this is probably a major low-hanging fruit optimization, and it would be nice to make these faster one way or another. I have some vague thoughts about passing around PrimVal instead of Pointer for some of miri's operations to reduce the number of allocations created which might help here, too. I need some more time to investigate that.

By the way, ZST Allocations themselves don't require any heap allocation in the interpreter, aside from the space used in the HashMap in Memory. Another idea is to have fake Pointers for ZSTs which somehow preserve distinctness but don't actually key into the HashMap.

oli-obk commented 8 years ago

Another idea is to have fake Pointers for ZSTs which somehow preserve distinctness but don't actually key into the HashMap.

Easy, just increase the alloc_id counter without allocating and make sure that miri doesn't actually deref ZST pointers. There'd be no way to detect dangling zst pointers, but I don't think that's an issue.

strega-nil commented 8 years ago

@solson I don't believe we make any guarantees about the uniqueness of ZST pointers (or, to be honest, any of the other pointer types), and we do not guarantee the ordering of stack variables.

oli-obk commented 8 years ago

@ubsan we do make guarantees for &mut T when T is not ZST

strega-nil commented 8 years ago

@oli-obk I don't think so... I can't imagine an implementation which would break that though (i.e., I can't imagine an implementation that requires what Rust does, and still would be able to do that). I believe we do specifically want to be able to do this:

{
  let x = 0;
  let y = 0;
  &x as *const _ == &y as *const _ // true
}

We guarantee noalias semantics, but nothing about pointer comparisons, actually. So... if someone wanted to make an entirely completely ridiculous implementation, they could do something like optimizing

fn doop (ptr1: *const u32, ptr2: *const u32) -> bool {
  ptr1 == ptr2
}
// to
fn doop (ptr1: *const u32, ptr2: *const u32) -> bool {
  true
}
solson commented 8 years ago

Easy, just increase the alloc_id counter without allocating and make sure that miri doesn't actually deref ZST pointers. There'd be no way to detect dangling zst pointers, but I don't think that's an issue.

@oli-obk I'd like to at least be able to tell a dangling pointer deref apart from a ZST deref (after being casted to a different pointer type, say).

solson commented 8 years ago

@oli-obk Based on @ubsan's comments, I think it would be fine to implement your original suggestion of a single ZST allocation. This would remove the problem of my previous comment.