summaryrefslogtreecommitdiff
path: root/tools/standalone_miri/value.cpp
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2018-02-11 21:57:10 +0800
committerJohn Hodge <tpg@mutabah.net>2018-02-11 21:57:10 +0800
commita3a0c6437302c60bd6f521fc11e30c0a16bd79fc (patch)
tree83b536f1d5b170a88417015ec0a7f378ab6ea4c4 /tools/standalone_miri/value.cpp
parent14fea32f414df2d1e0b8e2669c8fe13132210ae9 (diff)
downloadmrust-a3a0c6437302c60bd6f521fc11e30c0a16bd79fc.tar.gz
Standalone MIRI - Implementation sprint, statics in process.
Diffstat (limited to 'tools/standalone_miri/value.cpp')
-rw-r--r--tools/standalone_miri/value.cpp183
1 files changed, 171 insertions, 12 deletions
diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp
index e04154f6..59b68ea0 100644
--- a/tools/standalone_miri/value.cpp
+++ b/tools/standalone_miri/value.cpp
@@ -8,6 +8,54 @@
#include <iomanip>
#include <algorithm>
+
+AllocationPtr Allocation::new_alloc(size_t size)
+{
+ Allocation* rv = new Allocation();
+ rv->refcount = 1;
+ rv->data.resize( (size + 8-1) / 8 ); // QWORDS
+ rv->mask.resize( (size + 8-1) / 8 ); // bitmap bytes
+ return AllocationPtr(rv);
+}
+AllocationPtr AllocationPtr::new_fcn(::HIR::Path p)
+{
+ AllocationPtr rv;
+ auto* ptr = new ::HIR::Path(::std::move(p));
+ rv.m_ptr = reinterpret_cast<void*>( reinterpret_cast<uintptr_t>(ptr) + static_cast<uintptr_t>(Ty::Function) );
+ return rv;
+}
+AllocationPtr::AllocationPtr(const AllocationPtr& x):
+ m_ptr(x.m_ptr)
+{
+ if( is_alloc() ) {
+ assert(alloc().refcount != SIZE_MAX);
+ alloc().refcount += 1;
+ }
+}
+AllocationPtr::~AllocationPtr()
+{
+ if( *this )
+ {
+ switch(get_ty())
+ {
+ case Ty::Allocation: {
+ auto* ptr = &alloc();
+ ptr->refcount -= 1;
+ if(ptr->refcount == 0)
+ delete ptr;
+ } break;
+ case Ty::Function: {
+ auto* ptr = const_cast<::HIR::Path*>(&fcn());
+ delete ptr;
+ } break;
+ case Ty::Unused1: {
+ } break;
+ case Ty::Unused2: {
+ } break;
+ }
+ }
+}
+
Value::Value()
{
this->meta.direct_data.size = 0;
@@ -18,6 +66,7 @@ Value::Value(::HIR::TypeRef ty)
{
size_t size = ty.get_size();
#if 1
+ // 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->meta.direct_data.data) )
{
struct H
@@ -26,6 +75,11 @@ Value::Value(::HIR::TypeRef ty)
{
if( ty.wrappers.empty() || ::std::all_of(ty.wrappers.begin(), ty.wrappers.end(), [](const auto& x){ return x.type == TypeWrapper::Ty::Array; }) )
{
+ // TODO: Function pointers should be _pointers_
+ if( ty.inner_type == RawType::Function )
+ {
+ return true;
+ }
// Check the inner type
if( ty.inner_type != RawType::Composite )
{
@@ -45,28 +99,69 @@ Value::Value(::HIR::TypeRef ty)
if( ! H::has_pointer(ty) )
{
// Will fit in a inline allocation, nice.
+ ::std::cout << "Value::Value(): No pointers in " << ty << ", storing inline" << ::std::endl;
this->meta.direct_data.size = static_cast<uint8_t>(size);
+ this->meta.direct_data.mask[0] = 0;
+ this->meta.direct_data.mask[1] = 0;
return ;
}
}
#endif
// Fallback: Make a new allocation
- throw "TODO";
+ ::std::cout << "Value::Value(): Creating allocation for " << ty << ::std::endl;
+ this->allocation = Allocation::new_alloc(size);
+ this->meta.indirect_meta.offset = 0;
+ this->meta.indirect_meta.size = size;
+}
+Value Value::new_fnptr(const ::HIR::Path& fn_path)
+{
+ Value rv( ::HIR::TypeRef(::HIR::CoreType { RawType::Function }) );
+ assert(rv.allocation);
+ rv.allocation.alloc().relocations.push_back(Relocation { 0, AllocationPtr::new_fcn(fn_path) });
+ rv.allocation.alloc().data.at(0) = 0;
+ rv.allocation.alloc().mask.at(0) = 0xFF; // TODO: Get pointer size and make that much valid instead of 8 bytes
+ return rv;
}
void Value::check_bytes_valid(size_t ofs, size_t size) const
{
if( this->allocation )
{
- throw "TODO";
+ const auto& alloc = this->allocation.alloc();
+ if( ofs >= this->meta.indirect_meta.size || ofs+size > this->meta.indirect_meta.size ) {
+ ::std::cerr << "ERROR: OOB read" << ::std::endl;
+ throw "ERROR";
+ }
+ ofs += this->meta.indirect_meta.offset;
+ //assert(ofs + size < alloc.size());
+ for(size_t i = ofs; i < ofs + size; i++)
+ {
+ if( !(alloc.mask[i/8] & (1 << i%8)) )
+ {
+ ::std::cerr << "ERROR: Invalid bytes in value" << ::std::endl;
+ throw "ERROR";
+ }
+ }
}
else
{
- for(size_t i = 0; i < this->meta.direct_data.size; i++)
+ if( size == 0 && this->meta.direct_data.size > 0 ) {
+ return ;
+ }
+ if( ofs >= this->meta.direct_data.size ) {
+ ::std::cerr << "ERROR: OOB read" << ::std::endl;
+ throw "ERROR";
+ }
+ if( ofs+size > this->meta.direct_data.size ) {
+ ::std::cerr << "ERROR: OOB read" << ::std::endl;
+ throw "ERROR";
+ }
+ for(size_t i = ofs; i < ofs + size; i++)
{
if( !(this->meta.direct_data.mask[i/8] & (1 << i%8)) )
{
+ ::std::cerr << "ERROR: Invalid bytes in value" << ::std::endl;
throw "ERROR";
}
}
@@ -76,7 +171,14 @@ void Value::mark_bytes_valid(size_t ofs, size_t size)
{
if( this->allocation )
{
- throw "TODO";
+ auto& alloc = this->allocation.alloc();
+ // TODO: Assert range.
+ ofs += this->meta.indirect_meta.offset;
+ assert( (ofs+size+8-1) / 8 < alloc.mask.size() );
+ for(size_t i = ofs; i < ofs + size; i++)
+ {
+ alloc.mask[i/8] |= (1 << i%8);
+ }
}
else
{
@@ -93,7 +195,29 @@ Value Value::read_value(size_t ofs, size_t size) const
check_bytes_valid(ofs, size);
if( this->allocation )
{
- throw "TODO";
+ const auto& alloc = this->allocation.alloc();
+ // TODO: Determine if this can become an inline allocation.
+ bool has_reloc = false;
+ for(const auto& r : alloc.relocations)
+ {
+ if( this->meta.indirect_meta.offset+ofs <= r.slot_ofs && r.slot_ofs < this->meta.indirect_meta.offset + ofs + size )
+ {
+ has_reloc = true;
+ }
+ }
+ Value rv;
+ if( has_reloc && size < sizeof(this->meta.direct_data.data) )
+ {
+ rv.allocation = Allocation::new_alloc(size);
+ rv.meta.indirect_meta.offset = 0;
+ rv.meta.indirect_meta.size = size;
+ }
+ else
+ {
+ rv.meta.direct_data.size = static_cast<uint8_t>(size);
+ }
+ rv.write_bytes(0, this->data_ptr() + ofs, size);
+ return rv;
}
else
{
@@ -114,7 +238,12 @@ void Value::write_bytes(size_t ofs, const void* src, size_t count)
{
if( this->allocation )
{
- throw "TODO";
+ if(ofs >= this->meta.indirect_meta.size )
+ throw "ERROR";
+ if(count > this->meta.indirect_meta.size )
+ throw "ERROR";
+ if(ofs+count > this->meta.indirect_meta.size )
+ throw "ERROR";
}
else
{
@@ -124,21 +253,36 @@ void Value::write_bytes(size_t ofs, const void* src, size_t count)
throw "ERROR";
if(ofs+count > this->meta.direct_data.size )
throw "ERROR";
- ::std::memcpy(this->meta.direct_data.data+ofs, src, count);
- mark_bytes_valid(ofs, count);
}
+ ::std::memcpy(this->data_ptr() + ofs, src, count);
+ mark_bytes_valid(ofs, count);
}
void Value::write_value(size_t ofs, Value v)
{
if( v.allocation )
{
- throw "TODO";
+ v.check_bytes_valid(0, v.meta.indirect_meta.size);
+ const auto& src_alloc = v.allocation.alloc();
+ write_bytes(ofs, v.data_ptr(), v.meta.indirect_meta.size);
+ // Find any relocations that apply and copy those in.
+ // - Any relocations in the source within `v.meta.indirect_meta.offset` .. `v.meta.indirect_meta.offset + v.meta.indirect_meta.size`
+ for(const auto& r : src_alloc.relocations)
+ {
+ // TODO: Negative offsets in destination?
+ if( v.meta.indirect_meta.offset <= r.slot_ofs && r.slot_ofs < v.meta.indirect_meta.offset + v.meta.indirect_meta.size )
+ {
+ // Applicable
+ if( !this->allocation ) {
+ throw ::std::runtime_error("TODO: Writing value with a relocation into a slot without a relocation");
+ }
+ this->allocation.alloc().relocations.push_back( r );
+ }
+ }
}
else
{
v.check_bytes_valid(0, v.meta.direct_data.size);
write_bytes(ofs, v.meta.direct_data.data, v.meta.direct_data.size);
- mark_bytes_valid(ofs, meta.direct_data.size);
}
}
@@ -146,7 +290,7 @@ size_t Value::as_usize() const
{
uint64_t v;
this->read_bytes(0, &v, 8);
- // TODO: Handle endian
+ // TODO: Handle endian and different architectures
return v;
}
::std::ostream& operator<<(::std::ostream& os, const Value& v)
@@ -155,7 +299,22 @@ size_t Value::as_usize() const
os << ::std::hex;
if( v.allocation )
{
- throw "TODO";
+ const auto& alloc = v.allocation.alloc();
+ for(size_t i = 0; i < v.meta.indirect_meta.size; i++)
+ {
+ if( i != 0 )
+ os << " ";
+ size_t j = i + v.meta.indirect_meta.offset;
+
+ if( alloc.mask[j/8] & (1 << i%8) )
+ {
+ os << ::std::setw(2) << ::std::setfill('0') << (int)alloc.data_ptr()[j];
+ }
+ else
+ {
+ os << "--";
+ }
+ }
}
else
{