diff options
-rw-r--r-- | tools/standalone_miri/main.cpp | 94 | ||||
-rw-r--r-- | tools/standalone_miri/module_tree.cpp | 6 | ||||
-rw-r--r-- | tools/standalone_miri/value.cpp | 208 | ||||
-rw-r--r-- | tools/standalone_miri/value.hpp | 190 |
4 files changed, 280 insertions, 218 deletions
diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index 1ab5b955..cd521501 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -153,7 +153,7 @@ public: virtual bool multiply(const PrimitiveValue& v) = 0; virtual bool divide(const PrimitiveValue& v) = 0; virtual bool modulo(const PrimitiveValue& v) = 0; - virtual void write_to_value(ValueCommon& tgt, size_t ofs) const = 0; + virtual void write_to_value(ValueCommonWrite& tgt, size_t ofs) const = 0; template<typename T> const T& check(const char* opname) const @@ -212,14 +212,14 @@ struct PrimitiveUInt: struct PrimitiveU64: public PrimitiveUInt<uint64_t> { PrimitiveU64(uint64_t v): PrimitiveUInt(v) {} - void write_to_value(ValueCommon& tgt, size_t ofs) const override { + void write_to_value(ValueCommonWrite& tgt, size_t ofs) const override { tgt.write_u64(ofs, this->v); } }; struct PrimitiveU32: public PrimitiveUInt<uint32_t> { PrimitiveU32(uint32_t v): PrimitiveUInt(v) {} - void write_to_value(ValueCommon& tgt, size_t ofs) const override { + void write_to_value(ValueCommonWrite& tgt, size_t ofs) const override { tgt.write_u32(ofs, this->v); } }; @@ -273,14 +273,14 @@ struct PrimitiveSInt: struct PrimitiveI64: public PrimitiveSInt<int64_t> { PrimitiveI64(int64_t v): PrimitiveSInt(v) {} - void write_to_value(ValueCommon& tgt, size_t ofs) const override { + void write_to_value(ValueCommonWrite& tgt, size_t ofs) const override { tgt.write_i64(ofs, this->v); } }; struct PrimitiveI32: public PrimitiveSInt<int32_t> { PrimitiveI32(int32_t v): PrimitiveSInt(v) {} - void write_to_value(ValueCommon& tgt, size_t ofs) const override { + void write_to_value(ValueCommonWrite& tgt, size_t ofs) const override { tgt.write_i32(ofs, this->v); } }; @@ -458,11 +458,8 @@ struct MirHelpers size_t ofs = val.read_usize(0); // There MUST be a relocation at this point with a valid allocation. - auto& val_alloc = val.m_alloc ? val.m_alloc : val.m_value->allocation; - LOG_ASSERT(val_alloc, "Deref of a value with no allocation (hence no relocations)"); - LOG_ASSERT(val_alloc.is_alloc(), "Deref of a value with a non-data allocation"); - LOG_TRACE("Deref " << val_alloc.alloc() << " + " << ofs << " to give value of type " << ty); - auto alloc = val_alloc.alloc().get_relocation(val.m_offset); + auto alloc = val.get_relocation(val.m_offset); + LOG_TRACE("Deref " << alloc << " + " << ofs << " to give value of type " << ty); // NOTE: No alloc can happen when dereferencing a zero-sized pointer if( alloc.is_alloc() ) { @@ -595,7 +592,7 @@ struct MirHelpers Value val = Value(ty); val.write_usize(0, 0); val.write_usize(POINTER_SIZE, ce.size()); - val.allocation.alloc().relocations.push_back(Relocation { 0, AllocationPtr::new_string(&ce) }); + val.allocation->relocations.push_back(Relocation { 0, RelocationPtr::new_string(&ce) }); LOG_DEBUG(c << " = " << val); //return Value::new_dataptr(ce.data()); return val; @@ -612,7 +609,7 @@ struct MirHelpers ty.wrappers.push_back(TypeWrapper { TypeWrapper::Ty::Borrow, 0 }); Value val = Value(ty); val.write_usize(0, 0); - val.allocation.alloc().relocations.push_back(Relocation { 0, s->val.allocation }); + val.allocation->relocations.push_back(Relocation { 0, RelocationPtr::new_alloc(s->val.allocation) }); return val; } LOG_ERROR("Constant::ItemAddr - " << ce << " - not found"); @@ -676,6 +673,7 @@ InterpreterThread::~InterpreterThread() } void InterpreterThread::start(const ::HIR::Path& p, ::std::vector<Value> args) { + assert( this->m_stack.empty() ); Value v; if( this->call_path(v, p, ::std::move(args)) ) { @@ -720,7 +718,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) { src_base_value.m_value->create_allocation(); } - alloc = AllocationPtr(src_base_value.m_value->allocation); + alloc = RelocationPtr::new_alloc( src_base_value.m_value->allocation ); } if( alloc.is_alloc() ) LOG_DEBUG("- alloc=" << alloc << " (" << alloc.alloc() << ")"); @@ -740,7 +738,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) new_val.write_value(POINTER_SIZE, *src_base_value.m_metadata); } // - Add the relocation after writing the value (writing clears the relocations) - new_val.allocation.alloc().relocations.push_back(Relocation { 0, ::std::move(alloc) }); + new_val.allocation->relocations.push_back(Relocation { 0, ::std::move(alloc) }); } break; TU_ARM(se.src, Cast, re) { // Determine the type of cast, is it a reinterpret or is it a value transform? @@ -1073,8 +1071,8 @@ bool InterpreterThread::step_one(Value& out_thread_result) const auto& alloc_l = v_l.m_value ? v_l.m_value->allocation : v_l.m_alloc; const auto& alloc_r = v_r.m_value ? v_r.m_value->allocation : v_r.m_alloc; - auto reloc_l = alloc_l ? v_l.get_relocation(v_l.m_offset) : AllocationPtr(); - auto reloc_r = alloc_r ? v_r.get_relocation(v_r.m_offset) : AllocationPtr(); + auto reloc_l = alloc_l ? v_l.get_relocation(v_l.m_offset) : RelocationPtr(); + auto reloc_r = alloc_r ? v_r.get_relocation(v_r.m_offset) : RelocationPtr(); if( reloc_l != reloc_r ) { @@ -1109,8 +1107,8 @@ bool InterpreterThread::step_one(Value& out_thread_result) // Compare fat metadata. if( res == 0 && v_l.m_size > POINTER_SIZE ) { - reloc_l = alloc_l ? alloc_l.alloc().get_relocation(POINTER_SIZE) : AllocationPtr(); - reloc_r = alloc_r ? alloc_r.alloc().get_relocation(POINTER_SIZE) : AllocationPtr(); + reloc_l = v_l.get_relocation(POINTER_SIZE); + reloc_r = v_r.get_relocation(POINTER_SIZE); if( res == 0 && reloc_l != reloc_r ) { @@ -1427,7 +1425,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) { v.m_value->create_allocation(); } - alloc = AllocationPtr(v.m_value->allocation); + alloc = RelocationPtr::new_alloc( v.m_value->allocation ); } size_t ofs = v.m_offset; assert(ty.get_meta_type() == RawType::Unreachable); @@ -1436,7 +1434,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) auto ptr_val = Value(ptr_ty); ptr_val.write_usize(0, ofs); - ptr_val.allocation.alloc().relocations.push_back(Relocation { 0, ::std::move(alloc) }); + ptr_val.allocation->relocations.push_back(Relocation { 0, ::std::move(alloc) }); if( !drop_value(ptr_val, ty, /*shallow=*/se.kind == ::MIR::eDropKind::SHALLOW) ) { @@ -1549,7 +1547,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) } else { - AllocationPtr fcn_alloc_ptr; + RelocationPtr fcn_alloc_ptr; const ::HIR::Path* fcn_p; if( te.fcn.is_Path() ) { fcn_p = &te.fcn.as_Path(); @@ -1561,12 +1559,10 @@ bool InterpreterThread::step_one(Value& out_thread_result) // TODO: Assert type // TODO: Assert offset/content. assert(v.read_usize(0) == 0); - auto& alloc_ptr = v.m_alloc ? v.m_alloc : v.m_value->allocation; - LOG_ASSERT(alloc_ptr, "Calling value that can't be a pointer (no allocation)"); - fcn_alloc_ptr = alloc_ptr.alloc().get_relocation(v.m_offset); + fcn_alloc_ptr = v.get_relocation(v.m_offset); if( !fcn_alloc_ptr ) LOG_FATAL("Calling value with no relocation - " << v); - LOG_ASSERT(fcn_alloc_ptr.get_ty() == AllocationPtr::Ty::Function, "Calling value that isn't a function pointer"); + LOG_ASSERT(fcn_alloc_ptr.get_ty() == RelocationPtr::Ty::Function, "Calling value that isn't a function pointer"); fcn_p = &fcn_alloc_ptr.fcn(); } @@ -1717,12 +1713,12 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c rv = Value(rty); rv.write_usize(0, 0); // TODO: Use the alignment when making an allocation? - rv.allocation.alloc().relocations.push_back({ 0, Allocation::new_alloc(size) }); + rv.allocation->relocations.push_back({ 0, RelocationPtr::new_alloc(Allocation::new_alloc(size)) }); } else if( link_name == "__rust_reallocate" ) { LOG_ASSERT(args.at(0).allocation, "__rust_reallocate first argument doesn't have an allocation"); - auto alloc_ptr = args.at(0).allocation.alloc().get_relocation(0); + auto alloc_ptr = args.at(0).get_relocation(0); auto ptr_ofs = args.at(0).read_usize(0); LOG_ASSERT(ptr_ofs == 0, "__rust_reallocate with offset pointer"); auto oldsize = args.at(1).read_usize(0); @@ -1742,7 +1738,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c else if( link_name == "__rust_deallocate" ) { LOG_ASSERT(args.at(0).allocation, "__rust_deallocate first argument doesn't have an allocation"); - auto alloc_ptr = args.at(0).allocation.alloc().get_relocation(0); + auto alloc_ptr = args.at(0).get_relocation(0); auto ptr_ofs = args.at(0).read_usize(0); LOG_ASSERT(ptr_ofs == 0, "__rust_deallocate with offset pointer"); LOG_DEBUG("__rust_deallocate(ptr=" << alloc_ptr << ")"); @@ -1948,8 +1944,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c // - `void *memchr(const void *s, int c, size_t n);` else if( link_name == "memchr" ) { - LOG_ASSERT(args.at(0).allocation.is_alloc(), ""); - auto ptr_alloc = args.at(0).allocation.alloc().get_relocation(0); + auto ptr_alloc = args.at(0).get_relocation(0); auto c = args.at(1).read_i32(0); auto n = args.at(2).read_usize(0); const void* ptr = args.at(0).read_pointer_const(0, n); @@ -1961,7 +1956,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c if( ret ) { rv.write_usize(0, args.at(0).read_usize(0) + ( static_cast<const uint8_t*>(ret) - static_cast<const uint8_t*>(ptr) )); - rv.allocation.alloc().relocations.push_back({ 0, ptr_alloc }); + rv.allocation->relocations.push_back({ 0, ptr_alloc }); } else { @@ -1982,7 +1977,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c if( ret ) { rv.write_usize(0, args.at(0).read_usize(0) + ( static_cast<const uint8_t*>(ret) - static_cast<const uint8_t*>(ptr) )); - rv.allocation.alloc().relocations.push_back({ 0, ptr_alloc }); + rv.allocation->relocations.push_back({ 0, ptr_alloc }); } else { @@ -2027,9 +2022,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con LOG_ASSERT(ptr_val.size() == POINTER_SIZE, "atomic_store of a value that isn't a pointer-sized value"); // There MUST be a relocation at this point with a valid allocation. - LOG_ASSERT(ptr_val.allocation, "Deref of a value with no allocation (hence no relocations)"); - LOG_TRACE("Deref " << ptr_val.allocation.alloc()); - auto alloc = ptr_val.allocation.alloc().get_relocation(0); + auto alloc = ptr_val.get_relocation(0); LOG_ASSERT(alloc, "Deref of a value with no relocation"); // TODO: Atomic side of this? @@ -2042,9 +2035,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con LOG_ASSERT(ptr_val.size() == POINTER_SIZE, "atomic_store of a value that isn't a pointer-sized value"); // There MUST be a relocation at this point with a valid allocation. - LOG_ASSERT(ptr_val.allocation, "Deref of a value with no allocation (hence no relocations)"); - LOG_TRACE("Deref " << ptr_val.allocation.alloc()); - auto alloc = ptr_val.allocation.alloc().get_relocation(0); + auto alloc = ptr_val.get_relocation(0); LOG_ASSERT(alloc, "Deref of a value with no relocation"); // TODO: Atomic lock the allocation. @@ -2057,7 +2048,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con { const auto& ty_T = ty_params.tys.at(0); auto ptr_ofs = args.at(0).read_usize(0); - auto ptr_alloc = args.at(0).allocation.alloc().get_relocation(0); + auto ptr_alloc = args.at(0).get_relocation(0); auto v = args.at(1).read_value(0, ty_T.get_size()); // TODO: Atomic lock the allocation. @@ -2078,7 +2069,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con { const auto& ty_T = ty_params.tys.at(0); auto ptr_ofs = args.at(0).read_usize(0); - auto ptr_alloc = args.at(0).allocation.alloc().get_relocation(0); + auto ptr_alloc = args.at(0).get_relocation(0); auto v = args.at(1).read_value(0, ty_T.get_size()); // TODO: Atomic lock the allocation. @@ -2146,7 +2137,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con rv = ::std::move(args.at(0)); rv.write_usize(0, new_ofs); if( ptr_alloc ) { - rv.allocation.alloc().relocations.push_back({ 0, ptr_alloc }); + rv.allocation->relocations.push_back({ 0, ptr_alloc }); } } // effectively ptr::write @@ -2160,12 +2151,13 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con // There MUST be a relocation at this point with a valid allocation. LOG_ASSERT(ptr_val.allocation, "Deref of a value with no allocation (hence no relocations)"); LOG_TRACE("Deref " << ptr_val << " and store " << data_val); - auto alloc = ptr_val.allocation.alloc().get_relocation(0); - LOG_ASSERT(alloc, "Deref of a value with no relocation"); + + auto ptr_alloc = ptr_val.get_relocation(0); + LOG_ASSERT(ptr_alloc, "Deref of a value with no relocation"); size_t ofs = ptr_val.read_usize(0); - alloc.alloc().write_value(ofs, ::std::move(data_val)); - LOG_DEBUG(alloc.alloc()); + ptr_alloc.alloc().write_value(ofs, ::std::move(data_val)); + LOG_DEBUG(ptr_alloc.alloc()); } else if( name == "uninit" ) { @@ -2330,9 +2322,9 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con else if( name == "copy_nonoverlapping" ) { auto src_ofs = args.at(0).read_usize(0); - auto src_alloc = args.at(0).allocation.alloc().get_relocation(0); + auto src_alloc = args.at(0).get_relocation(0); auto dst_ofs = args.at(1).read_usize(0); - auto dst_alloc = args.at(1).allocation.alloc().get_relocation(0); + auto dst_alloc = args.at(1).get_relocation(0); size_t ent_count = args.at(2).read_usize(0); size_t ent_size = ty_params.tys.at(0).get_size(); auto byte_count = ent_count * ent_size; @@ -2343,21 +2335,21 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con switch(src_alloc.get_ty()) { - case AllocationPtr::Ty::Allocation: { + case RelocationPtr::Ty::Allocation: { auto v = src_alloc.alloc().read_value(src_ofs, byte_count); LOG_DEBUG("v = " << v); dst_alloc.alloc().write_value(dst_ofs, ::std::move(v)); } break; - case AllocationPtr::Ty::StdString: + case RelocationPtr::Ty::StdString: LOG_ASSERT(src_ofs <= src_alloc.str().size(), ""); LOG_ASSERT(byte_count <= src_alloc.str().size(), ""); LOG_ASSERT(src_ofs + byte_count <= src_alloc.str().size(), ""); dst_alloc.alloc().write_bytes(dst_ofs, src_alloc.str().data() + src_ofs, byte_count); break; - case AllocationPtr::Ty::Function: + case RelocationPtr::Ty::Function: LOG_FATAL("Attempt to copy* a function"); break; - case AllocationPtr::Ty::FfiPointer: + case RelocationPtr::Ty::FfiPointer: LOG_BUG("Trying to copy from a FFI pointer"); break; } diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index ad41b33a..6a7a0b5f 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -151,13 +151,13 @@ bool Parser::parse_one() auto a = Allocation::new_alloc( reloc_str.size() ); //a.alloc().set_tag(); - a.alloc().write_bytes(0, reloc_str.data(), reloc_str.size()); - s.val.allocation.alloc().relocations.push_back({ ofs, ::std::move(a) }); + a->write_bytes(0, reloc_str.data(), reloc_str.size()); + s.val.allocation->relocations.push_back({ ofs, RelocationPtr::new_alloc(::std::move(a)) }); } else if( lex.next() == "::" || lex.next() == "<" ) { auto reloc_path = parse_path(); - s.val.allocation.alloc().relocations.push_back({ ofs, AllocationPtr::new_fcn(reloc_path) }); + s.val.allocation->relocations.push_back({ ofs, RelocationPtr::new_fcn(reloc_path) }); } else { diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index cdace6e2..d8eeee01 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -9,49 +9,79 @@ #include <algorithm> #include "debug.hpp" -AllocationPtr Allocation::new_alloc(size_t size) +AllocationHandle 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 //LOG_DEBUG(rv << " ALLOC"); - return AllocationPtr(rv); + return AllocationHandle(rv); } -AllocationPtr AllocationPtr::new_fcn(::HIR::Path p) +AllocationHandle::AllocationHandle(const AllocationHandle& x): + m_ptr(x.m_ptr) { - AllocationPtr rv; + if( m_ptr ) + { + assert(m_ptr->refcount != 0); + assert(m_ptr->refcount != SIZE_MAX); + m_ptr->refcount += 1; + //LOG_DEBUG(m_ptr << " REF++ " << m_ptr->refcount); + } +} +AllocationHandle::~AllocationHandle() +{ + if( m_ptr ) + { + m_ptr->refcount -= 1; + //LOG_DEBUG(m_ptr << " REF-- " << m_ptr->refcount); + if(m_ptr->refcount == 0) + { + delete m_ptr; + } + } +} + +RelocationPtr RelocationPtr::new_alloc(AllocationHandle alloc) +{ + RelocationPtr rv; + auto* ptr = alloc.m_ptr; + alloc.m_ptr = nullptr; + rv.m_ptr = reinterpret_cast<void*>( reinterpret_cast<uintptr_t>(ptr) + static_cast<uintptr_t>(Ty::Allocation) ); + return rv; +} +RelocationPtr RelocationPtr::new_fcn(::HIR::Path p) +{ + RelocationPtr 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::new_string(const ::std::string* ptr) +RelocationPtr RelocationPtr::new_string(const ::std::string* ptr) { - AllocationPtr rv; + RelocationPtr rv; rv.m_ptr = reinterpret_cast<void*>( reinterpret_cast<uintptr_t>(ptr) + static_cast<uintptr_t>(Ty::StdString) ); return rv; } -AllocationPtr AllocationPtr::new_ffi(FFIPointer info) +RelocationPtr RelocationPtr::new_ffi(FFIPointer info) { - AllocationPtr rv; + RelocationPtr rv; auto* ptr = new FFIPointer(info); rv.m_ptr = reinterpret_cast<void*>( reinterpret_cast<uintptr_t>(ptr) + static_cast<uintptr_t>(Ty::FfiPointer) ); return rv; } -AllocationPtr::AllocationPtr(const AllocationPtr& x): +RelocationPtr::RelocationPtr(const RelocationPtr& x): m_ptr(nullptr) { if( x ) { switch(x.get_ty()) { - case Ty::Allocation: - m_ptr = x.m_ptr; - assert(alloc().refcount != 0); - assert(alloc().refcount != SIZE_MAX); - alloc().refcount += 1; - //LOG_DEBUG(&alloc() << " REF++ " << alloc().refcount); - break; + case Ty::Allocation: { + auto tmp = AllocationHandle( reinterpret_cast<Allocation*>(x.get_ptr()) ); + *this = RelocationPtr::new_alloc(tmp); + tmp.m_ptr = nullptr; + } break; case Ty::Function: { auto ptr_i = reinterpret_cast<uintptr_t>(new ::HIR::Path(x.fcn())); assert( (ptr_i & 3) == 0 ); @@ -75,21 +105,15 @@ AllocationPtr::AllocationPtr(const AllocationPtr& x): m_ptr = nullptr; } } -AllocationPtr::~AllocationPtr() +RelocationPtr::~RelocationPtr() { if( *this ) { switch(get_ty()) { - case Ty::Allocation: { - auto* ptr = &alloc(); - ptr->refcount -= 1; - //LOG_DEBUG(&alloc() << " REF-- " << ptr->refcount); - if(ptr->refcount == 0) - { - delete ptr; - } - } break; + case Ty::Allocation: + (void)AllocationHandle( reinterpret_cast<Allocation*>(get_ptr()) ); + break; case Ty::Function: { auto* ptr = const_cast<::HIR::Path*>(&fcn()); delete ptr; @@ -104,7 +128,7 @@ AllocationPtr::~AllocationPtr() } } } -size_t AllocationPtr::get_size() const +size_t RelocationPtr::get_size() const { if( !*this ) return 0; @@ -123,22 +147,22 @@ size_t AllocationPtr::get_size() const throw "Unreachable"; } -::std::ostream& operator<<(::std::ostream& os, const AllocationPtr& x) +::std::ostream& operator<<(::std::ostream& os, const RelocationPtr& x) { if( x ) { switch(x.get_ty()) { - case AllocationPtr::Ty::Allocation: + case RelocationPtr::Ty::Allocation: os << &x.alloc(); break; - case AllocationPtr::Ty::Function: + case RelocationPtr::Ty::Function: os << x.fcn(); break; - case AllocationPtr::Ty::StdString: + case RelocationPtr::Ty::StdString: os << "\"" << x.str() << "\""; break; - case AllocationPtr::Ty::FfiPointer: + case RelocationPtr::Ty::FfiPointer: os << "FFI " << x.ffi().source_function << " " << x.ffi().ptr_value; break; } @@ -150,17 +174,17 @@ size_t AllocationPtr::get_size() const return os; } -uint64_t ValueCommon::read_usize(size_t ofs) const +uint64_t ValueCommonRead::read_usize(size_t ofs) const { uint64_t v = 0; this->read_bytes(ofs, &v, POINTER_SIZE); return v; } -void ValueCommon::write_usize(size_t ofs, uint64_t v) +void ValueCommonWrite::write_usize(size_t ofs, uint64_t v) { this->write_bytes(ofs, &v, POINTER_SIZE); } -void* ValueCommon::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size_t& out_size, bool& out_is_mut) const +void* ValueCommonRead::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size_t& out_size, bool& out_is_mut) const { auto ofs = read_usize(rd_ofs); auto reloc = get_relocation(rd_ofs); @@ -180,7 +204,7 @@ void* ValueCommon::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size_t& { switch(reloc.get_ty()) { - case AllocationPtr::Ty::Allocation: { + case RelocationPtr::Ty::Allocation: { auto& a = reloc.alloc(); if( ofs > a.size() ) LOG_FATAL("Out-of-bounds pointer"); @@ -191,7 +215,7 @@ void* ValueCommon::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size_t& out_is_mut = true; return a.data_ptr() + ofs; } - case AllocationPtr::Ty::StdString: { + case RelocationPtr::Ty::StdString: { const auto& s = reloc.str(); if( ofs > s.size() ) LOG_FATAL("Out-of-bounds pointer"); @@ -201,9 +225,9 @@ void* ValueCommon::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size_t& out_is_mut = false; return const_cast<void*>( static_cast<const void*>(s.data() + ofs) ); } - case AllocationPtr::Ty::Function: + case RelocationPtr::Ty::Function: LOG_FATAL("read_pointer w/ function"); - case AllocationPtr::Ty::FfiPointer: + case RelocationPtr::Ty::FfiPointer: if( req_valid ) LOG_FATAL("Can't request valid data from a FFI pointer"); // TODO: Have an idea of mutability and available size from FFI @@ -214,7 +238,7 @@ void* ValueCommon::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size_t& throw ""; } } -ValueRef ValueCommon::read_pointer_valref_mut(size_t rd_ofs, size_t size) +ValueRef ValueCommonRead::read_pointer_valref_mut(size_t rd_ofs, size_t size) { auto ofs = read_usize(rd_ofs); auto reloc = get_relocation(rd_ofs); @@ -290,7 +314,7 @@ Value Allocation::read_value(size_t ofs, size_t size) const { if( ofs <= r.slot_ofs && r.slot_ofs < ofs + size ) { - rv.allocation.alloc().relocations.push_back({ r.slot_ofs - ofs, r.backing_alloc }); + rv.allocation->relocations.push_back({ r.slot_ofs - ofs, r.backing_alloc }); } } @@ -303,7 +327,7 @@ Value Allocation::read_value(size_t ofs, size_t size) const bool v = (this->mask[j/8] & test_mask) != 0; if( v ) { - rv.allocation.alloc().mask[i/8] |= set_mask; + rv.allocation->mask[i/8] |= set_mask; } } } @@ -365,8 +389,8 @@ void Allocation::write_value(size_t ofs, Value v) // LOG_ERROR("Writing to read-only allocation " << this); if( v.allocation ) { - size_t v_size = v.allocation.alloc().size(); - const auto& src_alloc = v.allocation.alloc(); + size_t v_size = v.allocation->size(); + const auto& src_alloc = *v.allocation; // Take a copy of the source mask auto s_mask = src_alloc.mask; @@ -575,18 +599,18 @@ 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 + rv.allocation->relocations.push_back(Relocation { 0, RelocationPtr::new_fcn(fn_path) }); + rv.allocation->data.at(0) = 0; + rv.allocation->mask.at(0) = 0xFF; // TODO: Get pointer size and make that much valid instead of 8 bytes return rv; } Value Value::new_ffiptr(FFIPointer ffi) { Value rv( ::HIR::TypeRef(::HIR::CoreType { RawType::USize }) ); rv.create_allocation(); - rv.allocation.alloc().relocations.push_back(Relocation { 0, AllocationPtr::new_ffi(ffi) }); - 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 + rv.allocation->relocations.push_back(Relocation { 0, RelocationPtr::new_ffi(ffi) }); + rv.allocation->data.at(0) = 0; + rv.allocation->mask.at(0) = 0xFF; // TODO: Get pointer size and make that much valid instead of 8 bytes return rv; } @@ -595,10 +619,10 @@ void Value::create_allocation() assert(!this->allocation); this->allocation = Allocation::new_alloc(this->direct_data.size); if( this->direct_data.size > 0 ) - this->allocation.alloc().mask[0] = this->direct_data.mask[0]; + this->allocation->mask[0] = this->direct_data.mask[0]; if( this->direct_data.size > 8 ) - this->allocation.alloc().mask[1] = this->direct_data.mask[1]; - ::std::memcpy(this->allocation.alloc().data.data(), this->direct_data.data, this->direct_data.size); + this->allocation->mask[1] = this->direct_data.mask[1]; + ::std::memcpy(this->allocation->data.data(), this->direct_data.data, this->direct_data.size); } void Value::check_bytes_valid(size_t ofs, size_t size) const { @@ -606,7 +630,7 @@ void Value::check_bytes_valid(size_t ofs, size_t size) const return ; if( this->allocation ) { - this->allocation.alloc().check_bytes_valid(ofs, size); + this->allocation->check_bytes_valid(ofs, size); } else { @@ -635,7 +659,7 @@ void Value::mark_bytes_valid(size_t ofs, size_t size) { if( this->allocation ) { - this->allocation.alloc().mark_bytes_valid(ofs, size); + this->allocation->mark_bytes_valid(ofs, size); } else { @@ -652,7 +676,7 @@ Value Value::read_value(size_t ofs, size_t size) const //TRACE_FUNCTION_R(ofs << ", " << size << ") - " << *this, rv); if( this->allocation ) { - rv = this->allocation.alloc().read_value(ofs, size); + rv = this->allocation->read_value(ofs, size); } else { @@ -670,7 +694,7 @@ void Value::read_bytes(size_t ofs, void* dst, size_t count) const return ; if( this->allocation ) { - this->allocation.alloc().read_bytes(ofs, dst, count); + this->allocation->read_bytes(ofs, dst, count); } else { @@ -698,7 +722,7 @@ void Value::write_bytes(size_t ofs, const void* src, size_t count) return ; if( this->allocation ) { - this->allocation.alloc().write_bytes(ofs, src, count); + this->allocation->write_bytes(ofs, src, count); } else { @@ -719,14 +743,14 @@ void Value::write_value(size_t ofs, Value v) { if( this->allocation ) { - this->allocation.alloc().write_value(ofs, ::std::move(v)); + this->allocation->write_value(ofs, ::std::move(v)); } else { - if( v.allocation && !v.allocation.alloc().relocations.empty() ) + if( v.allocation && !v.allocation->relocations.empty() ) { this->create_allocation(); - this->allocation.alloc().write_value(ofs, ::std::move(v)); + this->allocation->write_value(ofs, ::std::move(v)); } else { @@ -749,7 +773,7 @@ void Value::write_value(size_t ofs, Value v) { if( v.allocation ) { - os << v.allocation.alloc(); + os << *v.allocation; } else { @@ -776,13 +800,13 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v) { if( v.m_size == 0 ) return os; - if( v.m_alloc || v.m_value->allocation ) + if( v.m_alloc ) { - const auto& alloc_ptr = v.m_alloc ? v.m_alloc : v.m_value->allocation; + const auto& alloc_ptr = v.m_alloc;; // TODO: What if alloc_ptr isn't a data allocation? switch(alloc_ptr.get_ty()) { - case AllocationPtr::Ty::Allocation: { + case RelocationPtr::Ty::Allocation: { const auto& alloc = alloc_ptr.alloc(); auto flags = os.flags(); @@ -813,10 +837,10 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v) } os << " }"; } break; - case AllocationPtr::Ty::Function: + case RelocationPtr::Ty::Function: LOG_TODO("ValueRef to " << alloc_ptr); break; - case AllocationPtr::Ty::StdString: { + case RelocationPtr::Ty::StdString: { const auto& s = alloc_ptr.str(); assert(v.m_offset < s.size()); assert(v.m_size < s.size()); @@ -829,12 +853,44 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v) } os.setf(flags); } break; - case AllocationPtr::Ty::FfiPointer: + case RelocationPtr::Ty::FfiPointer: LOG_TODO("ValueRef to " << alloc_ptr); break; } } - else + else if( v.m_value && v.m_value->allocation ) + { + const auto& alloc = *v.m_value->allocation; + + auto flags = os.flags(); + os << ::std::hex; + for(size_t i = v.m_offset; i < ::std::min(alloc.size(), v.m_offset + v.m_size); i++) + { + if( i != 0 ) + os << " "; + + if( alloc.mask[i/8] & (1 << i%8) ) + { + os << ::std::setw(2) << ::std::setfill('0') << (int)alloc.data_ptr()[i]; + } + else + { + os << "--"; + } + } + os.setf(flags); + + os << " {"; + for(const auto& r : alloc.relocations) + { + if( v.m_offset <= r.slot_ofs && r.slot_ofs < v.m_offset + v.m_size ) + { + os << " @" << (r.slot_ofs - v.m_offset) << "=" << r.backing_alloc; + } + } + os << " }"; + } + else if( v.m_value ) { const auto& direct = v.m_value->direct_data; @@ -855,6 +911,10 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v) } os.setf(flags); } + else + { + // TODO: no value? + } return os; } @@ -868,9 +928,9 @@ Value ValueRef::read_value(size_t ofs, size_t size) const if( m_alloc ) { switch(m_alloc.get_ty()) { - case AllocationPtr::Ty::Allocation: + case RelocationPtr::Ty::Allocation: return m_alloc.alloc().read_value(m_offset + ofs, size); - case AllocationPtr::Ty::StdString: { + case RelocationPtr::Ty::StdString: { auto rv = Value::with_size(size, false); //ASSERT_BUG(ofs <= m_alloc.str().size(), ""); //ASSERT_BUG(size <= m_alloc.str().size(), ""); @@ -893,9 +953,3 @@ bool ValueRef::compare(const void* other, size_t other_len) const check_bytes_valid(0, other_len); return ::std::memcmp(data_ptr(), other, other_len) == 0; } -uint64_t ValueRef::read_usize(size_t ofs) const -{ - uint64_t v = 0; - this->read_bytes(ofs, &v, POINTER_SIZE); - return v; -} diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index aa41b838..4da2eee6 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -23,12 +23,46 @@ struct FFIPointer void* ptr_value; }; -class AllocationPtr +class AllocationHandle { friend class Allocation; - void* m_ptr; + friend class RelocationPtr; + Allocation* m_ptr; + +private: + AllocationHandle(Allocation* p): + m_ptr(p) + { + } public: + AllocationHandle(): m_ptr(nullptr) {} + AllocationHandle(AllocationHandle&& x): m_ptr(x.m_ptr) { + x.m_ptr = nullptr; + } + AllocationHandle(const AllocationHandle& x); + ~AllocationHandle(); + + AllocationHandle& operator=(const AllocationHandle& x) = delete; + AllocationHandle& operator=(AllocationHandle&& x) { + this->~AllocationHandle(); + this->m_ptr = x.m_ptr; + x.m_ptr = nullptr; + return *this; + } + operator bool() const { return m_ptr != 0; } + const Allocation& operator*() const { assert(m_ptr); return *m_ptr; } + Allocation& operator*() { assert(m_ptr); return *m_ptr; } + const Allocation* operator->() const { assert(m_ptr); return m_ptr; } + Allocation* operator->() { assert(m_ptr); return m_ptr; } +}; + +// TODO: Split into RelocationPtr and AllocationHandle +class RelocationPtr +{ + void* m_ptr; + +public: enum class Ty { Allocation, @@ -37,26 +71,20 @@ public: FfiPointer, }; -private: - AllocationPtr(Allocation* p): - m_ptr(p) - { - } -public: - AllocationPtr(): m_ptr(nullptr) {} - AllocationPtr(AllocationPtr&& x): m_ptr(x.m_ptr) { + RelocationPtr(): m_ptr(nullptr) {} + RelocationPtr(RelocationPtr&& x): m_ptr(x.m_ptr) { x.m_ptr = nullptr; } - AllocationPtr(const AllocationPtr& x); - ~AllocationPtr(); - static AllocationPtr new_fcn(::HIR::Path p); - //static AllocationPtr new_rawdata(const void* buf, size_t len); - static AllocationPtr new_string(const ::std::string* s); // NOTE: The string must have a stable pointer - static AllocationPtr new_ffi(FFIPointer info); - - AllocationPtr& operator=(const AllocationPtr& x) = delete; - AllocationPtr& operator=(AllocationPtr&& x) { - this->~AllocationPtr(); + RelocationPtr(const RelocationPtr& x); + ~RelocationPtr(); + static RelocationPtr new_alloc(AllocationHandle h); + static RelocationPtr new_fcn(::HIR::Path p); + static RelocationPtr new_string(const ::std::string* s); // NOTE: The string must have a stable pointer + static RelocationPtr new_ffi(FFIPointer info); + + RelocationPtr& operator=(const RelocationPtr& x) = delete; + RelocationPtr& operator=(RelocationPtr&& x) { + this->~RelocationPtr(); this->m_ptr = x.m_ptr; x.m_ptr = nullptr; return *this; @@ -98,7 +126,7 @@ public: return static_cast<Ty>( reinterpret_cast<uintptr_t>(m_ptr) & 3 ); } - friend ::std::ostream& operator<<(::std::ostream& os, const AllocationPtr& x); + friend ::std::ostream& operator<<(::std::ostream& os, const RelocationPtr& x); private: void* get_ptr() const { return reinterpret_cast<void*>( reinterpret_cast<uintptr_t>(m_ptr) & ~3 ); @@ -109,27 +137,14 @@ struct Relocation // Offset within parent allocation where this relocation is performed. // TODO: Size? size_t slot_ofs; - AllocationPtr backing_alloc; + RelocationPtr backing_alloc; }; -struct ValueCommon +// TODO: Split write and read +struct ValueCommonRead { - virtual AllocationPtr get_relocation(size_t ofs) const = 0; + virtual RelocationPtr get_relocation(size_t ofs) const = 0; virtual void read_bytes(size_t ofs, void* dst, size_t count) const = 0; - virtual void write_bytes(size_t ofs, const void* src, size_t count) = 0; - - void write_u8 (size_t ofs, uint8_t v) { write_bytes(ofs, &v, 1); } - void write_u16(size_t ofs, uint16_t v) { write_bytes(ofs, &v, 2); } - void write_u32(size_t ofs, uint32_t v) { write_bytes(ofs, &v, 4); } - void write_u64(size_t ofs, uint64_t v) { write_bytes(ofs, &v, 8); } - void write_i8 (size_t ofs, int8_t v) { write_u8 (ofs, static_cast<uint8_t >(v)); } - void write_i16(size_t ofs, int16_t v) { write_u16(ofs, static_cast<uint16_t>(v)); } - void write_i32(size_t ofs, int32_t v) { write_u32(ofs, static_cast<uint32_t>(v)); } - void write_i64(size_t ofs, int64_t v) { write_u64(ofs, static_cast<uint64_t>(v)); } - void write_f32(size_t ofs, float v) { write_bytes(ofs, &v, 4); } - void write_f64(size_t ofs, double v) { write_bytes(ofs, &v, 8); } - void write_usize(size_t ofs, uint64_t v); - void write_isize(size_t ofs, int64_t v) { write_usize(ofs, static_cast<uint64_t>(v)); } uint8_t read_u8(size_t ofs) const { uint8_t rv; read_bytes(ofs, &rv, 1); return rv; } uint16_t read_u16(size_t ofs) const { uint16_t rv; read_bytes(ofs, &rv, 2); return rv; } @@ -164,16 +179,34 @@ struct ValueCommon /// Read a pointer and return a ValueRef to it (mutable data) ValueRef read_pointer_valref_mut(size_t rd_ofs, size_t size); }; +struct ValueCommonWrite: + public ValueCommonRead +{ + virtual void write_bytes(size_t ofs, const void* src, size_t count) = 0; + + void write_u8 (size_t ofs, uint8_t v) { write_bytes(ofs, &v, 1); } + void write_u16(size_t ofs, uint16_t v) { write_bytes(ofs, &v, 2); } + void write_u32(size_t ofs, uint32_t v) { write_bytes(ofs, &v, 4); } + void write_u64(size_t ofs, uint64_t v) { write_bytes(ofs, &v, 8); } + void write_i8 (size_t ofs, int8_t v) { write_u8 (ofs, static_cast<uint8_t >(v)); } + void write_i16(size_t ofs, int16_t v) { write_u16(ofs, static_cast<uint16_t>(v)); } + void write_i32(size_t ofs, int32_t v) { write_u32(ofs, static_cast<uint32_t>(v)); } + void write_i64(size_t ofs, int64_t v) { write_u64(ofs, static_cast<uint64_t>(v)); } + void write_f32(size_t ofs, float v) { write_bytes(ofs, &v, 4); } + void write_f64(size_t ofs, double v) { write_bytes(ofs, &v, 8); } + void write_usize(size_t ofs, uint64_t v); + void write_isize(size_t ofs, int64_t v) { write_usize(ofs, static_cast<uint64_t>(v)); } +}; class Allocation: - public ValueCommon + public ValueCommonWrite { - friend class AllocationPtr; + friend class AllocationHandle; size_t refcount; // TODO: Read-only flag? bool is_freed = false; public: - static AllocationPtr new_alloc(size_t size); + static AllocationHandle new_alloc(size_t size); const uint8_t* data_ptr() const { return reinterpret_cast<const uint8_t*>(this->data.data()); } uint8_t* data_ptr() { return reinterpret_cast< uint8_t*>(this->data.data()); } @@ -183,12 +216,12 @@ public: ::std::vector<uint8_t> mask; ::std::vector<Relocation> relocations; - AllocationPtr get_relocation(size_t ofs) const override { + RelocationPtr get_relocation(size_t ofs) const override { for(const auto& r : relocations) { if(r.slot_ofs == ofs) return r.backing_alloc; } - return AllocationPtr(); + return RelocationPtr(); } void mark_as_freed() { is_freed = true; @@ -211,10 +244,10 @@ public: extern ::std::ostream& operator<<(::std::ostream& os, const Allocation& x); struct Value: - public ValueCommon + public ValueCommonWrite { // If NULL, data is direct - AllocationPtr allocation; + AllocationHandle allocation; struct { uint8_t data[2*sizeof(size_t)-3]; // 16-3 = 13, fits in 16 bits of mask uint8_t mask[2]; @@ -228,15 +261,15 @@ struct Value: static Value new_ffiptr(FFIPointer ffi); void create_allocation(); - size_t size() const { return allocation ? allocation.alloc().size() : direct_data.size; } - const uint8_t* data_ptr() const { return allocation ? allocation.alloc().data_ptr() : direct_data.data; } - uint8_t* data_ptr() { return allocation ? allocation.alloc().data_ptr() : direct_data.data; } + size_t size() const { return allocation ? allocation->size() : direct_data.size; } + const uint8_t* data_ptr() const { return allocation ? allocation->data_ptr() : direct_data.data; } + uint8_t* data_ptr() { return allocation ? allocation->data_ptr() : direct_data.data; } - AllocationPtr get_relocation(size_t ofs) const override { - if( this->allocation && this->allocation.is_alloc() ) - return this->allocation.alloc().get_relocation(ofs); + RelocationPtr get_relocation(size_t ofs) const override { + if( this->allocation && this->allocation ) + return this->allocation->get_relocation(ofs); else - return AllocationPtr(); + return RelocationPtr(); } void check_bytes_valid(size_t ofs, size_t size) const; @@ -251,17 +284,17 @@ struct Value: extern ::std::ostream& operator<<(::std::ostream& os, const Value& v); // A read-only reference to a value (to write, you have to go through it) -struct ValueRef - //:public ValueCommon +struct ValueRef: + public ValueCommonRead { - // Either an AllocationPtr, or a Value pointer - AllocationPtr m_alloc; + // Either an AllocationHandle, or a Value pointer + RelocationPtr m_alloc; Value* m_value; size_t m_offset; // Offset within the value size_t m_size; // Size in bytes of the referenced value ::std::shared_ptr<Value> m_metadata; - ValueRef(AllocationPtr ptr, size_t ofs, size_t size): + ValueRef(RelocationPtr ptr, size_t ofs, size_t size): m_alloc(ptr), m_value(nullptr), m_offset(ofs), @@ -271,12 +304,12 @@ struct ValueRef { switch(m_alloc.get_ty()) { - case AllocationPtr::Ty::Allocation: + case RelocationPtr::Ty::Allocation: assert(ofs < m_alloc.alloc().size()); assert(size <= m_alloc.alloc().size()); assert(ofs+size <= m_alloc.alloc().size()); break; - case AllocationPtr::Ty::StdString: + case RelocationPtr::Ty::StdString: assert(ofs < m_alloc.str().size()); assert(size <= m_alloc.str().size()); assert(ofs+size <= m_alloc.str().size()); @@ -297,24 +330,21 @@ struct ValueRef { } - AllocationPtr get_relocation(size_t ofs) const { + RelocationPtr get_relocation(size_t ofs) const override { if(m_alloc) { if( m_alloc.is_alloc() ) return m_alloc.alloc().get_relocation(ofs); else - return AllocationPtr(); + return RelocationPtr(); } - else if( m_value && m_value->allocation ) + else if( m_value ) { - if( m_value->allocation.is_alloc() ) - return m_value->allocation.alloc().get_relocation(ofs); - else - return AllocationPtr(); + return m_value->get_relocation(ofs); } else { - return AllocationPtr(); + return RelocationPtr(); } } Value read_value(size_t ofs, size_t size) const; @@ -322,10 +352,10 @@ struct ValueRef if( m_alloc ) { switch(m_alloc.get_ty()) { - case AllocationPtr::Ty::Allocation: + case RelocationPtr::Ty::Allocation: return m_alloc.alloc().data_ptr() + m_offset; break; - case AllocationPtr::Ty::StdString: + case RelocationPtr::Ty::StdString: return reinterpret_cast<const uint8_t*>(m_alloc.str().data() + m_offset); default: throw "TODO"; @@ -347,10 +377,10 @@ struct ValueRef if( m_alloc ) { switch(m_alloc.get_ty()) { - case AllocationPtr::Ty::Allocation: + case RelocationPtr::Ty::Allocation: m_alloc.alloc().read_bytes(m_offset + ofs, dst, size); break; - case AllocationPtr::Ty::StdString: + case RelocationPtr::Ty::StdString: assert(m_offset+ofs <= m_alloc.str().size() && size <= m_alloc.str().size() && m_offset+ofs+size <= m_alloc.str().size()); ::std::memcpy(dst, m_alloc.str().data() + m_offset + ofs, size); break; @@ -372,10 +402,10 @@ struct ValueRef if( m_alloc ) { switch(m_alloc.get_ty()) { - case AllocationPtr::Ty::Allocation: + case RelocationPtr::Ty::Allocation: m_alloc.alloc().check_bytes_valid(m_offset + ofs, size); break; - case AllocationPtr::Ty::StdString: + case RelocationPtr::Ty::StdString: assert(m_offset+ofs <= m_alloc.str().size() && size <= m_alloc.str().size() && m_offset+ofs+size <= m_alloc.str().size()); break; default: @@ -389,19 +419,5 @@ struct ValueRef } bool compare(const void* other, size_t other_len) const; - - // TODO: Figure out how to make this use `ValueCommon` when it can't write. - uint8_t read_u8(size_t ofs) const { uint8_t rv; read_bytes(ofs, &rv, 1); return rv; } - uint16_t read_u16(size_t ofs) const { uint16_t rv; read_bytes(ofs, &rv, 2); return rv; } - uint32_t read_u32(size_t ofs) const { uint32_t rv; read_bytes(ofs, &rv, 4); return rv; } - uint64_t read_u64(size_t ofs) const { uint64_t rv; read_bytes(ofs, &rv, 8); return rv; } - int8_t read_i8(size_t ofs) const { return static_cast<int8_t>(read_u8(ofs)); } - int16_t read_i16(size_t ofs) const { return static_cast<int16_t>(read_u16(ofs)); } - int32_t read_i32(size_t ofs) const { return static_cast<int32_t>(read_u32(ofs)); } - int64_t read_i64(size_t ofs) const { return static_cast<int64_t>(read_u64(ofs)); } - float read_f32(size_t ofs) const { float rv; read_bytes(ofs, &rv, 4); return rv; } - double read_f64(size_t ofs) const { double rv; read_bytes(ofs, &rv, 8); return rv; } - uint64_t read_usize(size_t ofs) const; - int64_t read_isize(size_t ofs) const { return static_cast<int64_t>(read_usize(ofs)); } }; extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v); |