summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2018-03-07 22:09:19 +0800
committerJohn Hodge <tpg@mutabah.net>2018-03-17 18:52:16 +0800
commit4dca93d85c1cf0753183d7e4156ff925ac514b4d (patch)
tree5badd80fd8b8f346935331340651ec4e6a788041 /tools
parent912f54efc564f1928b70349960e0eee6020242fe (diff)
downloadmrust-4dca93d85c1cf0753183d7e4156ff925ac514b4d.tar.gz
Standalone MIRI - Coming along slowly.
Diffstat (limited to 'tools')
-rw-r--r--tools/standalone_miri/hir_sim.cpp41
-rw-r--r--tools/standalone_miri/hir_sim.hpp2
-rw-r--r--tools/standalone_miri/main.cpp257
-rw-r--r--tools/standalone_miri/module_tree.cpp2
-rw-r--r--tools/standalone_miri/value.cpp152
-rw-r--r--tools/standalone_miri/value.hpp77
6 files changed, 429 insertions, 102 deletions
diff --git a/tools/standalone_miri/hir_sim.cpp b/tools/standalone_miri/hir_sim.cpp
index e1b7faf8..85c05459 100644
--- a/tools/standalone_miri/hir_sim.cpp
+++ b/tools/standalone_miri/hir_sim.cpp
@@ -74,7 +74,9 @@ size_t HIR::TypeRef::get_size(size_t ofs) const
{
return POINTER_SIZE;
}
- LOG_TODO("Handle unsized struct " << *this);
+
+ // TODO: Ideally, this inner type wouldn't be unsized itself... but checking that would be interesting.
+ return POINTER_SIZE + this->composite_type->dst_meta.get_size();
}
else if( this->inner_type == RawType::Str )
return POINTER_SIZE*2;
@@ -94,7 +96,7 @@ size_t HIR::TypeRef::get_size(size_t ofs) const
return POINTER_SIZE;
}
case TypeWrapper::Ty::Slice:
- throw "Invalid";
+ LOG_BUG("Getting size of a slice - " << *this);
}
throw "";
}
@@ -128,6 +130,40 @@ HIR::TypeRef HIR::TypeRef::get_inner() const
ity.wrappers.erase(ity.wrappers.begin());
return ity;
}
+HIR::TypeRef HIR::TypeRef::wrap(TypeWrapper::Ty ty, size_t size) const
+{
+ auto rv = *this;
+ rv.wrappers.insert(rv.wrappers.begin(), { ty, size });
+ return rv;
+}
+const HIR::TypeRef* HIR::TypeRef::get_meta_type() const
+{
+ static ::HIR::TypeRef static_usize = ::HIR::TypeRef(RawType::USize);
+ if( this->wrappers.empty() )
+ {
+ switch(this->inner_type)
+ {
+ case RawType::Composite:
+ if( this->composite_type->dst_meta == RawType::Unreachable )
+ return nullptr;
+ return &this->composite_type->dst_meta;
+ case RawType::TraitObject:
+ LOG_TODO("get_meta_type on TraitObject - " << *this);
+ case RawType::Str:
+ return &static_usize;
+ default:
+ return nullptr;
+ }
+ }
+ else if( this->wrappers[0].type == TypeWrapper::Ty::Slice )
+ {
+ return &static_usize;
+ }
+ else
+ {
+ return nullptr;
+ }
+}
HIR::TypeRef HIR::TypeRef::get_field(size_t idx, size_t& ofs) const
{
@@ -135,6 +171,7 @@ HIR::TypeRef HIR::TypeRef::get_field(size_t idx, size_t& ofs) const
{
if( this->inner_type == RawType::Composite )
{
+ LOG_ASSERT(idx < this->composite_type->fields.size(), "Field " << idx << " out of bounds in type " << *this);
ofs = this->composite_type->fields.at(idx).first;
return this->composite_type->fields.at(idx).second;
}
diff --git a/tools/standalone_miri/hir_sim.hpp b/tools/standalone_miri/hir_sim.hpp
index 4b111d3e..504f0450 100644
--- a/tools/standalone_miri/hir_sim.hpp
+++ b/tools/standalone_miri/hir_sim.hpp
@@ -119,7 +119,9 @@ namespace HIR {
size_t get_size(size_t ofs=0) const;
bool has_slice_meta() const; // The attached metadata is a count
+ const TypeRef* get_meta_type() const;
TypeRef get_inner() const;
+ TypeRef wrap(TypeWrapper::Ty ty, size_t size) const;
TypeRef get_field(size_t idx, size_t& ofs) const;
bool operator==(const RawType& x) const {
diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp
index 703a6fab..d6cf6702 100644
--- a/tools/standalone_miri/main.cpp
+++ b/tools/standalone_miri/main.cpp
@@ -60,7 +60,7 @@ int main(int argc, const char* argv[])
catch(const DebugExceptionError& /*e*/)
{
::std::cerr << "Error encountered" << ::std::endl;
- throw;
+ return 1;
}
return 0;
@@ -291,7 +291,8 @@ struct Ops {
Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> args)
{
Value ret;
- TRACE_FUNCTION_R(path, path << " = " << ret);
+
+ const auto& fcn = modtree.get_function(path);
// TODO: Support overriding certain functions
@@ -304,19 +305,20 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
}
}
- const auto& fcn = modtree.get_function(path);
- for(size_t i = 0; i < args.size(); i ++)
- {
- LOG_DEBUG("- Argument(" << i << ") = " << args[i]);
- }
-
if( fcn.external.link_name != "" )
{
// External function!
ret = MIRI_Invoke_Extern(fcn.external.link_name, fcn.external.link_abi, ::std::move(args));
+ LOG_DEBUG(path << " = " << ret);
return ret;
}
+ TRACE_FUNCTION_R(path, path << " = " << ret);
+ for(size_t i = 0; i < args.size(); i ++)
+ {
+ LOG_DEBUG("- Argument(" << i << ") = " << args[i]);
+ }
+
ret = Value(fcn.ret_ty == RawType::Unreachable ? ::HIR::TypeRef() : fcn.ret_ty);
struct State
@@ -393,10 +395,16 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
TU_ARM(lv, Field, e) {
::HIR::TypeRef composite_ty;
auto base_val = get_value_and_type(*e.val, composite_ty);
- LOG_DEBUG("Field - " << composite_ty);
+ // TODO: if there's metadata present in the base, but the inner doesn't have metadata, clear the metadata
size_t inner_ofs;
ty = composite_ty.get_field(e.field_index, inner_ofs);
+ LOG_DEBUG("Field - " << composite_ty << "#" << e.field_index << " = @" << inner_ofs << " " << ty);
base_val.m_offset += inner_ofs;
+ if( !ty.get_meta_type() )
+ {
+ LOG_ASSERT(base_val.m_size >= ty.get_size(), "Field didn't fit in the value - " << ty.get_size() << " required, but " << base_val.m_size << " avail");
+ base_val.m_size = ty.get_size();
+ }
return base_val;
}
TU_ARM(lv, Downcast, e) {
@@ -413,33 +421,46 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
::HIR::TypeRef ptr_ty;
auto val = get_value_and_type(*e.val, ptr_ty);
ty = ptr_ty.get_inner();
- // TODO: Slices and slice-like types have the same logic.
- if( ty == RawType::Str || (!ty.wrappers.empty() && ty.wrappers.front().type == TypeWrapper::Ty::Slice) )
+ LOG_DEBUG("val = " << val);
+
+ LOG_ASSERT(val.m_size >= POINTER_SIZE, "Deref of a value that doesn't fit a pointer - " << ty);
+ 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);
+ LOG_ASSERT(alloc, "Deref of a value with no relocation");
+ if( alloc.is_alloc() )
+ {
+ LOG_DEBUG("> " << lv << " alloc=" << alloc.alloc());
+ }
+ size_t size;
+
+ const auto* meta_ty = ty.get_meta_type();
+ ::std::shared_ptr<Value> meta_val;
+ // If the type has metadata, store it.
+ if( meta_ty )
{
- LOG_ASSERT(val.m_size == 2*POINTER_SIZE, "Deref of " << ty << " that isn't a fat-pointer sized value");
- // 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_TRACE("Deref " << val_alloc.alloc());
- auto alloc = val_alloc.alloc().get_relocation(val.m_offset);
- LOG_ASSERT(alloc, "Deref of a value with no relocation");
- size_t ofs = val.read_usize(0);
- size_t size = val.read_usize(POINTER_SIZE);
- return ValueRef(::std::move(alloc), ofs, size);
+ auto meta_size = meta_ty->get_size();
+ LOG_ASSERT(val.m_size == POINTER_SIZE + meta_size, "Deref of " << ty << ", but pointer isn't correct size");
+ meta_val = ::std::make_shared<Value>( val.read_value(POINTER_SIZE, meta_size) );
+
+ // TODO: Get a more sane size from the metadata
+ LOG_DEBUG("> Meta " << *meta_val << ", size = " << alloc.get_size() << " - " << ofs);
+ size = alloc.get_size() - ofs;
}
- // TODO: Trait objects and trait-object likes
else
{
- LOG_ASSERT(val.m_size == POINTER_SIZE, "Deref of a value that isn't a pointer-sized value");
- // 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_TRACE("Deref " << val_alloc.alloc());
- auto alloc = val_alloc.alloc().get_relocation(val.m_offset);
- LOG_ASSERT(alloc, "Deref of a value with no relocation");
- size_t ofs = val.read_usize(0);
- return ValueRef(::std::move(alloc), ofs, ty.get_size());
+ LOG_ASSERT(val.m_size == POINTER_SIZE, "Deref of a value that isn't a pointer-sized value (size=" << val.m_size << ") - " << val << ": " << ptr_ty);
+ size = ty.get_size();
}
+
+ auto rv = ValueRef(::std::move(alloc), ofs, size);
+ rv.m_metadata = ::std::move(meta_val);
+ return rv;
} break;
}
throw "";
@@ -624,15 +645,17 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
else
LOG_DEBUG("- alloc=" << alloc);
size_t ofs = src_base_value.m_offset;
+ const auto* meta = src_ty.get_meta_type();
bool is_slice_like = src_ty.has_slice_meta();
src_ty.wrappers.insert(src_ty.wrappers.begin(), TypeWrapper { TypeWrapper::Ty::Borrow, static_cast<size_t>(re.type) });
new_val = Value(src_ty);
// ^ Pointer value
new_val.write_usize(0, ofs);
- if( is_slice_like )
+ if( meta )
{
- new_val.write_usize(POINTER_SIZE, src_base_value.m_size);
+ LOG_ASSERT(src_base_value.m_metadata, "Borrow of an unsized value, but no metadata avaliable");
+ 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) });
@@ -801,11 +824,13 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
case RawType::Str:
LOG_FATAL("Cast of unsized type - " << src_ty);
case RawType::Function:
- LOG_ASSERT(re.type.inner_type == RawType::USize, "");
+ LOG_ASSERT(re.type.inner_type == RawType::USize, "Function pointers can only be casted to usize, instead " << re.type);
new_val = src_value.read_value(0, re.type.get_size());
break;
case RawType::Char:
- LOG_TODO("Cast char to integer (only u32)");
+ LOG_ASSERT(re.type.inner_type == RawType::U32, "Char can only be casted to u32, instead " << re.type);
+ new_val = src_value.read_value(0, 4);
+ break;
case RawType::Unit:
LOG_FATAL("Cast of unit");
case RawType::Composite: {
@@ -964,8 +989,8 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
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 ? alloc_l.alloc().get_relocation(v_l.m_offset) : AllocationPtr();
- auto reloc_r = alloc_r ? alloc_r.alloc().get_relocation(v_r.m_offset) : AllocationPtr();
+ 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();
if( reloc_l != reloc_r )
{
@@ -1179,7 +1204,17 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
LOG_TODO(stmt);
} break;
TU_ARM(se.src, MakeDst, re) {
- LOG_TODO(stmt);
+ // - Get target type, just for some assertions
+ ::HIR::TypeRef dst_ty;
+ state.get_value_and_type(se.dst, dst_ty);
+ new_val = Value(dst_ty);
+
+ auto ptr = state.param_to_value(re.ptr_val );
+ auto meta = state.param_to_value(re.meta_val);
+ LOG_DEBUG("ty=" << dst_ty << ", ptr=" << ptr << ", meta=" << meta);
+
+ new_val.write_value(0, ::std::move(ptr));
+ new_val.write_value(POINTER_SIZE, ::std::move(meta));
} break;
TU_ARM(se.src, Tuple, re) {
::HIR::TypeRef dst_ty;
@@ -1227,6 +1262,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
const auto& data_ty = state.modtree.get_composite(re.path);
auto dst_ty = ::HIR::TypeRef(&data_ty);
new_val = Value(dst_ty);
+ LOG_DEBUG("Variant " << new_val);
// Three cases:
// - Unions (no tag)
// - Data enums (tag and data)
@@ -1238,6 +1274,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
new_val.write_value(fld.first, state.param_to_value(re.val));
}
+ LOG_DEBUG("Variant " << new_val);
if( var.base_field != SIZE_MAX )
{
::HIR::TypeRef tag_ty;
@@ -1249,6 +1286,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
{
// Union, no tag
}
+ LOG_DEBUG("Variant " << new_val);
} break;
TU_ARM(se.src, Struct, re) {
const auto& data_ty = state.modtree.get_composite(re.path);
@@ -1274,14 +1312,35 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
TU_ARM(stmt, Drop, se) {
if( se.flag_idx == ~0u || state.drop_flags.at(se.flag_idx) )
{
- auto drop_value = [](ValueRef v, const ::HIR::TypeRef& ty) {
+ auto drop_value = [&](ValueRef v, const ::HIR::TypeRef& ty) {
if( ty.wrappers.empty() )
{
if( ty.inner_type == RawType::Composite )
{
if( ty.composite_type->drop_glue != ::HIR::Path() )
{
- LOG_TODO("Drop - " << ty);
+ LOG_DEBUG("Drop - " << ty);
+
+ // - Take a pointer to the inner
+ auto alloc = v.m_alloc;
+ if( !alloc )
+ {
+ if( !v.m_value->allocation )
+ {
+ v.m_value->create_allocation();
+ }
+ alloc = AllocationPtr(v.m_value->allocation);
+ }
+ size_t ofs = v.m_offset;
+ assert(!ty.get_meta_type());
+
+ auto ptr_ty = ty.wrap(TypeWrapper::Ty::Borrow, 2);
+
+ auto ptr_val = Value(ptr_ty);
+ ptr_val.write_usize(0, ofs);
+ ptr_val.allocation.alloc().relocations.push_back(Relocation { 0, ::std::move(alloc) });
+
+ MIRI_Invoke(modtree, ty.composite_type->drop_glue, { ptr_val });
}
else
{
@@ -1290,7 +1349,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
}
else if( ty.inner_type == RawType::TraitObject )
{
- LOG_TODO("Drop - " << ty);
+ LOG_TODO("Drop - " << ty << " - trait object");
}
else
{
@@ -1312,7 +1371,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
// TODO: Arrays
else
{
- LOG_TODO("Drop - " << ty);
+ LOG_TODO("Drop - " << ty << " - array");
}
};
@@ -1384,6 +1443,8 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
// Read the value bytes
::std::vector<char> tmp( var.tag_data.size() );
v.read_bytes(tag_ofs, const_cast<char*>(tmp.data()), tmp.size());
+ if( v.get_relocation(tag_ofs) )
+ continue ;
if( ::std::memcmp(tmp.data(), var.tag_data.data(), tmp.size()) == 0 )
{
found_target = i;
@@ -1435,8 +1496,9 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
}
LOG_DEBUG("Call " << *fcn_p);
- state.write_lvalue(te.ret_val, MIRI_Invoke(modtree, *fcn_p, ::std::move(sub_args)));
- LOG_DEBUG("resume " << path);
+ auto v = MIRI_Invoke(modtree, *fcn_p, ::std::move(sub_args));
+ LOG_DEBUG(te.ret_val << " = " << v << " (resume " << path << ")");
+ state.write_lvalue(te.ret_val, ::std::move(v));
}
bb_idx = te.ret_block;
} continue;
@@ -1448,25 +1510,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
}
Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& abi, ::std::vector<Value> args)
{
- // WinAPI functions used by libstd
- if( link_name == "AddVectoredExceptionHandler" )
- {
- LOG_DEBUG("Call `AddVectoredExceptionHandler` - Ignoring and returning non-null");
- auto rv = Value(::HIR::TypeRef(RawType::USize));
- rv.write_usize(0, 1);
- return rv;
- }
-#ifdef _WIN32
- else if( link_name == "GetModuleHandleW" )
- {
- const void* arg0 = (args.at(0).allocation ? args.at(0).allocation.alloc().data_ptr() : nullptr);
- //extern void* GetModuleHandleW(const void* s);
-
- return Value::new_ffiptr(FFIPointer { "GetModuleHandleW", GetModuleHandleW(static_cast<LPCWSTR>(arg0)) });
- }
-#endif
- // Allocators!
- else if( link_name == "__rust_allocate" )
+ if( link_name == "__rust_allocate" )
{
auto size = args.at(0).read_usize(0);
auto align = args.at(1).read_usize(0);
@@ -1474,7 +1518,8 @@ Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& ab
::HIR::TypeRef rty { RawType::Unit };
rty.wrappers.push_back({ TypeWrapper::Ty::Pointer, 0 });
Value rv = Value(rty);
- // TODO: Use the alignment when making an allocation.
+ rv.write_usize(0, 0);
+ // TODO: Use the alignment when making an allocation?
rv.allocation.alloc().relocations.push_back({ 0, Allocation::new_alloc(size) });
return rv;
}
@@ -1493,10 +1538,76 @@ Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& ab
LOG_ASSERT(alloc_ptr.is_alloc(), "__rust_reallocate with no backing allocation attached to pointer");
auto& alloc = alloc_ptr.alloc();
// TODO: Check old size and alignment against allocation.
- alloc.data.resize(newsize);
+ alloc.data.resize( (newsize + 8-1) / 8 );
+ alloc.mask.resize( (newsize + 8-1) / 8 );
// TODO: Should this instead make a new allocation to catch use-after-free?
return ::std::move(args.at(0));
}
+#ifdef _WIN32
+ // WinAPI functions used by libstd
+ else if( link_name == "AddVectoredExceptionHandler" )
+ {
+ LOG_DEBUG("Call `AddVectoredExceptionHandler` - Ignoring and returning non-null");
+ auto rv = Value(::HIR::TypeRef(RawType::USize));
+ rv.write_usize(0, 1);
+ return rv;
+ }
+ else if( link_name == "GetModuleHandleW" )
+ {
+ LOG_ASSERT(args.at(0).allocation.is_alloc(), "");
+ const auto& tgt_alloc = args.at(0).allocation.alloc().get_relocation(0);
+ const void* arg0 = (tgt_alloc ? tgt_alloc.alloc().data_ptr() : nullptr);
+ //extern void* GetModuleHandleW(const void* s);
+ if(arg0) {
+ LOG_DEBUG("GetModuleHandleW(" << tgt_alloc.alloc() << ")");
+ }
+ else {
+ LOG_DEBUG("GetModuleHandleW(NULL)");
+ }
+
+ auto rv = GetModuleHandleW(static_cast<LPCWSTR>(arg0));
+ if(rv)
+ {
+ return Value::new_ffiptr(FFIPointer { "GetModuleHandleW", rv });
+ }
+ else
+ {
+ auto rv = Value(::HIR::TypeRef(RawType::USize));
+ rv.create_allocation();
+ rv.write_usize(0,0);
+ return rv;
+ }
+ }
+ else if( link_name == "GetProcAddress" )
+ {
+ LOG_ASSERT(args.at(0).allocation.is_alloc(), "");
+ const auto& handle_alloc = args.at(0).allocation.alloc().get_relocation(0);
+ LOG_ASSERT(args.at(1).allocation.is_alloc(), "");
+ const auto& sym_alloc = args.at(1).allocation.alloc().get_relocation(0);
+
+ // TODO: Ensure that first arg is a FFI pointer with offset+size of zero
+ void* handle = handle_alloc.ffi().ptr_value;
+ // TODO: Get either a FFI data pointer, or a inner data pointer
+ const void* symname = sym_alloc.alloc().data_ptr();
+ // TODO: Sanity check that it's a valid c string within its allocation
+ LOG_DEBUG("FFI GetProcAddress(" << handle << ", \"" << static_cast<const char*>(symname) << "\")");
+
+ auto rv = GetProcAddress(static_cast<HMODULE>(handle), static_cast<LPCSTR>(symname));
+
+ if( rv )
+ {
+ return Value::new_ffiptr(FFIPointer { "GetProcAddress", rv });
+ }
+ else
+ {
+ auto rv = Value(::HIR::TypeRef(RawType::USize));
+ rv.create_allocation();
+ rv.write_usize(0,0);
+ return rv;
+ }
+ }
+#endif
+ // Allocators!
else
{
LOG_TODO("Call external function " << link_name);
@@ -1558,16 +1669,15 @@ Value MIRI_Invoke_Intrinsic(const ModuleTree& modtree, const ::std::string& name
auto r = ptr_val.allocation.alloc().get_relocation(0);
auto orig_ofs = ptr_val.read_usize(0);
- auto delta_ofs = ptr_val.read_usize(0);
- auto new_ofs = orig_ofs + delta_ofs;
+ auto delta_counts = ofs_val.read_usize(0);
+ auto new_ofs = orig_ofs + delta_counts * ty_params.tys.at(0).get_size();
if(POINTER_SIZE != 8) {
new_ofs &= 0xFFFFFFFF;
}
-
ptr_val.write_usize(0, new_ofs);
ptr_val.allocation.alloc().relocations.push_back({ 0, r });
- return ptr_val;
+ rv = ::std::move(ptr_val);
}
// effectively ptr::write
else if( name == "move_val_init" )
@@ -1579,17 +1689,18 @@ Value MIRI_Invoke_Intrinsic(const ModuleTree& modtree, const ::std::string& name
// 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());
+ 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");
size_t ofs = ptr_val.read_usize(0);
const auto& ty = ty_params.tys.at(0);
alloc.alloc().write_value(ofs, ::std::move(data_val));
+ LOG_DEBUG(alloc.alloc());
}
else if( name == "uninit" )
{
- return Value(ty_params.tys.at(0));
+ rv = Value(ty_params.tys.at(0));
}
// ----------------------------------------------------------------
// Checked arithmatic
@@ -1667,7 +1778,9 @@ Value MIRI_Invoke_Intrinsic(const ModuleTree& modtree, const ::std::string& name
auto src_alloc = args.at(0).allocation.alloc().get_relocation(0);
auto dst_ofs = args.at(1).read_usize(0);
auto dst_alloc = args.at(1).allocation.alloc().get_relocation(0);
- auto byte_count = args.at(2).read_usize(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;
LOG_ASSERT(src_alloc, "Source of copy* must have an allocation");
LOG_ASSERT(dst_alloc, "Destination of copy* must be a memory allocation");
diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp
index 905e6aaf..2513140a 100644
--- a/tools/standalone_miri/module_tree.cpp
+++ b/tools/standalone_miri/module_tree.cpp
@@ -265,7 +265,7 @@ bool Parser::parse_one()
}
else
{
- LOG_BUG("");
+ LOG_BUG("Unexpected token in `type` - " << lex.next());
}
}
lex.check_consume('}');
diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp
index 168df328..18bed61e 100644
--- a/tools/standalone_miri/value.cpp
+++ b/tools/standalone_miri/value.cpp
@@ -104,6 +104,24 @@ AllocationPtr::~AllocationPtr()
}
}
}
+size_t AllocationPtr::get_size() const
+{
+ if( !*this )
+ return 0;
+ switch(get_ty())
+ {
+ case Ty::Allocation:
+ return alloc().size();
+ case Ty::Function:
+ return 0;
+ case Ty::StdString:
+ return str().size();
+ case Ty::FfiPointer:
+ return 0;
+ //return ffi().size;
+ }
+ throw "Unreachable";
+}
::std::ostream& operator<<(::std::ostream& os, const AllocationPtr& x)
{
@@ -167,6 +185,7 @@ void Allocation::mark_bytes_valid(size_t ofs, size_t size)
Value Allocation::read_value(size_t ofs, size_t size) const
{
Value rv;
+
// TODO: Determine if this can become an inline allocation.
bool has_reloc = false;
for(const auto& r : this->relocations)
@@ -189,11 +208,44 @@ Value Allocation::read_value(size_t ofs, size_t size) const
rv.allocation.alloc().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;
+ bool v = (this->mask[j/8] & (1 << j%8)) != 0;
+ if( v )
+ {
+ rv.allocation.alloc().mask[i/8] |= (1 << i%8);
+ }
+ else
+ {
+ rv.allocation.alloc().mask[i/8] &= ~(1 << i%8);
+ }
+ }
}
else
{
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 ++)
+ {
+ size_t j = ofs + i;
+ bool v = (this->mask[j/8] & (1 << j%8)) != 0;
+ if( v )
+ {
+ rv.direct_data.mask[i/8] |= (1 << i%8);
+ }
+ //else
+ //{
+ // rv.direct_data.mask[i/8] &= ~(1 << i%8);
+ //}
+ }
}
return rv;
}
@@ -240,7 +292,7 @@ void Allocation::write_value(size_t ofs, Value v)
// 2. Move the new relocations into this allocation
for(auto& r : new_relocs)
{
- LOG_TRACE("Insert " << r.backing_alloc);
+ //LOG_TRACE("Insert " << r.backing_alloc);
r.slot_ofs += ofs;
this->relocations.push_back( ::std::move(r) );
}
@@ -307,7 +359,7 @@ void Allocation::write_bytes(size_t ofs, const void* src, size_t count)
{
if( ofs <= it->slot_ofs && it->slot_ofs < ofs + count)
{
- LOG_TRACE("Delete " << it->backing_alloc);
+ //LOG_TRACE("Delete " << it->backing_alloc);
it = this_relocs.erase(it);
}
else
@@ -325,6 +377,8 @@ void Allocation::write_usize(size_t ofs, uint64_t v)
}
::std::ostream& operator<<(::std::ostream& os, const Allocation& x)
{
+ auto flags = os.flags();
+ os << ::std::hex;
for(size_t i = 0; i < x.size(); i++)
{
if( i != 0 )
@@ -339,6 +393,7 @@ void Allocation::write_usize(size_t ofs, uint64_t v)
os << "--";
}
}
+ os.setf(flags);
os << " {";
for(const auto& r : x.relocations)
@@ -408,6 +463,21 @@ Value::Value(::HIR::TypeRef ty)
//LOG_TRACE(" Creating allocation for " << ty);
this->allocation = Allocation::new_alloc(size);
}
+Value Value::with_size(size_t size, bool have_allocation)
+{
+ Value rv;
+ if(have_allocation)
+ {
+ rv.allocation = Allocation::new_alloc(size);
+ }
+ else
+ {
+ rv.direct_data.size = static_cast<uint8_t>(size);
+ rv.direct_data.mask[0] = 0;
+ rv.direct_data.mask[1] = 0;
+ }
+ return rv;
+}
Value Value::new_fnptr(const ::HIR::Path& fn_path)
{
Value rv( ::HIR::TypeRef(::HIR::CoreType { RawType::Function }) );
@@ -476,7 +546,7 @@ void Value::mark_bytes_valid(size_t ofs, size_t size)
}
else
{
- for(size_t i = 0; i < this->direct_data.size; i++)
+ for(size_t i = ofs; i < ofs+size; i++)
{
this->direct_data.mask[i/8] |= (1 << i%8);
}
@@ -567,8 +637,17 @@ void Value::write_value(size_t ofs, Value v)
}
else
{
- v.check_bytes_valid(0, v.direct_data.size);
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 ++)
+ {
+ 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;
+ }
}
}
}
@@ -606,36 +685,65 @@ void Value::write_usize(size_t ofs, uint64_t v)
}
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 )
{
const auto& alloc_ptr = v.m_alloc ? v.m_alloc : v.m_value->allocation;
// TODO: What if alloc_ptr isn't a data allocation?
- const auto& alloc = alloc_ptr.alloc();
-
- for(size_t i = v.m_offset; i < ::std::min(alloc.size(), v.m_offset + v.m_size); i++)
+ switch(alloc_ptr.get_ty())
{
- if( i != 0 )
- os << " ";
-
- if( alloc.mask[i/8] & (1 << i%8) )
+ case AllocationPtr::Ty::Allocation: {
+ const auto& alloc = alloc_ptr.alloc();
+
+ 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++)
{
- os << ::std::setw(2) << ::std::setfill('0') << (int)alloc.data_ptr()[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 << "--";
+ }
}
- else
+ os.setf(flags);
+
+ os << " {";
+ for(const auto& r : alloc.relocations)
{
- os << "--";
+ 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 << " {";
- for(const auto& r : alloc.relocations)
- {
- if( v.m_offset <= r.slot_ofs && r.slot_ofs < v.m_offset + v.m_size )
+ os << " }";
+ } break;
+ case AllocationPtr::Ty::Function:
+ LOG_TODO("ValueRef to " << alloc_ptr);
+ break;
+ case AllocationPtr::Ty::StdString: {
+ const auto& s = alloc_ptr.str();
+ assert(v.m_offset < s.size());
+ assert(v.m_size < s.size());
+ assert(v.m_offset + v.m_size <= s.size());
+ auto flags = os.flags();
+ os << ::std::hex;
+ for(size_t i = v.m_offset; i < v.m_offset + v.m_size; i++)
{
- os << " @" << (r.slot_ofs - v.m_offset) << "=" << r.backing_alloc;
+ os << ::std::setw(2) << ::std::setfill('0') << (int)s.data()[i];
}
+ os.setf(flags);
+ } break;
+ case AllocationPtr::Ty::FfiPointer:
+ LOG_TODO("ValueRef to " << alloc_ptr);
+ break;
}
- os << " }";
}
else
{
diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp
index ca15dea9..3dfdd369 100644
--- a/tools/standalone_miri/value.hpp
+++ b/tools/standalone_miri/value.hpp
@@ -60,8 +60,10 @@ public:
return *this;
}
+ size_t get_size() const;
+
operator bool() const { return m_ptr != 0; }
- bool is_alloc() {
+ bool is_alloc() const {
return *this && get_ty() == Ty::Allocation;
}
Allocation& alloc() {
@@ -183,6 +185,7 @@ struct Value
Value();
Value(::HIR::TypeRef ty);
+ static Value with_size(size_t size, bool have_allocation);
static Value new_fnptr(const ::HIR::Path& fn_path);
static Value new_ffiptr(FFIPointer ffi);
@@ -233,8 +236,9 @@ struct ValueRef
// Either an AllocationPtr, or a Value pointer
AllocationPtr m_alloc;
Value* m_value;
- size_t m_offset;
- size_t m_size;
+ 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):
m_alloc(ptr),
@@ -242,6 +246,21 @@ struct ValueRef
m_offset(ofs),
m_size(size)
{
+ switch(m_alloc.get_ty())
+ {
+ case AllocationPtr::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:
+ assert(ofs < m_alloc.str().size());
+ assert(size <= m_alloc.str().size());
+ assert(ofs+size <= m_alloc.str().size());
+ break;
+ default:
+ throw "TODO";
+ }
}
ValueRef(Value& val):
ValueRef(val, 0, val.size())
@@ -254,6 +273,26 @@ struct ValueRef
{
}
+ AllocationPtr get_relocation(size_t ofs) const {
+ if(m_alloc)
+ {
+ if( m_alloc.is_alloc() )
+ return m_alloc.alloc().get_relocation(ofs);
+ else
+ return AllocationPtr();
+ }
+ else if( m_value->allocation )
+ {
+ if( m_value->allocation.is_alloc() )
+ return m_value->allocation.alloc().get_relocation(ofs);
+ else
+ return AllocationPtr();
+ }
+ else
+ {
+ return AllocationPtr();
+ }
+ }
Value read_value(size_t ofs, size_t size) const {
if( size == 0 )
return Value();
@@ -261,7 +300,23 @@ struct ValueRef
assert(size <= m_size);
assert(ofs+size <= m_size);
if( m_alloc ) {
- return m_alloc.alloc().read_value(m_offset + ofs, size);
+ switch(m_alloc.get_ty())
+ {
+ case AllocationPtr::Ty::Allocation:
+ return m_alloc.alloc().read_value(m_offset + ofs, size);
+ case AllocationPtr::Ty::StdString: {
+ auto rv = Value::with_size(size, false);
+ //ASSERT_BUG(ofs <= m_alloc.str().size(), "");
+ //ASSERT_BUG(size <= m_alloc.str().size(), "");
+ //ASSERT_BUG(ofs+size <= m_alloc.str().size(), "");
+ assert(m_offset+ofs <= m_alloc.str().size() && size <= m_alloc.str().size() && m_offset+ofs+size <= m_alloc.str().size());
+ rv.write_bytes(0, m_alloc.str().data() + m_offset + ofs, size);
+ return rv;
+ }
+ default:
+ //ASSERT_BUG(m_alloc.is_alloc(), "read_value on non-data backed Value - " << );
+ throw "TODO";
+ }
}
else {
return m_value->read_value(m_offset + ofs, size);
@@ -274,7 +329,19 @@ struct ValueRef
assert(size <= m_size);
assert(ofs+size <= m_size);
if( m_alloc ) {
- m_alloc.alloc().read_bytes(m_offset + ofs, dst, size);
+ switch(m_alloc.get_ty())
+ {
+ case AllocationPtr::Ty::Allocation:
+ m_alloc.alloc().read_bytes(m_offset + ofs, dst, size);
+ break;
+ case AllocationPtr::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;
+ default:
+ //ASSERT_BUG(m_alloc.is_alloc(), "read_value on non-data backed Value - " << );
+ throw "TODO";
+ }
}
else {
m_value->read_bytes(m_offset + ofs, dst, size);