diff options
author | John Hodge <tpg@mutabah.net> | 2018-02-11 21:57:10 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2018-02-11 21:57:10 +0800 |
commit | a3a0c6437302c60bd6f521fc11e30c0a16bd79fc (patch) | |
tree | 83b536f1d5b170a88417015ec0a7f378ab6ea4c4 /tools/standalone_miri/value.cpp | |
parent | 14fea32f414df2d1e0b8e2669c8fe13132210ae9 (diff) | |
download | mrust-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.cpp | 183 |
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 { |