diff options
Diffstat (limited to 'tools/standalone_miri/value.cpp')
-rw-r--r-- | tools/standalone_miri/value.cpp | 334 |
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 { |