summaryrefslogtreecommitdiff
path: root/tools/standalone_miri/value.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/standalone_miri/value.cpp')
-rw-r--r--tools/standalone_miri/value.cpp334
1 files changed, 148 insertions, 186 deletions
diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp
index 8860c8d9..a497f0bd 100644
--- a/tools/standalone_miri/value.cpp
+++ b/tools/standalone_miri/value.cpp
@@ -21,6 +21,37 @@ namespace {
return false;
return ofs + size <= max_size;
}
+
+ void set_bit(uint8_t* p, size_t i, bool v)
+ {
+ if(v) {
+ p[i/8] |= 1 << (i%8);
+ }
+ else {
+ p[i/8] &= ~(1 << (i%8));
+ }
+ }
+ bool get_bit(const uint8_t* p, size_t i) {
+ return (p[i/8] & (1 << (i%8))) != 0;
+ }
+ void copy_bits(uint8_t* dst, size_t dst_ofs, const uint8_t* src, size_t src_ofs, size_t len)
+ {
+ // Even number of bytes, fast copy
+ if( dst_ofs % 8 == 0 && src_ofs % 8 == 0 && len % 8 == 0 )
+ {
+ for(size_t i = 0; i < len/8; i ++)
+ {
+ dst[dst_ofs/8 + i] = src[src_ofs/8 + i];
+ }
+ }
+ else
+ {
+ for(size_t i = 0; i < len; i ++)
+ {
+ set_bit( dst, dst_ofs+i, get_bit(src, src_ofs+i) );
+ }
+ }
+ }
};
::std::ostream& operator<<(::std::ostream& os, const Allocation* x)
@@ -383,57 +414,25 @@ Value Allocation::read_value(size_t ofs, size_t size) const
{
if( ofs <= r.slot_ofs && r.slot_ofs < ofs + size )
{
+ // NOTE: A relocation at offset zero is allowed
+ if( r.slot_ofs == ofs )
+ continue ;
has_reloc = true;
}
}
- if( has_reloc || size > sizeof(rv.direct_data.data) )
- {
- rv.allocation = Allocation::new_alloc(size, FMT_STRING("Allocation::read_value(" << ofs << "," << size << ")"));
-
- rv.write_bytes(0, this->data_ptr() + ofs, size);
+ rv = Value::with_size(size, has_reloc);
+ rv.write_bytes(0, this->data_ptr() + ofs, size);
- for(const auto& r : this->relocations)
- {
- if( ofs <= r.slot_ofs && r.slot_ofs < ofs + size )
- {
- rv.allocation->relocations.push_back({ r.slot_ofs - ofs, r.backing_alloc });
- }
- }
-
- // Copy the mask bits
- for(size_t i = 0; i < size; i ++)
- {
- size_t j = ofs + i;
- const uint8_t test_mask = (1 << (j%8));
- const uint8_t set_mask = (1 << (i%8));
- bool v = (this->m_mask[j/8] & test_mask) != 0;
- if( v )
- {
- rv.allocation->m_mask[i/8] |= set_mask;
- }
- }
- }
- else
+ for(const auto& r : this->relocations)
{
- rv.direct_data.size = static_cast<uint8_t>(size);
-
- rv.write_bytes(0, this->data_ptr() + ofs, size);
- rv.direct_data.mask[0] = 0;
- rv.direct_data.mask[1] = 0;
-
- // Copy the mask bits
- for(size_t i = 0; i < size; i ++)
+ if( ofs <= r.slot_ofs && r.slot_ofs < ofs + size )
{
- size_t j = ofs + i;
- const uint8_t tst_mask = 1 << (j%8);
- const uint8_t set_mask = 1 << (i%8);
- bool v = (this->m_mask[j/8] & tst_mask) != 0;
- if( v )
- {
- rv.direct_data.mask[i/8] |= set_mask;
- }
+ rv.set_reloc(r.slot_ofs - ofs, /*r.size*/POINTER_SIZE, r.backing_alloc);
}
}
+ // Copy the mask bits
+ copy_bits(rv.get_mask_mut(), 0, m_mask.data(), ofs, size);
+
return rv;
}
void Allocation::read_bytes(size_t ofs, void* dst, size_t count) const
@@ -461,14 +460,15 @@ void Allocation::write_value(size_t ofs, Value v)
LOG_ERROR("Use of freed memory " << this);
//if( this->is_read_only )
// LOG_ERROR("Writing to read-only allocation " << this);
- if( v.allocation )
+ if( v.m_inner.is_alloc )
{
- size_t v_size = v.allocation->size();
- const auto& src_alloc = *v.allocation;
+ const auto& src_alloc = *v.m_inner.alloc.alloc;
+ size_t v_size = src_alloc.size();
+ assert(&src_alloc != this); // Shouldn't happen?
+
// Take a copy of the source mask
auto s_mask = src_alloc.m_mask;
-
- // Save relocations first, because `Foo = Foo` is valid.
+ // Save relocations first, because `Foo = Foo` is valid?
::std::vector<Relocation> new_relocs = src_alloc.relocations;
// - write_bytes removes any relocations in this region.
write_bytes(ofs, src_alloc.data_ptr(), v_size);
@@ -487,39 +487,16 @@ void Allocation::write_value(size_t ofs, Value v)
}
// Set mask in destination
- if( ofs % 8 != 0 || v_size % 8 != 0 )
- {
- // Lazy way, sets/clears individual bits
- for(size_t i = 0; i < v_size; i ++)
- {
- uint8_t dbit = 1 << ((ofs+i) % 8);
- if( s_mask[i/8] & (1 << (i %8)) )
- this->m_mask[ (ofs+i) / 8 ] |= dbit;
- else
- this->m_mask[ (ofs+i) / 8 ] &= ~dbit;
- }
- }
- else
- {
- // Copy the mask bytes directly
- for(size_t i = 0; i < v_size / 8; i ++)
- {
- this->m_mask[ofs/8+i] = s_mask[i];
- }
- }
+ copy_bits(m_mask.data(), ofs, s_mask.data(), 0, v_size);
}
else
{
- this->write_bytes(ofs, v.direct_data.data, v.direct_data.size);
-
- // Lazy way, sets/clears individual bits
- for(size_t i = 0; i < v.direct_data.size; i ++)
+ this->write_bytes(ofs, v.data_ptr(), v.size());
+ copy_bits(m_mask.data(), ofs, v.get_mask(), 0, v.size());
+ // TODO: Copy relocation
+ if( v.m_inner.direct.reloc_0 )
{
- uint8_t dbit = 1 << ((ofs+i) % 8);
- if( v.direct_data.mask[i/8] & (1 << (i %8)) )
- this->m_mask[ (ofs+i) / 8 ] |= dbit;
- else
- this->m_mask[ (ofs+i) / 8 ] &= ~dbit;
+ this->set_reloc(ofs, POINTER_SIZE, ::std::move(v.m_inner.direct.reloc_0));
}
}
}
@@ -618,58 +595,55 @@ void Allocation::set_reloc(size_t ofs, size_t len, RelocationPtr reloc)
Value::Value()
{
- this->direct_data.size = 0;
- memset(this->direct_data.mask, 0, sizeof(this->direct_data.mask));
+ memset(&m_inner, 0, sizeof(m_inner));
}
Value::Value(::HIR::TypeRef ty)
{
size_t size = ty.get_size();
// Support inline data if the data will fit within the inline region (which is the size of the metadata)
- if( ty.get_size() <= sizeof(this->direct_data.data) )
+ if( size <= sizeof(m_inner.direct.data) )
{
// AND the type doesn't contain a pointer (of any kind)
- if( ! ty.has_pointer() )
+ // TODO: Pointers _are_ allowed now (but only one)
+ if( true || ! ty.has_pointer() )
{
// Will fit in a inline allocation, nice.
//LOG_TRACE("No pointers in " << ty << ", storing inline");
- this->direct_data.size = static_cast<uint8_t>(size);
- this->direct_data.mask[0] = 0;
- this->direct_data.mask[1] = 0;
+ new(&m_inner.direct) Inner::Direct(size);
return ;
}
}
// Fallback: Make a new allocation
//LOG_TRACE(" Creating allocation for " << ty);
- this->allocation = Allocation::new_alloc(size, FMT_STRING(ty));
+ new(&m_inner.alloc) Inner::Alloc( Allocation::new_alloc(size, FMT_STRING(ty)) );
+ assert(m_inner.is_alloc);
}
Value Value::with_size(size_t size, bool have_allocation)
{
Value rv;
- if(have_allocation || size > sizeof(rv.direct_data.data))
+ if(have_allocation || size > sizeof(m_inner.direct.data))
{
- rv.allocation = Allocation::new_alloc(size, FMT_STRING("with_size(" << size << ")"));
+ new(&rv.m_inner.alloc) Inner::Alloc( Allocation::new_alloc(size, FMT_STRING("with_size(" << size << ")")) );
}
else
{
- rv.direct_data.size = static_cast<uint8_t>(size);
- memset(rv.direct_data.mask, 0, sizeof(rv.direct_data.mask));
+ new(&rv.m_inner.direct) Inner::Direct(size);
}
return rv;
}
Value Value::new_fnptr(const ::HIR::Path& fn_path)
{
Value rv( ::HIR::TypeRef(::HIR::CoreType { RawType::Function }) );
- assert(rv.allocation);
- rv.allocation->write_ptr(0, Allocation::PTR_BASE, RelocationPtr::new_fcn(fn_path));
+ rv.write_ptr(0, Allocation::PTR_BASE, RelocationPtr::new_fcn(fn_path));
return rv;
}
Value Value::new_ffiptr(FFIPointer ffi)
{
Value rv( ::HIR::TypeRef(::HIR::CoreType { RawType::USize }) );
- rv.create_allocation();
- rv.allocation->write_ptr(0, Allocation::PTR_BASE, RelocationPtr::new_ffi(ffi));
+ assert( !rv.m_inner.is_alloc );
+ rv.write_ptr(0, Allocation::PTR_BASE, RelocationPtr::new_ffi(ffi));
return rv;
}
Value Value::new_pointer(::HIR::TypeRef ty, uint64_t v, RelocationPtr r) {
@@ -707,52 +681,49 @@ Value Value::new_i64(int64_t v) {
void Value::create_allocation()
{
- assert(!this->allocation);
- this->allocation = Allocation::new_alloc(this->direct_data.size, "create_allocation");
- if( this->direct_data.size > 0 )
- this->allocation->m_mask[0] = this->direct_data.mask[0];
- if( this->direct_data.size > 8 )
- this->allocation->m_mask[1] = this->direct_data.mask[1];
- ::std::memcpy(this->allocation->data_ptr(), this->direct_data.data, this->direct_data.size);
+ assert(!m_inner.is_alloc);
+ auto new_alloc = Allocation::new_alloc(m_inner.direct.size, "create_allocation"); // TODO: Provide a better name?
+ auto& direct = m_inner.direct;
+ if( direct.size > 0 )
+ new_alloc->m_mask[0] = direct.mask[0];
+ if( direct.size > 8 )
+ new_alloc->m_mask[1] = direct.mask[1];
+ ::std::memcpy(new_alloc->data_ptr(), direct.data, direct.size);
+ if( direct.reloc_0 )
+ {
+ new_alloc->set_reloc(0, POINTER_SIZE, ::std::move(direct.reloc_0));
+ }
+
+ new(&m_inner.alloc) Inner::Alloc(::std::move(new_alloc));
}
void Value::check_bytes_valid(size_t ofs, size_t size) const
{
if( size == 0 )
return ;
- if( this->allocation )
- {
- this->allocation->check_bytes_valid(ofs, size);
+ if( !in_bounds(ofs, size, this->size()) ) {
+ LOG_ERROR("Read out of bounds " << ofs+size << " >= " << this->size());
+ throw "ERROR";
}
- else
+ const auto* mask = this->get_mask();
+ for(size_t i = ofs; i < ofs + size; i++)
{
- if( size == 0 && this->direct_data.size > 0 ) {
- return ;
- }
- if( !in_bounds(ofs, size, this->direct_data.size) ) {
- LOG_ERROR("Read out of bounds " << ofs+size << " >= " << int(this->direct_data.size));
- throw "ERROR";
- }
- for(size_t i = ofs; i < ofs + size; i++)
+ if( !get_bit(mask, i) )
{
- if( !(this->direct_data.mask[i/8] & (1 << i%8)) )
- {
- LOG_ERROR("Accessing invalid bytes in value");
- throw "ERROR";
- }
+ LOG_ERROR("Accessing invalid bytes in value, offset " << i << " of " << *this);
}
}
}
void Value::mark_bytes_valid(size_t ofs, size_t size)
{
- if( this->allocation )
+ if( m_inner.is_alloc )
{
- this->allocation->mark_bytes_valid(ofs, size);
+ m_inner.alloc.alloc->mark_bytes_valid(ofs, size);
}
else
{
for(size_t i = ofs; i < ofs+size; i++)
{
- this->direct_data.mask[i/8] |= (1 << i%8);
+ m_inner.direct.mask[i/8] |= (1 << i%8);
}
}
}
@@ -760,18 +731,28 @@ void Value::mark_bytes_valid(size_t ofs, size_t size)
Value Value::read_value(size_t ofs, size_t size) const
{
Value rv;
- //TRACE_FUNCTION_R(ofs << ", " << size << ") - " << *this, rv);
- if( this->allocation )
+ TRACE_FUNCTION_R(ofs << ", " << size << " - " << *this, rv);
+ if( m_inner.is_alloc )
{
- rv = this->allocation->read_value(ofs, size);
+ rv = m_inner.alloc.alloc->read_value(ofs, size);
}
else
{
// Inline always fits in inline.
- rv.direct_data.size = static_cast<uint8_t>(size);
- rv.write_bytes(0, this->direct_data.data+ofs, size);
- rv.direct_data.mask[0] = this->direct_data.mask[0];
- rv.direct_data.mask[1] = this->direct_data.mask[1];
+ if( ofs == 0 && size == this->size() )
+ {
+ rv = Value(*this);
+ }
+ else
+ {
+ rv.m_inner.direct.size = static_cast<uint8_t>(size);
+ memcpy(rv.m_inner.direct.data, this->data_ptr() + ofs, size);
+ copy_bits(rv.m_inner.direct.mask, 0, this->get_mask(), ofs, size);
+ if( ofs == 0 )
+ {
+ rv.m_inner.direct.reloc_0 = RelocationPtr(m_inner.direct.reloc_0);
+ }
+ }
}
return rv;
}
@@ -779,20 +760,14 @@ void Value::read_bytes(size_t ofs, void* dst, size_t count) const
{
if(count == 0)
return ;
- if( this->allocation )
+ if( m_inner.is_alloc )
{
- this->allocation->read_bytes(ofs, dst, count);
+ m_inner.alloc.alloc->read_bytes(ofs, dst, count);
}
else
{
check_bytes_valid(ofs, count);
-
- // TODO: Redundant due to above?
- if( !in_bounds(ofs, count, this->direct_data.size) ) {
- LOG_ERROR("Out of bounds read, " << ofs << "+" << count << " > " << this->size());
- throw "ERROR";
- }
- ::std::memcpy(dst, this->direct_data.data + ofs, count);
+ ::std::memcpy(dst, m_inner.direct.data + ofs, count);
}
}
@@ -800,82 +775,65 @@ void Value::write_bytes(size_t ofs, const void* src, size_t count)
{
if( count == 0 )
return ;
- if( this->allocation )
+ if( m_inner.is_alloc )
{
- this->allocation->write_bytes(ofs, src, count);
+ m_inner.alloc.alloc->write_bytes(ofs, src, count);
}
else
{
- if( !in_bounds(ofs, count, this->direct_data.size) ) {
- LOG_BUG("Write extends outside value size (" << ofs << "+" << count << " >= " << (int)this->direct_data.size << ")");
+ auto& direct = m_inner.direct;
+ if( !in_bounds(ofs, count, direct.size) ) {
+ LOG_ERROR("Write extends outside value size (" << ofs << "+" << count << " >= " << (int)direct.size << ")");
}
- ::std::memcpy(this->direct_data.data + ofs, src, count);
+ ::std::memcpy(direct.data + ofs, src, count);
mark_bytes_valid(ofs, count);
+ if( 0 <= ofs && ofs < POINTER_SIZE ) {
+ direct.reloc_0 = RelocationPtr();
+ }
}
}
void Value::write_value(size_t ofs, Value v)
{
- if( this->allocation )
+ if( m_inner.is_alloc )
{
- this->allocation->write_value(ofs, ::std::move(v));
+ m_inner.alloc.alloc->write_value(ofs, ::std::move(v));
}
else
{
- if( v.allocation && !v.allocation->relocations.empty() )
- {
- this->create_allocation();
- this->allocation->write_value(ofs, ::std::move(v));
- }
- else
- {
- write_bytes(ofs, v.direct_data.data, v.direct_data.size);
+ write_bytes(ofs, v.data_ptr(), v.size());
+ // - Copy mask
+ copy_bits(this->get_mask_mut(), ofs, v.get_mask(), 0, v.size());
- // Lazy way, sets/clears individual bits
- for(size_t i = 0; i < v.direct_data.size; i ++)
+ // TODO: Faster way of knowing where there are relocations
+ for(size_t i = 0; i < v.size(); i ++)
+ {
+ if( auto r = v.get_relocation(i) )
{
- uint8_t dbit = 1 << ((ofs+i) % 8);
- if( v.direct_data.mask[i/8] & (1 << (i %8)) )
- this->direct_data.mask[ (ofs+i) / 8 ] |= dbit;
- else
- this->direct_data.mask[ (ofs+i) / 8 ] &= ~dbit;
+ this->set_reloc(ofs + i, POINTER_SIZE, r);
}
}
}
}
void Value::write_ptr(size_t ofs, size_t ptr_ofs, RelocationPtr reloc)
{
- if( !this->allocation )
+ if( m_inner.is_alloc )
{
- LOG_ERROR("Writing a pointer with no allocation");
- }
- this->allocation->write_ptr(ofs, ptr_ofs, ::std::move(reloc));
-}
-
-::std::ostream& operator<<(::std::ostream& os, const Value& v)
-{
- if( v.allocation )
- {
- os << *v.allocation;
+ m_inner.alloc.alloc->write_ptr(ofs, ptr_ofs, ::std::move(reloc));
}
else
{
- auto flags = os.flags();
- os << ::std::hex;
- for(size_t i = 0; i < v.direct_data.size; i++)
+ write_usize(ofs, ptr_ofs);
+ if( ofs != 0 )
{
- if( i != 0 )
- os << " ";
- if( v.direct_data.mask[i/8] & (1 << i%8) )
- {
- os << ::std::setw(2) << ::std::setfill('0') << (int)v.direct_data.data[i];
- }
- else
- {
- os << "--";
- }
+ LOG_ERROR("Writing a pointer with no allocation");
}
- os.setf(flags);
+ m_inner.direct.reloc_0 = ::std::move(reloc);
}
+}
+
+::std::ostream& operator<<(::std::ostream& os, const Value& v)
+{
+ os << ValueRef(const_cast<Value&>(v), 0, v.size());
return os;
}
extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v)
@@ -940,9 +898,9 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v)
break;
}
}
- else if( v.m_value && v.m_value->allocation )
+ else if( v.m_value && v.m_value->m_inner.is_alloc )
{
- const auto& alloc = *v.m_value->allocation;
+ const auto& alloc = *v.m_value->m_inner.alloc.alloc;
os << &alloc << "@" << v.m_offset << "+" << v.m_size << " ";
@@ -976,7 +934,7 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v)
}
else if( v.m_value )
{
- const auto& direct = v.m_value->direct_data;
+ const auto& direct = v.m_value->m_inner.direct;
auto flags = os.flags();
os << ::std::hex;
@@ -994,6 +952,10 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v)
}
}
os.setf(flags);
+ if(direct.reloc_0)
+ {
+ os << " { " << direct.reloc_0 << " }";
+ }
}
else
{