From 144bd3cdcea986f907468074365dfd17893a0f0f Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 12 May 2018 12:52:46 +0800 Subject: Standalone Miri - Linux build support --- tools/standalone_miri/module_tree.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/standalone_miri/module_tree.cpp') diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index 2513140a..d62695d1 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -5,6 +5,7 @@ #include "lex.hpp" #include "value.hpp" #include +#include // std::find #include "debug.hpp" ModuleTree::ModuleTree() @@ -1328,4 +1329,4 @@ Value* ModuleTree::get_static_opt(const ::HIR::Path& p) return nullptr; } return &it->second; -} \ No newline at end of file +} -- cgit v1.2.3 From 835519441441dcff3bb39e9a82f433a37c61d6ef Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 12 May 2018 17:54:27 +0800 Subject: Standalone MIRI - Get type for statics, add some pthread_* FFI stubs --- tools/standalone_miri/main.cpp | 43 +++++++++++++++++++++++++++-------- tools/standalone_miri/module_tree.cpp | 12 ++++++---- tools/standalone_miri/module_tree.hpp | 17 ++++++++------ 3 files changed, 50 insertions(+), 22 deletions(-) (limited to 'tools/standalone_miri/module_tree.cpp') diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index 86a213dd..e3c7ab50 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -433,8 +433,9 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar return ValueRef(args.at(e.idx), 0, args.at(e.idx).size()); } break; TU_ARM(lv, Static, e) { - // TODO: Type! - return ValueRef(modtree.get_static(e), 0, modtree.get_static(e).size()); + /*const*/ auto& s = modtree.get_static(e); + ty = s.ty; + return ValueRef(s.val, 0, s.val.size()); } break; TU_ARM(lv, Index, e) { auto idx = get_value_ref(*e.idx).read_usize(0); @@ -678,7 +679,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar for(const auto& stmt : bb.statements) { - LOG_DEBUG("BB" << bb_idx << "/" << (&stmt - bb.statements.data()) << ": " << stmt); + LOG_DEBUG("=== BB" << bb_idx << "/" << (&stmt - bb.statements.data()) << ": " << stmt); switch(stmt.tag()) { case ::MIR::Statement::TAGDEAD: throw ""; @@ -1424,7 +1425,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar } } - LOG_DEBUG("BB" << bb_idx << "/TERM: " << bb.terminator); + LOG_DEBUG("=== BB" << bb_idx << "/TERM: " << bb.terminator); switch(bb.terminator.tag()) { case ::MIR::Terminator::TAGDEAD: throw ""; @@ -1522,7 +1523,8 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar 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)"); const auto& fcn_alloc_ptr = alloc_ptr.alloc().get_relocation(v.m_offset); - LOG_ASSERT(fcn_alloc_ptr, "Calling value with no relocation"); + 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"); fcn_p = &fcn_alloc_ptr.fcn(); } @@ -1671,6 +1673,30 @@ Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& ab rv.write_usize(0, val); return rv; } + else if( link_name == "pthread_mutex_init" || link_name == "pthread_mutex_lock" || link_name == "pthread_mutex_unlock" ) + { + auto rv = Value(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, 0); + return rv; + } + else if( link_name == "pthread_mutexattr_init" || link_name == "pthread_mutexattr_settype" || link_name == "pthread_mutexattr_destroy" ) + { + auto rv = Value(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, 0); + return rv; + } + else if( link_name == "pthread_condattr_init" || link_name == "pthread_condattr_destroy" || link_name == "pthread_condattr_setclock" ) + { + auto rv = Value(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, 0); + return rv; + } + else if( link_name == "pthread_cond_init" || link_name == "pthread_cond_destroy" ) + { + auto rv = Value(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, 0); + return rv; + } #endif // std C else if( link_name == "signal" ) @@ -1684,15 +1710,12 @@ Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& ab else if( link_name == "memchr" ) { LOG_ASSERT(args.at(0).allocation.is_alloc(), ""); - //size_t ptr_space; - //void* ptr = args.at(0).read_pointer(0, ptr_space); auto ptr_alloc = args.at(0).allocation.alloc().get_relocation(0); - void* ptr = ptr_alloc.alloc().data_ptr() + args.at(0).read_usize(0); auto c = args.at(1).read_i32(0); auto n = args.at(2).read_usize(0); - // TODO: Check range of `n` + const void* ptr = args.at(0).read_pointer_const(0, n); - void* ret = memchr(ptr, c, n); + const void* ret = memchr(ptr, c, n); auto rv = Value(::HIR::TypeRef(RawType::USize)); rv.create_allocation(); diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index d62695d1..d6c7dcec 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -154,10 +154,12 @@ bool Parser::parse_one() } lex.check_consume(';'); - Value val = Value(ty); - val.write_bytes(0, data.data(), data.size()); + Static s; + s.val = Value(ty); + s.val.write_bytes(0, data.data(), data.size()); + s.ty = ty; - tree.statics.insert(::std::make_pair( ::std::move(p), ::std::move(val) )); + tree.statics.insert(::std::make_pair( ::std::move(p), ::std::move(s) )); } else if( lex.consume_if("type") ) { @@ -1311,7 +1313,7 @@ const Function* ModuleTree::get_function_opt(const ::HIR::Path& p) const } return &it->second; } -Value& ModuleTree::get_static(const ::HIR::Path& p) +Static& ModuleTree::get_static(const ::HIR::Path& p) { auto it = statics.find(p); if(it == statics.end()) @@ -1321,7 +1323,7 @@ Value& ModuleTree::get_static(const ::HIR::Path& p) } return it->second; } -Value* ModuleTree::get_static_opt(const ::HIR::Path& p) +Static* ModuleTree::get_static_opt(const ::HIR::Path& p) { auto it = statics.find(p); if(it == statics.end()) diff --git a/tools/standalone_miri/module_tree.hpp b/tools/standalone_miri/module_tree.hpp index ca24b06a..5479d9ef 100644 --- a/tools/standalone_miri/module_tree.hpp +++ b/tools/standalone_miri/module_tree.hpp @@ -9,15 +9,14 @@ #include "../../src/mir/mir.hpp" #include "hir_sim.hpp" - -struct Value; +#include "value.hpp" struct Function { ::HIR::Path my_path; ::std::vector<::HIR::TypeRef> args; ::HIR::TypeRef ret_ty; - + // If `link_name` is non-empty, then the function is an external struct { ::std::string link_name; @@ -25,6 +24,11 @@ struct Function } external; ::MIR::Function m_mir; }; +struct Static +{ + ::HIR::TypeRef ty; + Value val; +}; /// Container for loaded code and structures class ModuleTree @@ -34,8 +38,7 @@ class ModuleTree ::std::set<::std::string> loaded_files; ::std::map<::HIR::Path, Function> functions; - ::std::map<::HIR::Path, Value> statics; - // TODO: statics + ::std::map<::HIR::Path, Static> statics; // Hack: Tuples are stored as `::""::` ::std::map<::HIR::GenericPath, ::std::unique_ptr> data_types; @@ -47,8 +50,8 @@ public: ::HIR::SimplePath find_lang_item(const char* name) const; const Function& get_function(const ::HIR::Path& p) const; const Function* get_function_opt(const ::HIR::Path& p) const; - Value& get_static(const ::HIR::Path& p); - Value* get_static_opt(const ::HIR::Path& p); + Static& get_static(const ::HIR::Path& p); + Static* get_static_opt(const ::HIR::Path& p); const DataType& get_composite(const ::HIR::GenericPath& p) const { return *data_types.at(p); -- cgit v1.2.3 From 11574b8b30b87fdc130f4e276839eda52860582b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 12 May 2018 18:21:36 +0800 Subject: Standalone MIRI - Better handling of statics --- tools/standalone_miri/main.cpp | 23 ++++++++++++++++++++--- tools/standalone_miri/module_tree.cpp | 19 ++++++++++++------- 2 files changed, 32 insertions(+), 10 deletions(-) (limited to 'tools/standalone_miri/module_tree.cpp') diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index e3c7ab50..c9cc7f38 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -627,9 +627,18 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar TU_ARM(c, ItemAddr, ce) { // Create a value with a special backing allocation of zero size that references the specified item. if( const auto* fn = modtree.get_function_opt(ce) ) { + ty = ::HIR::TypeRef(RawType::Function); return Value::new_fnptr(ce); } - LOG_TODO("Constant::ItemAddr - statics?"); + if( const auto* s = modtree.get_static_opt(ce) ) { + ty = s->ty; + 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 }); + return val; + } + LOG_TODO("Constant::ItemAddr - " << ce << " - not found"); } break; } throw ""; @@ -1510,6 +1519,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar } else { + AllocationPtr fcn_alloc_ptr; const ::HIR::Path* fcn_p; if( te.fcn.is_Path() ) { fcn_p = &te.fcn.as_Path(); @@ -1517,12 +1527,13 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar else { ::HIR::TypeRef ty; auto v = state.get_value_and_type(te.fcn.as_Value(), ty); + LOG_DEBUG("> Indirect call " << v); // TODO: Assert type // TODO: Assert offset/content. assert(v.read_usize(v.m_offset) == 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)"); - const auto& fcn_alloc_ptr = alloc_ptr.alloc().get_relocation(v.m_offset); + fcn_alloc_ptr = alloc_ptr.alloc().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"); @@ -1697,6 +1708,12 @@ Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& ab rv.write_i32(0, 0); return rv; } + else if( link_name == "pthread_key_create" || link_name == "pthread_key_delete" ) + { + auto rv = Value(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, 0); + return rv; + } #endif // std C else if( link_name == "signal" ) @@ -1761,7 +1778,7 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, const ::std::string& name, cons const auto& ty = ty_params.tys.at(0); alloc.alloc().write_value(ofs, ::std::move(data_val)); } - else if( name == "atomic_load" ) + else if( name == "atomic_load" || name == "atomic_load_relaxed" ) { auto& ptr_val = args.at(0); LOG_ASSERT(ptr_val.size() == POINTER_SIZE, "atomic_store of a value that isn't a pointer-sized value"); diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index d6c7dcec..f6b681cf 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -121,6 +121,15 @@ bool Parser::parse_one() lex.check_consume('='); lex.check(TokenClass::String); auto data = ::std::move(lex.consume().strval); + + Static s; + s.val = Value(ty); + // - Statics need to always have an allocation (for references) + if( !s.val.allocation ) + s.val.create_allocation(); + s.val.write_bytes(0, data.data(), data.size()); + s.ty = ty; + if( lex.consume_if('{') ) { while( !lex.consume_if('}') ) @@ -135,12 +144,13 @@ bool Parser::parse_one() if( lex.next() == TokenClass::String ) { auto reloc_str = ::std::move(lex.consume().strval); - // TODO: Add relocation + // TODO: Figure out how to create this allocation... + //s.val.allocation.alloc().relocations.push_back({ ofs, AllocationPtr::new_string(reloc_str) }); } else if( lex.next() == "::" ) { auto reloc_path = parse_path(); - // TODO: Add relocation + s.val.allocation.alloc().relocations.push_back({ ofs, AllocationPtr::new_fcn(reloc_path) }); } else { @@ -154,11 +164,6 @@ bool Parser::parse_one() } lex.check_consume(';'); - Static s; - s.val = Value(ty); - s.val.write_bytes(0, data.data(), data.size()); - s.ty = ty; - tree.statics.insert(::std::make_pair( ::std::move(p), ::std::move(s) )); } else if( lex.consume_if("type") ) -- cgit v1.2.3 From d8928895e318b026f106a30f145d6a41be74cb0f Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 12 May 2018 19:05:54 +0800 Subject: Standalone MIRI - Fiddling around --- tools/standalone_miri/main.cpp | 14 +++++++++----- tools/standalone_miri/module_tree.cpp | 3 ++- 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'tools/standalone_miri/module_tree.cpp') diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index c9cc7f38..b7f62252 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -378,6 +378,8 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar return ret; } + // TODO: Recursion limit. + TRACE_FUNCTION_R(path, path << " = " << ret); for(size_t i = 0; i < args.size(); i ++) { @@ -809,11 +811,13 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar switch(re.type.inner_type) { case RawType::Unreachable: throw "BUG"; - case RawType::Composite: throw "ERROR"; - case RawType::TraitObject: throw "ERROR"; - case RawType::Function: throw "ERROR"; - case RawType::Str: throw "ERROR"; - case RawType::Unit: throw "ERROR"; + case RawType::Composite: + case RawType::TraitObject: + case RawType::Function: + case RawType::Str: + case RawType::Unit: + LOG_ERROR("Casting to " << re.type << " is invalid"); + throw "ERROR"; case RawType::F32: { float dst_val = 0.0; // Can be an integer, or F64 (pointer is impossible atm) diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index f6b681cf..a75cfa8f 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -147,13 +147,14 @@ bool Parser::parse_one() // TODO: Figure out how to create this allocation... //s.val.allocation.alloc().relocations.push_back({ ofs, AllocationPtr::new_string(reloc_str) }); } - else if( lex.next() == "::" ) + else if( lex.next() == "::" || lex.next() == "<" ) { auto reloc_path = parse_path(); s.val.allocation.alloc().relocations.push_back({ ofs, AllocationPtr::new_fcn(reloc_path) }); } else { + LOG_FATAL(lex << "Unexepcted token " << lex.next() << " in relocation value"); throw "ERROR"; } if( ! lex.consume_if(',') ) { -- cgit v1.2.3 From ac6f3ffba823e539c4c9afd93b7edf7122f463cc Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 13 May 2018 09:27:13 +0800 Subject: Standalone MIRI - Better vtable handling, fix to offset with null pointers --- tools/standalone_miri/hir_sim.cpp | 30 +++++++++++-------- tools/standalone_miri/hir_sim.hpp | 6 ++-- tools/standalone_miri/main.cpp | 31 +++++++++---------- tools/standalone_miri/module_tree.cpp | 56 +++++++++++++++++------------------ 4 files changed, 65 insertions(+), 58 deletions(-) (limited to 'tools/standalone_miri/module_tree.cpp') diff --git a/tools/standalone_miri/hir_sim.cpp b/tools/standalone_miri/hir_sim.cpp index 604f65a4..f3b4d400 100644 --- a/tools/standalone_miri/hir_sim.cpp +++ b/tools/standalone_miri/hir_sim.cpp @@ -166,32 +166,34 @@ const HIR::TypeRef* HIR::TypeRef::get_usized_type(size_t& running_inner_size) co return nullptr; } } -const HIR::TypeRef* HIR::TypeRef::get_meta_type() 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); + return TypeRef(RawType::Unreachable); + return this->composite_type->dst_meta; + case RawType::TraitObject: { + auto rv = ::HIR::TypeRef( this->composite_type ); + rv.wrappers.push_back(TypeWrapper { TypeWrapper::Ty::Pointer, static_cast(BorrowType::Shared) }); + return rv; + } case RawType::Str: - return &static_usize; + return TypeRef(RawType::USize); default: - return nullptr; + return TypeRef(RawType::Unreachable); } } else if( this->wrappers[0].type == TypeWrapper::Ty::Slice ) { - return &static_usize; + return TypeRef(RawType::USize); } else { - return nullptr; + return TypeRef(RawType::Unreachable); } } @@ -305,7 +307,11 @@ namespace HIR { os << "function_?"; break; case RawType::TraitObject: - os << "traitobject_?"; + os << "dyn "; + if( x.composite_type ) + os << x.composite_type->my_path; + else + os << "?"; break; case RawType::Bool: os << "bool"; break; case RawType::Char: os << "char"; break; @@ -385,4 +391,4 @@ namespace HIR { } return os; } -} \ No newline at end of file +} diff --git a/tools/standalone_miri/hir_sim.hpp b/tools/standalone_miri/hir_sim.hpp index 7154de13..1dc9bcc4 100644 --- a/tools/standalone_miri/hir_sim.hpp +++ b/tools/standalone_miri/hir_sim.hpp @@ -23,7 +23,7 @@ struct DataType; enum class RawType { Unreachable, - Function, + Function, // TODO: Needs a way of indicating the signature? Unit, Bool, @@ -39,7 +39,7 @@ enum class RawType Char, Str, Composite, // Struct, Enum, Union, tuple, ... - TraitObject, // Data pointer is `*const ()`, metadata type stored in `composite_type` + TraitObject, // Data pointer is `*const ()`, vtable type stored in `composite_type` }; struct TypeWrapper { @@ -120,7 +120,7 @@ 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_usized_type(size_t& running_inner_size) const; - const TypeRef* get_meta_type() 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; diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index e5ef9c15..16cfd972 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -503,7 +503,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: 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() ) + if( ty.get_meta_type() == HIR::TypeRef(RawType::Unreachable) ) { 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(); @@ -542,12 +542,12 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: } size_t size; - const auto* meta_ty = ty.get_meta_type(); + const auto meta_ty = ty.get_meta_type(); ::std::shared_ptr meta_val; // If the type has metadata, store it. - if( meta_ty ) + if( meta_ty != RawType::Unreachable ) { - auto meta_size = meta_ty->get_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( val.read_value(POINTER_SIZE, meta_size) ); @@ -768,14 +768,14 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: else LOG_DEBUG("- alloc=" << alloc); size_t ofs = src_base_value.m_offset; - const auto* meta = src_ty.get_meta_type(); + 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(re.type) }); new_val = Value(src_ty); // ^ Pointer value new_val.write_usize(0, ofs); - if( meta ) + if( meta != RawType::Unreachable ) { 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); @@ -1460,7 +1460,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: alloc = AllocationPtr(v.m_value->allocation); } size_t ofs = v.m_offset; - assert(!ty.get_meta_type()); + assert(ty.get_meta_type() == RawType::Unreachable); auto ptr_ty = ty.wrap(TypeWrapper::Ty::Borrow, 2); @@ -1954,20 +1954,21 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st } else if( name == "offset" ) { - auto ptr_val = ::std::move(args.at(0)); + auto ptr_alloc = args.at(0).get_relocation(0); + auto ptr_ofs = args.at(0).read_usize(0); auto& ofs_val = args.at(1); - auto r = ptr_val.allocation.alloc().get_relocation(0); - auto orig_ofs = ptr_val.read_usize(0); auto delta_counts = ofs_val.read_usize(0); - auto new_ofs = orig_ofs + delta_counts * ty_params.tys.at(0).get_size(); + auto new_ofs = ptr_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 }); - rv = ::std::move(ptr_val); + rv = ::std::move(args.at(0)); + rv.write_usize(0, new_ofs); + if( ptr_alloc ) { + rv.allocation.alloc().relocations.push_back({ 0, ptr_alloc }); + } } // effectively ptr::write else if( name == "move_val_init" ) @@ -2008,7 +2009,7 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st size_t fixed_size = 0; if( const auto* ity = ty.get_usized_type(fixed_size) ) { - const auto& meta_ty = *ty.get_meta_type(); + const auto meta_ty = ty.get_meta_type(); LOG_DEBUG("size_of_val - " << ty << " ity=" << *ity << " meta_ty=" << meta_ty << " fixed_size=" << fixed_size); size_t flex_size = 0; if( !ity->wrappers.empty() ) diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index a75cfa8f..fdc8f587 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -32,6 +32,8 @@ struct Parser RawType parse_core_type(); ::HIR::TypeRef parse_type(); ::HIR::GenericPath parse_tuple(); + + const DataType* get_composite(::HIR::GenericPath gp); }; void ModuleTree::load_file(const ::std::string& path) @@ -1130,19 +1132,8 @@ RawType Parser::parse_core_type() // Tuples! Should point to a composite ::HIR::GenericPath gp = parse_tuple(); - // Look up this type, then create a TypeRef referring to the type in the datastore - // - May need to create an unpopulated type? - auto it = tree.data_types.find(gp); - if( it == tree.data_types.end() ) - { - // TODO: Later on need to check if the type is valid. - auto v = ::std::make_unique(DataType {}); - v->my_path = gp; - auto ir = tree.data_types.insert(::std::make_pair( ::std::move(gp), ::std::move(v)) ); - it = ir.first; - } // Good. - return ::HIR::TypeRef(it->second.get()); + return ::HIR::TypeRef( this->get_composite(::std::move(gp)) ); } else if( lex.consume_if('[') ) { @@ -1155,7 +1146,6 @@ RawType Parser::parse_core_type() } else { - // TODO: How to handle arrays? rv.wrappers.insert( rv.wrappers.begin(), { TypeWrapper::Ty::Slice, 0 }); } lex.check_consume(']'); @@ -1196,19 +1186,7 @@ RawType Parser::parse_core_type() else if( lex.next() == "::" ) { auto path = parse_genericpath(); - // Look up this type, then create a TypeRef referring to the type in the datastore - // - May need to create an unpopulated type? - auto it = tree.data_types.find(path); - if( it == tree.data_types.end() ) - { - // TODO: Later on need to check if the type is valid. - auto v = ::std::make_unique(DataType {}); - v->my_path = path; - auto ir = tree.data_types.insert(::std::make_pair( ::std::move(path), ::std::move(v)) ); - it = ir.first; - } - // Good. - return ::HIR::TypeRef(it->second.get()); + return ::HIR::TypeRef( this->get_composite(::std::move(path))); } else if( lex.next() == "extern" || lex.next() == "fn" || lex.next() == "unsafe" ) { @@ -1282,8 +1260,17 @@ RawType Parser::parse_core_type() markers.push_back(parse_genericpath()); } lex.consume_if(')'); - return ::HIR::TypeRef(RawType::TraitObject); - // TODO: Generate the vtable path and locate that struct + + auto rv = ::HIR::TypeRef(RawType::TraitObject); + if( base_trait != ::HIR::GenericPath() ) + { + // Generate vtable path + auto vtable_path = base_trait; + vtable_path.m_simplepath.ents.back() += "#vtable"; + // - TODO: Associated types? + rv.composite_type = this->get_composite( ::std::move(vtable_path) ); + } + return rv; } else if( lex.next() == TokenClass::Ident ) { @@ -1295,6 +1282,19 @@ RawType Parser::parse_core_type() throw "ERROR"; } } +const DataType* Parser::get_composite(::HIR::GenericPath gp) +{ + auto it = tree.data_types.find(gp); + if( it == tree.data_types.end() ) + { + // TODO: Later on need to check if the type is valid. + auto v = ::std::make_unique(DataType {}); + v->my_path = gp; + auto ir = tree.data_types.insert(::std::make_pair( ::std::move(gp), ::std::move(v)) ); + it = ir.first; + } + return it->second.get(); +} ::HIR::SimplePath ModuleTree::find_lang_item(const char* name) const { -- cgit v1.2.3 From d3334162fa91fe6fd5d02912d9f82794306e646a Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 13 May 2018 09:54:54 +0800 Subject: Standalone MIRI - Create allocations for static data --- tools/standalone_miri/module_tree.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'tools/standalone_miri/module_tree.cpp') diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index fdc8f587..c70f17dd 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -146,8 +146,11 @@ bool Parser::parse_one() if( lex.next() == TokenClass::String ) { auto reloc_str = ::std::move(lex.consume().strval); - // TODO: Figure out how to create this allocation... - //s.val.allocation.alloc().relocations.push_back({ ofs, AllocationPtr::new_string(reloc_str) }); + + 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) }); } else if( lex.next() == "::" || lex.next() == "<" ) { -- cgit v1.2.3 From 689722fa920cfa74880922ac626cc935b202acc4 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 13 May 2018 14:08:55 +0800 Subject: Standalone MIRI - Shallow drops and better tracing --- tools/standalone_miri/main.cpp | 76 ++++++++++++++++++++++++++++++----- tools/standalone_miri/module_tree.cpp | 2 +- tools/standalone_miri/value.cpp | 52 ++++++++++++++++-------- tools/standalone_miri/value.hpp | 11 +++-- 4 files changed, 109 insertions(+), 32 deletions(-) (limited to 'tools/standalone_miri/module_tree.cpp') diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index d210849c..97ca8e6f 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -314,8 +314,22 @@ struct Ops { namespace { - void drop_value(ModuleTree& modtree, ThreadState& thread, Value ptr, const ::HIR::TypeRef& ty) + void drop_value(ModuleTree& modtree, ThreadState& thread, Value ptr, const ::HIR::TypeRef& ty, bool is_shallow=false) { + if( is_shallow ) + { + // HACK: Only works for Box where the first pointer is the data pointer + auto box_ptr_vr = ptr.read_pointer_valref_mut(0, POINTER_SIZE); + auto ofs = box_ptr_vr.read_usize(0); + auto alloc = box_ptr_vr.get_relocation(0); + if( ofs != 0 || !alloc || !alloc.is_alloc() ) { + LOG_ERROR("Attempting to shallow drop with invalid pointer (no relocation or non-zero offset) - " << box_ptr_vr); + } + + LOG_DEBUG("drop_value SHALLOW deallocate " << alloc); + alloc.alloc().mark_as_freed(); + return ; + } if( ty.wrappers.empty() ) { if( ty.inner_type == RawType::Composite ) @@ -1479,7 +1493,8 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: ptr_val.write_usize(0, ofs); ptr_val.allocation.alloc().relocations.push_back(Relocation { 0, ::std::move(alloc) }); - drop_value(modtree, thread, ptr_val, ty); + // TODO: Shallow drop + drop_value(modtree, thread, ptr_val, ty, /*shallow=*/se.kind == ::MIR::eDropKind::SHALLOW); // TODO: Clear validity on the entire inner value. //alloc.mark_as_freed(); } @@ -1618,6 +1633,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: extern "C" { long sysconf(int); + ssize_t write(int, const void*, size_t); } Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std::string& link_name, const ::std::string& abi, ::std::vector args) @@ -1661,14 +1677,12 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: auto alloc_ptr = args.at(0).allocation.alloc().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 << ")"); LOG_ASSERT(alloc_ptr, "__rust_deallocate with no backing allocation attached to pointer"); LOG_ASSERT(alloc_ptr.is_alloc(), "__rust_deallocate with no backing allocation attached to pointer"); auto& alloc = alloc_ptr.alloc(); - // TODO: Figure out how to prevent this ever being written again. - //alloc.mark_as_freed(); - for(auto& v : alloc.mask) - v = 0; + alloc.mark_as_freed(); // Just let it drop. return Value(); } @@ -1693,6 +1707,10 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: { LOG_TODO("__rust_start_panic"); } + else if( link_name == "rust_begin_unwind" ) + { + LOG_TODO("rust_begin_unwind"); + } #ifdef _WIN32 // WinAPI functions used by libstd else if( link_name == "AddVectoredExceptionHandler" ) @@ -1758,6 +1776,18 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: } #else // POSIX + else if( link_name == "write" ) + { + auto fd = args.at(0).read_i32(0); + auto count = args.at(2).read_isize(0); + const auto* buf = args.at(1).read_pointer_const(0, count); + + ssize_t val = write(fd, buf, count); + + auto rv = Value(::HIR::TypeRef(RawType::ISize)); + rv.write_isize(0, val); + return rv; + } else if( link_name == "sysconf" ) { auto name = args.at(0).read_i32(0); @@ -1767,7 +1797,7 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: rv.write_usize(0, val); return rv; } - else if( link_name == "pthread_mutex_init" || link_name == "pthread_mutex_lock" || link_name == "pthread_mutex_unlock" ) + else if( link_name == "pthread_mutex_init" || link_name == "pthread_mutex_lock" || link_name == "pthread_mutex_unlock" || link_name == "pthread_mutex_destroy" ) { auto rv = Value(::HIR::TypeRef(RawType::I32)); rv.write_i32(0, 0); @@ -1902,7 +1932,11 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st TRACE_FUNCTION_R(name, rv); for(const auto& a : args) LOG_DEBUG("#" << (&a - args.data()) << ": " << a); - if( name == "atomic_store" ) + if( name == "atomic_fence" || name == "atomic_fence_acq" ) + { + return Value(); + } + else if( name == "atomic_store" ) { auto& ptr_val = args.at(0); auto& data_val = args.at(1); @@ -1956,6 +1990,27 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st val_l.get().write_to_value( ptr_alloc.alloc(), ptr_ofs ); } + else if( name == "atomic_xsub" || name == "atomic_xsub_relaxed" || name == "atomic_xsub_rel" ) + { + 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 v = args.at(1).read_value(0, ty_T.get_size()); + + // TODO: Atomic lock the allocation. + if( !ptr_alloc || !ptr_alloc.is_alloc() ) { + LOG_ERROR("atomic pointer has no allocation"); + } + + // - Result is the original value + rv = ptr_alloc.alloc().read_value(ptr_ofs, ty_T.get_size()); + + auto val_l = PrimitiveValueVirt::from_value(ty_T, rv); + const auto val_r = PrimitiveValueVirt::from_value(ty_T, v); + val_l.get().subtract( val_r.get() ); + + val_l.get().write_to_value( ptr_alloc.alloc(), ptr_ofs ); + } else if( name == "atomic_cxchg" ) { const auto& ty_T = ty_params.tys.at(0); @@ -2086,13 +2141,14 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st case TypeWrapper::Ty::Pointer: break; case TypeWrapper::Ty::Borrow: + // TODO: Only &move has a destructor break; } LOG_ASSERT(ty.wrappers[0].type == TypeWrapper::Ty::Slice, "drop_in_place should only exist for slices - " << ty); const auto& ity = ty.get_inner(); size_t item_size = ity.get_size(); - auto ptr = val.read_value(0, POINTER_SIZE);; + auto ptr = val.read_value(0, POINTER_SIZE); for(size_t i = 0; i < item_count; i ++) { drop_value(modtree, thread, ptr, ity); @@ -2101,7 +2157,7 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st } else { - LOG_TODO("drop_in_place - " << ty); + drop_value(modtree, thread, val, ty); } } // ---------------------------------------------------------------- diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index c70f17dd..88d8ff88 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -675,7 +675,7 @@ bool Parser::parse_one() case '<': if( t.strval[1] == '<' ) op = ::MIR::eBinOp::BIT_SHL; - else if( lex.consume_if('=') ) + else if( t.strval[1] == '=' ) op = ::MIR::eBinOp::LE; else op = ::MIR::eBinOp::LT; diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index db352019..cdace6e2 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -232,6 +232,8 @@ ValueRef ValueCommon::read_pointer_valref_mut(size_t rd_ofs, size_t size) void Allocation::resize(size_t new_size) { + if( this->is_freed ) + LOG_ERROR("Use of freed memory " << this); //size_t old_size = this->size(); //size_t extra_bytes = (new_size > old_size ? new_size - old_size : 0); @@ -246,9 +248,9 @@ void Allocation::check_bytes_valid(size_t ofs, size_t size) const } for(size_t i = ofs; i < ofs + size; i++) { - if( !(this->mask[i/8] & (1 << i%8)) ) + if( !(this->mask[i/8] & (1 << (i%8))) ) { - LOG_ERROR("Invalid bytes in value"); + LOG_ERROR("Invalid bytes in value - " << ofs << "+" << size << " - " << *this); throw "ERROR"; } } @@ -258,14 +260,18 @@ void Allocation::mark_bytes_valid(size_t ofs, size_t size) assert( ofs+size <= this->mask.size() * 8 ); for(size_t i = ofs; i < ofs + size; i++) { - this->mask[i/8] |= (1 << i%8); + this->mask[i/8] |= (1 << (i%8)); } } Value Allocation::read_value(size_t ofs, size_t size) const { Value rv; + TRACE_FUNCTION_R("Allocation::read_value " << this << " " << ofs << "+" << size, *this << " | " << rv); + if( this->is_freed ) + LOG_ERROR("Use of freed memory " << this); + LOG_DEBUG(*this); - // TODO: Determine if this can become an inline allocation. + // Determine if this can become an inline allocation. bool has_reloc = false; for(const auto& r : this->relocations) { @@ -292,14 +298,12 @@ Value Allocation::read_value(size_t ofs, size_t size) const for(size_t i = 0; i < size; i ++) { size_t j = ofs + i; - bool v = (this->mask[j/8] & (1 << j%8)) != 0; + const uint8_t test_mask = (1 << (j%8)); + const uint8_t set_mask = (1 << (i%8)); + bool v = (this->mask[j/8] & test_mask) != 0; if( v ) { - rv.allocation.alloc().mask[i/8] |= (1 << i%8); - } - else - { - rv.allocation.alloc().mask[i/8] &= ~(1 << i%8); + rv.allocation.alloc().mask[i/8] |= set_mask; } } } @@ -315,21 +319,23 @@ Value Allocation::read_value(size_t ofs, size_t size) const for(size_t i = 0; i < size; i ++) { size_t j = ofs + i; - bool v = (this->mask[j/8] & (1 << j%8)) != 0; + const uint8_t tst_mask = 1 << (j%8); + const uint8_t set_mask = 1 << (i%8); + bool v = (this->mask[j/8] & tst_mask) != 0; if( v ) { - rv.direct_data.mask[i/8] |= (1 << i%8); + rv.direct_data.mask[i/8] |= set_mask; } - //else - //{ - // rv.direct_data.mask[i/8] &= ~(1 << i%8); - //} } } return rv; } void Allocation::read_bytes(size_t ofs, void* dst, size_t count) const { + if( this->is_freed ) + LOG_ERROR("Use of freed memory " << this); + + LOG_DEBUG("Allocation::read_bytes " << this << " " << ofs << "+" << count); if(count == 0) return ; @@ -352,6 +358,11 @@ void Allocation::read_bytes(size_t ofs, void* dst, size_t count) const } void Allocation::write_value(size_t ofs, Value v) { + TRACE_FUNCTION_R("Allocation::write_value " << this << " " << ofs << "+" << v.size() << " " << v, *this); + if( this->is_freed ) + LOG_ERROR("Use of freed memory " << this); + //if( this->is_read_only ) + // LOG_ERROR("Writing to read-only allocation " << this); if( v.allocation ) { size_t v_size = v.allocation.alloc().size(); @@ -416,8 +427,15 @@ void Allocation::write_value(size_t ofs, Value v) } void Allocation::write_bytes(size_t ofs, const void* src, size_t count) { + //LOG_DEBUG("Allocation::write_bytes " << this << " " << ofs << "+" << count); + if( this->is_freed ) + LOG_ERROR("Use of freed memory " << this); + //if( this->is_read_only ) + // LOG_ERROR("Writing to read-only allocation " << this); + if(count == 0) return ; + TRACE_FUNCTION_R("Allocation::write_bytes " << this << " " << ofs << "+" << count, *this); if(ofs >= this->size() ) { LOG_ERROR("Out of bounds write, " << ofs << "+" << count << " > " << this->size()); throw "ERROR"; @@ -459,7 +477,7 @@ void Allocation::write_bytes(size_t ofs, const void* src, size_t count) if( i != 0 ) os << " "; - if( x.mask[i/8] & (1 << i%8) ) + if( x.mask[i/8] & (1 << (i%8)) ) { os << ::std::setw(2) << ::std::setfill('0') << (int)x.data_ptr()[i]; } diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index 2b3bd4e6..aa41b838 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -171,6 +171,7 @@ class Allocation: friend class AllocationPtr; size_t refcount; // TODO: Read-only flag? + bool is_freed = false; public: static AllocationPtr new_alloc(size_t size); @@ -189,10 +190,12 @@ public: } return AllocationPtr(); } - //void mark_as_freed() { - // for(auto& v : mask) - // v = 0; - //} + void mark_as_freed() { + is_freed = true; + relocations.clear(); + for(auto& v : mask) + v = 0; + } void resize(size_t new_size); -- cgit v1.2.3 From 872827f5d8db975f41eabe1ec1048e50b3bc166f Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 13 May 2018 17:00:44 +0800 Subject: Standalone MIRI - Working hello.rs --- tools/standalone_miri/main.cpp | 35 ++++++++++++++++++++++++++++++++--- tools/standalone_miri/module_tree.cpp | 4 ++++ 2 files changed, 36 insertions(+), 3 deletions(-) (limited to 'tools/standalone_miri/module_tree.cpp') diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index 97ca8e6f..bd86967c 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -1803,6 +1803,12 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: rv.write_i32(0, 0); return rv; } + else if( link_name == "pthread_rwlock_rdlock" ) + { + auto rv = Value(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, 0); + return rv; + } else if( link_name == "pthread_mutexattr_init" || link_name == "pthread_mutexattr_settype" || link_name == "pthread_mutexattr_destroy" ) { auto rv = Value(::HIR::TypeRef(RawType::I32)); @@ -1932,7 +1938,20 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st TRACE_FUNCTION_R(name, rv); for(const auto& a : args) LOG_DEBUG("#" << (&a - args.data()) << ": " << a); - if( name == "atomic_fence" || name == "atomic_fence_acq" ) + if( name == "type_id" ) + { + const auto& ty_T = ty_params.tys.at(0); + static ::std::vector type_ids; + auto it = ::std::find(type_ids.begin(), type_ids.end(), ty_T); + if( it == type_ids.end() ) + { + it = type_ids.insert(it, ty_T); + } + + rv = Value::with_size(POINTER_SIZE, false); + rv.write_usize(0, it - type_ids.begin()); + } + else if( name == "atomic_fence" || name == "atomic_fence_acq" ) { return Value(); } @@ -2011,16 +2030,26 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st val_l.get().write_to_value( ptr_alloc.alloc(), ptr_ofs ); } + else if( name == "atomic_xchg" ) + { + const auto& ty_T = ty_params.tys.at(0); + auto data_ref = args.at(0).read_pointer_valref_mut(0, ty_T.get_size()); + const auto& new_v = args.at(1); + + rv = data_ref.read_value(0, new_v.size()); + data_ref.m_alloc.alloc().write_value( data_ref.m_offset, new_v ); + } else if( name == "atomic_cxchg" ) { const auto& ty_T = ty_params.tys.at(0); // TODO: Get a ValueRef to the target location auto data_ref = args.at(0).read_pointer_valref_mut(0, ty_T.get_size()); const auto& old_v = args.at(1); - const auto& new_v = args.at(1); + const auto& new_v = args.at(2); rv = Value::with_size( ty_T.get_size() + 1, false ); rv.write_value(0, data_ref.read_value(0, old_v.size())); - if( data_ref.compare(old_v.data_ptr(), old_v.size()) == 0 ) { + LOG_DEBUG("> *ptr = " << data_ref); + if( data_ref.compare(old_v.data_ptr(), old_v.size()) == true ) { data_ref.m_alloc.alloc().write_value( data_ref.m_offset, new_v ); rv.write_u8( old_v.size(), 1 ); } diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index 88d8ff88..ad41b33a 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -102,6 +102,7 @@ bool Parser::parse_one() auto abi = ::std::move(lex.check_consume(TokenClass::String).strval); lex.check_consume(';'); + LOG_DEBUG("fn " << p); auto p2 = p; tree.functions.insert( ::std::make_pair(::std::move(p), Function { ::std::move(p2), ::std::move(arg_tys), rv_ty, {link_name, abi}, {} }) ); } @@ -109,6 +110,7 @@ bool Parser::parse_one() { auto body = parse_body(); + LOG_DEBUG("fn " << p); auto p2 = p; tree.functions.insert( ::std::make_pair(::std::move(p), Function { ::std::move(p2), ::std::move(arg_tys), rv_ty, {}, ::std::move(body) }) ); } @@ -170,6 +172,7 @@ bool Parser::parse_one() } lex.check_consume(';'); + LOG_DEBUG("static " << p); tree.statics.insert(::std::make_pair( ::std::move(p), ::std::move(s) )); } else if( lex.consume_if("type") ) @@ -290,6 +293,7 @@ bool Parser::parse_one() throw "ERROR"; } + LOG_DEBUG("type " << p); auto it = this->tree.data_types.find(p); if( it != this->tree.data_types.end() ) { -- cgit v1.2.3 From 55ea64451a81be2f797094c9a4140a7a98ba6b5d Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 15 May 2018 21:25:47 +0800 Subject: Standalone MIRI - Split AllocationPtr into AllocationHandle and RelocationPtr --- tools/standalone_miri/main.cpp | 94 +++++++-------- tools/standalone_miri/module_tree.cpp | 6 +- tools/standalone_miri/value.cpp | 208 +++++++++++++++++++++------------- tools/standalone_miri/value.hpp | 190 +++++++++++++++++-------------- 4 files changed, 280 insertions(+), 218 deletions(-) (limited to 'tools/standalone_miri/module_tree.cpp') 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 const T& check(const char* opname) const @@ -212,14 +212,14 @@ struct PrimitiveUInt: struct PrimitiveU64: public PrimitiveUInt { 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 { 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 { 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 { 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 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(ret) - static_cast(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(ret) - static_cast(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 #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( reinterpret_cast(ptr) + static_cast(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( reinterpret_cast(ptr) + static_cast(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( reinterpret_cast(ptr) + static_cast(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( reinterpret_cast(ptr) + static_cast(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(x.get_ptr()) ); + *this = RelocationPtr::new_alloc(tmp); + tmp.m_ptr = nullptr; + } break; case Ty::Function: { auto ptr_i = reinterpret_cast(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(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( static_cast(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( reinterpret_cast(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( reinterpret_cast(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(v)); } - void write_i16(size_t ofs, int16_t v) { write_u16(ofs, static_cast(v)); } - void write_i32(size_t ofs, int32_t v) { write_u32(ofs, static_cast(v)); } - void write_i64(size_t ofs, int64_t v) { write_u64(ofs, static_cast(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(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(v)); } + void write_i16(size_t ofs, int16_t v) { write_u16(ofs, static_cast(v)); } + void write_i32(size_t ofs, int32_t v) { write_u32(ofs, static_cast(v)); } + void write_i64(size_t ofs, int64_t v) { write_u64(ofs, static_cast(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(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(this->data.data()); } uint8_t* data_ptr() { return reinterpret_cast< uint8_t*>(this->data.data()); } @@ -183,12 +216,12 @@ public: ::std::vector mask; ::std::vector 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 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(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(read_u8(ofs)); } - int16_t read_i16(size_t ofs) const { return static_cast(read_u16(ofs)); } - int32_t read_i32(size_t ofs) const { return static_cast(read_u32(ofs)); } - int64_t read_i64(size_t ofs) const { return static_cast(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(read_usize(ofs)); } }; extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v); -- cgit v1.2.3 From ae177706bf0b4b2ff05e9102d1403c73799756b0 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 19 May 2018 10:15:20 +0800 Subject: Standalone MIRI - Better logging (can redirect to a file, leaving stdout for the program) --- test_smiri.sh | 2 +- tools/standalone_miri/debug.cpp | 34 +++++++++---- tools/standalone_miri/debug.hpp | 14 +++-- tools/standalone_miri/main.cpp | 61 +++++++++++++++++----- tools/standalone_miri/miri.cpp | 10 ++-- tools/standalone_miri/module_tree.cpp | 96 ++++++++++++++--------------------- tools/standalone_miri/value.cpp | 10 ++-- tools/standalone_miri/value.hpp | 15 ++++-- 8 files changed, 148 insertions(+), 94 deletions(-) (limited to 'tools/standalone_miri/module_tree.cpp') diff --git a/test_smiri.sh b/test_smiri.sh index 63c94fa2..5a7de4e4 100755 --- a/test_smiri.sh +++ b/test_smiri.sh @@ -3,4 +3,4 @@ set -e cd $(dirname $0) make -f minicargo.mk MMIR=1 LIBS ./bin/mrustc rustc-1.19.0-src/src/test/run-pass/hello.rs -O -C codegen-type=monomir -o output-mmir/hello -L output-mmir/ > output-mmir/hello_dbg.txt -./tools/bin/standalone_miri output-mmir/hello.mir +./tools/bin/standalone_miri output-mmir/hello.mir --logfile smiri_hello.log diff --git a/tools/standalone_miri/debug.cpp b/tools/standalone_miri/debug.cpp index 415bc5d5..f0476df7 100644 --- a/tools/standalone_miri/debug.cpp +++ b/tools/standalone_miri/debug.cpp @@ -1,6 +1,15 @@ +/* + * mrustc Standalone MIRI + * - by John Hodge (Mutabah) + * + * debug.cpp + * - Interpreter debug logging + */ #include "debug.hpp" +#include unsigned DebugSink::s_indent = 0; +::std::unique_ptr DebugSink::s_out_file; DebugSink::DebugSink(::std::ostream& inner): m_inner(inner) @@ -10,39 +19,44 @@ DebugSink::~DebugSink() { m_inner << "\n"; } +bool DebugSink::set_output_file(const ::std::string& s) +{ + s_out_file.reset(new ::std::ofstream(s)); +} bool DebugSink::enabled(const char* fcn_name) { return true; } DebugSink DebugSink::get(const char* fcn_name, const char* file, unsigned line, DebugLevel lvl) { + auto& sink = s_out_file ? *s_out_file : ::std::cout; for(size_t i = s_indent; i--;) - ::std::cout << " "; + sink << " "; switch(lvl) { case DebugLevel::Trace: - ::std::cout << "Trace: " << file << ":" << line << ": "; + sink << "Trace: " << file << ":" << line << ": "; break; case DebugLevel::Debug: - ::std::cout << "DEBUG: " << fcn_name << ": "; + sink << "DEBUG: " << fcn_name << ": "; break; case DebugLevel::Notice: - ::std::cout << "NOTE: "; + sink << "NOTE: "; break; case DebugLevel::Warn: - ::std::cout << "WARN: "; + sink << "WARN: "; break; case DebugLevel::Error: - ::std::cout << "ERROR: "; + sink << "ERROR: "; break; case DebugLevel::Fatal: - ::std::cout << "FATAL: "; + sink << "FATAL: "; break; case DebugLevel::Bug: - ::std::cout << "BUG: " << file << ":" << line << ": "; + sink << "BUG: " << file << ":" << line << ": "; break; } - return DebugSink(::std::cout); + return DebugSink(sink); } void DebugSink::inc_indent() { @@ -51,4 +65,4 @@ void DebugSink::inc_indent() void DebugSink::dec_indent() { s_indent --; -} \ No newline at end of file +} diff --git a/tools/standalone_miri/debug.hpp b/tools/standalone_miri/debug.hpp index f7d32fe5..6b136ccb 100644 --- a/tools/standalone_miri/debug.hpp +++ b/tools/standalone_miri/debug.hpp @@ -1,10 +1,15 @@ -// -// -// +/* + * mrustc Standalone MIRI + * - by John Hodge (Mutabah) + * + * debug.hpp + * - Interpreter debug logging + */ #pragma once #include #include +#include enum class DebugLevel { Trace, @@ -19,6 +24,7 @@ enum class DebugLevel { class DebugSink { static unsigned s_indent; + static ::std::unique_ptr s_out_file; ::std::ostream& m_inner; DebugSink(::std::ostream& inner); public: @@ -27,6 +33,7 @@ public: template ::std::ostream& operator<<(const T& v) { return m_inner << v; } + static bool set_output_file(const ::std::string& s); static bool enabled(const char* fcn_name); static DebugSink get(const char* fcn_name, const char* file, unsigned line, DebugLevel lvl); // TODO: Add a way to insert an annotation before/after an abort/warning/... that indicates what input location caused it. @@ -90,6 +97,7 @@ struct DebugExceptionError: #define TRACE_FUNCTION_R(entry, exit) auto ftg##__LINE__ = FunctionTrace_d(__FUNCTION__,__FILE__,__LINE__,[&](DebugSink& FunctionTrace_ss){FunctionTrace_ss << entry;}, [&](DebugSink& FunctionTrace_ss) {FunctionTrace_ss << exit;} ) #define LOG_TRACE(strm) do { if(DebugSink::enabled(__FUNCTION__)) DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Trace) << strm; } while(0) #define LOG_DEBUG(strm) do { if(DebugSink::enabled(__FUNCTION__)) DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Debug) << strm; } while(0) +#define LOG_NOTICE(strm) do { DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Notice) << strm; } while(0) #define LOG_ERROR(strm) do { DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Error) << strm; throw DebugExceptionError{}; } while(0) #define LOG_FATAL(strm) do { DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Fatal) << strm; exit(1); } while(0) #define LOG_TODO(strm) do { DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Bug) << "TODO: " << strm; throw DebugExceptionTodo{}; } while(0) diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index 1755a9d7..c214676a 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -1,6 +1,10 @@ -// -// -// +/* + * mrustc Standalone MIRI + * - by John Hodge (Mutabah) + * + * main.cpp + * - Program entrypoint + */ #include #include "module_tree.hpp" #include "value.hpp" @@ -17,8 +21,10 @@ struct ProgramOptions //::std::string archname; //TODO: Loadable FFI descriptions //::std::vector ffi_api_files; - //TODO: Logfile - //::std::string logfile; + + // Output logfile + ::std::string logfile; + // Arguments for the program ::std::vector args; int parse(int argc, const char* argv[]); @@ -34,10 +40,17 @@ int main(int argc, const char* argv[]) return 1; } - auto tree = ModuleTree {}; + // Configure logging + if( opts.logfile != "" ) + { + DebugSink::set_output_file(opts.logfile); + } + // Load HIR tree + auto tree = ModuleTree {}; tree.load_file(opts.infile); + // Construct argc/argv values auto val_argc = Value( ::HIR::TypeRef{RawType::ISize} ); ::HIR::TypeRef argv_ty { RawType::I8 }; argv_ty.wrappers.push_back(TypeWrapper { TypeWrapper::Ty::Pointer, 0 }); @@ -54,9 +67,11 @@ int main(int argc, const char* argv[]) argv_alloc->write_usize((1 + i) * POINTER_SIZE, 0); argv_alloc->relocations.push_back({ (1 + i) * POINTER_SIZE, RelocationPtr::new_ffi({ "", (void*)(opts.args[0]), ::std::strlen(opts.args[0]) + 1 }) }); } + //val_argv.write_ptr(0, 0, RelocationPtr::new_alloc(argv_alloc)); val_argv.write_usize(0, 0); val_argv.allocation->relocations.push_back({ 0 * POINTER_SIZE, RelocationPtr::new_alloc(argv_alloc) }); + // Catch various exceptions from the interpreter try { InterpreterThread root_thread(tree); @@ -70,16 +85,24 @@ int main(int argc, const char* argv[]) { } - ::std::cout << rv << ::std::endl; + LOG_NOTICE("Return code: " << rv); } catch(const DebugExceptionTodo& /*e*/) { ::std::cerr << "TODO Hit" << ::std::endl; + if(opts.logfile != "") + { + ::std::cerr << "- See '" << opts.logfile << "' for details" << ::std::endl; + } return 1; } catch(const DebugExceptionError& /*e*/) { ::std::cerr << "Error encountered" << ::std::endl; + if(opts.logfile != "") + { + ::std::cerr << "- See '" << opts.logfile << "' for details" << ::std::endl; + } return 1; } @@ -89,26 +112,31 @@ int main(int argc, const char* argv[]) int ProgramOptions::parse(int argc, const char* argv[]) { bool all_free = false; + // TODO: use getopt? POSIX only for(int argidx = 1; argidx < argc; argidx ++) { const char* arg = argv[argidx]; if( arg[0] != '-' || all_free ) { - // Free + // Free arguments + // - First is the input file if( this->infile == "" ) { this->infile = arg; } else { + // Any subsequent arguments are passed to the taget this->args.push_back(arg); } } else if( arg[1] != '-' ) { - // Short + // Short arguments if( arg[2] != '\0' ) { // Error? + ::std::cerr << "Unexpected option " << arg << ::std::endl; + return 1; } switch(arg[1]) { @@ -116,8 +144,8 @@ int ProgramOptions::parse(int argc, const char* argv[]) this->show_help(argv[0]); exit(0); default: - // TODO: Error - break; + ::std::cerr << "Unexpected option -" << arg[1] << ::std::endl; + return 1; } } else if( arg[2] != '\0' ) @@ -127,10 +155,19 @@ int ProgramOptions::parse(int argc, const char* argv[]) this->show_help(argv[0]); exit(0); } + else if( ::std::strcmp(arg, "--logfile") == 0 ) { + if( argidx + 1 == argc ) { + ::std::cerr << "Option " << arg << " requires an argument" << ::std::endl; + return 1; + } + const char* opt = argv[++argidx]; + this->logfile = opt; + } //else if( ::std::strcmp(arg, "--api") == 0 ) { //} else { - // TODO: Error + ::std::cerr << "Unexpected option " << arg << ::std::endl; + return 1; } } else diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index eccc54c9..733aa8a3 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -1,6 +1,10 @@ -// -// -// +/* + * mrustc Standalone MIRI + * - by John Hodge (Mutabah) + * + * miri.cpp + * - Interpreter core + */ #include #include "module_tree.hpp" #include "value.hpp" diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index 6a7a0b5f..cb6f943d 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -40,12 +40,11 @@ void ModuleTree::load_file(const ::std::string& path) { if( !loaded_files.insert(path).second ) { - ::std::cout << "DEBUG: load_file(" << path << ") - Already loaded" << ::std::endl; + LOG_DEBUG("load_file(" << path << ") - Already loaded"); return ; } - ::std::cout << "DEBUG: load_file(" << path << ")" << ::std::endl; - //TRACE_FUNCTION_F(path); + TRACE_FUNCTION_R(path, ""); auto parse = Parser { *this, path }; while(parse.parse_one()) @@ -56,7 +55,7 @@ void ModuleTree::load_file(const ::std::string& path) // Parse a single item from a .mir file bool Parser::parse_one() { - //::std::cout << "DEBUG: parse_one" << ::std::endl; + //TRACE_FUNCTION_F(""); if( lex.next() == "" ) // EOF? { return false; @@ -68,7 +67,7 @@ bool Parser::parse_one() lex.check(TokenClass::String); auto path = ::std::move(lex.next().strval); lex.consume(); - //::std::cout << "DEBUG: parse_one - crate '" << path << "'" << ::std::endl; + //LOG_TRACE(lex << "crate '" << path << "'"); lex.check_consume(';'); @@ -78,7 +77,7 @@ bool Parser::parse_one() else if( lex.consume_if("fn") ) { auto p = parse_path(); - //::std::cout << "DEBUG: parse_one - fn " << p << ::std::endl; + //LOG_TRACE(lex << "fn " << p); lex.check_consume('('); ::std::vector<::HIR::TypeRef> arg_tys; @@ -94,7 +93,7 @@ bool Parser::parse_one() { rv_ty = parse_type(); } - + if( lex.consume_if('=') ) { auto link_name = ::std::move(lex.check_consume(TokenClass::String).strval); @@ -102,7 +101,7 @@ bool Parser::parse_one() auto abi = ::std::move(lex.check_consume(TokenClass::String).strval); lex.check_consume(';'); - LOG_DEBUG("fn " << p); + LOG_DEBUG(lex << "extern fn " << p); auto p2 = p; tree.functions.insert( ::std::make_pair(::std::move(p), Function { ::std::move(p2), ::std::move(arg_tys), rv_ty, {link_name, abi}, {} }) ); } @@ -110,7 +109,7 @@ bool Parser::parse_one() { auto body = parse_body(); - LOG_DEBUG("fn " << p); + LOG_DEBUG(lex << "fn " << p); auto p2 = p; tree.functions.insert( ::std::make_pair(::std::move(p), Function { ::std::move(p2), ::std::move(arg_tys), rv_ty, {}, ::std::move(body) }) ); } @@ -118,7 +117,7 @@ bool Parser::parse_one() else if( lex.consume_if("static") ) { auto p = parse_path(); - //::std::cout << "DEBUG: parse_one - static " << p << ::std::endl; + //LOG_TRACE(lex << "static " << p); lex.check_consume(':'); auto ty = parse_type(); // TODO: externs? @@ -152,12 +151,12 @@ bool Parser::parse_one() auto a = Allocation::new_alloc( reloc_str.size() ); //a.alloc().set_tag(); a->write_bytes(0, reloc_str.data(), reloc_str.size()); - s.val.allocation->relocations.push_back({ ofs, RelocationPtr::new_alloc(::std::move(a)) }); + s.val.allocation->relocations.push_back({ ofs, /*size,*/ RelocationPtr::new_alloc(::std::move(a)) }); } else if( lex.next() == "::" || lex.next() == "<" ) { auto reloc_path = parse_path(); - s.val.allocation->relocations.push_back({ ofs, RelocationPtr::new_fcn(reloc_path) }); + s.val.allocation->relocations.push_back({ ofs, /*size,*/ RelocationPtr::new_fcn(reloc_path) }); } else { @@ -172,13 +171,13 @@ bool Parser::parse_one() } lex.check_consume(';'); - LOG_DEBUG("static " << p); + LOG_DEBUG(lex << "static " << p); tree.statics.insert(::std::make_pair( ::std::move(p), ::std::move(s) )); } else if( lex.consume_if("type") ) { auto p = (lex.consume_if('(')) ? parse_tuple() : parse_genericpath(); - //::std::cout << "DEBUG: parse_one - type " << p << ::std::endl; + //LOG_TRACE("type " << p); auto rv = DataType {}; rv.my_path = p; @@ -223,7 +222,7 @@ bool Parser::parse_one() lex.check_consume('='); auto ty = parse_type(); lex.check_consume(';'); - //::std::cout << ofs << " " << ty << ::std::endl; + //LOG_DEBUG(ofs << " " << ty); rv.fields.push_back(::std::make_pair(ofs, ::std::move(ty))); } @@ -289,11 +288,10 @@ bool Parser::parse_one() if( rv.alignment == 0 && rv.fields.size() != 0 ) { - ::std::cerr << lex << "Alignment of zero with fields is invalid, " << p << ::std::endl; - throw "ERROR"; + LOG_ERROR(lex << "Alignment of zero with fields is invalid, " << p); } - LOG_DEBUG("type " << p); + LOG_DEBUG(lex << "type " << p); auto it = this->tree.data_types.find(p); if( it != this->tree.data_types.end() ) { @@ -303,10 +301,7 @@ bool Parser::parse_one() } else { - //::std::cerr << lex << "Duplicate definition of " << p << ::std::endl; - - // Not really an error, can happen when loading crates - //throw "ERROR"; + //LOG_ERROR(lex << "Duplicate definition of " << p); } } else @@ -316,7 +311,7 @@ bool Parser::parse_one() } else { - ::std::cerr << lex << "Unexpected token at root - " << lex.next() << ::std::endl; + LOG_ERROR(lex << "Unexpected token at root - " << lex.next()); // Unknown item type throw "ERROR"; @@ -360,8 +355,7 @@ bool Parser::parse_one() lv = ::MIR::LValue::make_Argument({ idx }); } catch(const ::std::exception& e) { - ::std::cerr << lex << "Invalid argument name - " << name << " - " << e.what() << ::std::endl; - throw "ERROR"; + LOG_ERROR(lex << "Invalid argument name - " << name << " - " << e.what()); } } // Hard-coded "RETURN" lvalue @@ -372,8 +366,7 @@ bool Parser::parse_one() else { auto it = ::std::find(var_names.begin(), var_names.end(), name); if( it == var_names.end() ) { - ::std::cerr << lex << "Cannot find variable named '" << name << "'" << ::std::endl; - throw "ERROR"; + LOG_ERROR(lex << "Cannot find variable named '" << name << "'"); } lv = ::MIR::LValue::make_Local(static_cast(it - var_names.begin())); } @@ -384,8 +377,7 @@ bool Parser::parse_one() lv = ::MIR::LValue( ::std::move(path) ); } else { - ::std::cerr << lex << "Unexpected token in LValue - " << lex.next() << ::std::endl; - throw "ERROR"; + LOG_ERROR(lex << "Unexpected token in LValue - " << lex.next()); } for(;;) { @@ -455,8 +447,7 @@ bool Parser::parse_one() } else { - ::std::cerr << p.lex << "Expected an integer or float, got " << p.lex.next() << ::std::endl; - throw "ERROR"; + LOG_ERROR(p.lex << "Expected an integer or float, got " << p.lex.next()); } } else if( p.lex.consume_if("true") ) { @@ -471,8 +462,7 @@ bool Parser::parse_one() return ::MIR::Constant::make_ItemAddr({ ::std::move(path) }); } else { - ::std::cerr << p.lex << "BUG? " << p.lex.next() << ::std::endl; - throw "ERROR"; + LOG_BUG(p.lex << "BUG? " << p.lex.next()); } } @@ -653,8 +643,7 @@ bool Parser::parse_one() op = ::MIR::eUniOp::NEG; } else { - ::std::cerr << lex << "Unexpected token in uniop - " << lex.next() << ::std::endl; - throw "ERROR"; + LOG_ERROR(lex << "Unexpected token in uniop - " << lex.next()); } auto lv = H::parse_lvalue(*this, var_names); @@ -701,8 +690,7 @@ bool Parser::parse_one() lex.check_consume('='); break; default: - ::std::cerr << lex << "Unexpected token " << t << " in BINOP" << ::std::endl; - throw "ERROR"; + LOG_ERROR(lex << "Unexpected token " << t << " in BINOP"); } auto lv2 = H::parse_param(*this, var_names); @@ -723,8 +711,7 @@ bool Parser::parse_one() src_rval = ::MIR::RValue::make_DstMeta({ ::std::move(lv) }); } else { - ::std::cerr << lex << "Unexpected token in RValue - " << lex.next() << ::std::endl; - throw "ERROR"; + LOG_ERROR(lex << "Unexpected token in RValue - " << lex.next()); } stmts.push_back(::MIR::Statement::make_Assign({ ::std::move(dst_val), ::std::move(src_rval) })); @@ -735,8 +722,7 @@ bool Parser::parse_one() auto name = ::std::move(lex.consume().strval); auto df_it = ::std::find(drop_flag_names.begin(), drop_flag_names.end(), name); if( df_it == drop_flag_names.end() ) { - ::std::cerr << lex << "Unable to find drop flag '" << name << "'" << ::std::endl; - throw "ERROR"; + LOG_ERROR(lex << "Unable to find drop flag '" << name << "'"); } auto df_idx = static_cast( df_it - drop_flag_names.begin() ); lex.check_consume('='); @@ -754,8 +740,7 @@ bool Parser::parse_one() auto name = ::std::move(lex.consume().strval); df_it = ::std::find(drop_flag_names.begin(), drop_flag_names.end(), name); if( df_it == drop_flag_names.end() ) { - ::std::cerr << lex << "Unable to find drop flag '" << name << "'" << ::std::endl; - throw "ERROR"; + LOG_ERROR(lex << "Unable to find drop flag '" << name << "'"); } auto other_idx = static_cast( df_it - drop_flag_names.begin() ); @@ -777,8 +762,7 @@ bool Parser::parse_one() auto name = ::std::move(lex.consume().strval); auto df_it = ::std::find(drop_flag_names.begin(), drop_flag_names.end(), name); if( df_it == drop_flag_names.end() ) { - ::std::cerr << lex << "Unable to find drop flag '" << name << "'" << ::std::endl; - throw "ERROR"; + LOG_ERROR(lex << "Unable to find drop flag '" << name << "'"); } flag_idx = static_cast( df_it - drop_flag_names.begin() ); } @@ -842,7 +826,7 @@ bool Parser::parse_one() break; } lex.check_consume(';'); - //::std::cout << stmts.back() << ::std::endl; + //LOG_TRACE(stmts.back()); } lex.check(TokenClass::Ident); @@ -928,8 +912,7 @@ bool Parser::parse_one() vals = ::MIR::SwitchValues::make_String(::std::move(values)); } else { - ::std::cerr << lex << "Unexpected token for SWITCHVALUE value - " << lex.next() << ::std::endl; - throw "ERROR"; + LOG_ERROR(lex << "Unexpected token for SWITCHVALUE value - " << lex.next()); } lex.check_consume('_'); lex.check_consume('='); @@ -976,8 +959,7 @@ bool Parser::parse_one() } else { - ::std::cerr << lex << "Unexpected token at terminator - " << lex.next() << ::std::endl; - throw "ERROR"; + LOG_ERROR(lex << "Unexpected token at terminator - " << lex.next()); } lex.check_consume('}'); @@ -1068,7 +1050,7 @@ bool Parser::parse_one() } RawType Parser::parse_core_type() { - //::std::cout << lex.next() << ::std::endl; + //LOG_TRACE(lex.next()); lex.check(TokenClass::Ident); auto tok = lex.consume(); // Primitive type. @@ -1124,8 +1106,7 @@ RawType Parser::parse_core_type() return RawType::Str; } else { - ::std::cerr << lex << "Unknown core type " << tok << "'" << ::std::endl; - throw "ERROR"; + LOG_ERROR(lex << "Unknown core type " << tok << "'"); } } ::HIR::TypeRef Parser::parse_type() @@ -1285,8 +1266,7 @@ RawType Parser::parse_core_type() } else { - ::std::cerr << lex << "Unexpected token in type - " << lex.next() << ::std::endl; - throw "ERROR"; + LOG_ERROR(lex << "Unexpected token in type - " << lex.next()); } } const DataType* Parser::get_composite(::HIR::GenericPath gp) @@ -1312,8 +1292,7 @@ const Function& ModuleTree::get_function(const ::HIR::Path& p) const auto it = functions.find(p); if(it == functions.end()) { - ::std::cerr << "Unable to find function " << p << " for invoke" << ::std::endl; - throw ""; + LOG_ERROR("Unable to find function " << p << " for invoke"); } return it->second; } @@ -1331,8 +1310,7 @@ Static& ModuleTree::get_static(const ::HIR::Path& p) auto it = statics.find(p); if(it == statics.end()) { - ::std::cerr << "Unable to find static " << p << " for invoke" << ::std::endl; - throw ""; + LOG_ERROR("Unable to find static " << p << " for invoke"); } return it->second; } diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index e9376ce6..c3db284a 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -1,6 +1,10 @@ -// -// -// +/* + * mrustc Standalone MIRI + * - by John Hodge (Mutabah) + * + * value.cpp + * - Runtime values + */ #include "value.hpp" #include "hir_sim.hpp" #include "module_tree.hpp" diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index 4528b98f..81302e67 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -1,6 +1,10 @@ -// -// -// +/* + * mrustc Standalone MIRI + * - by John Hodge (Mutabah) + * + * value.hpp + * - Runtime values + */ #pragma once #include @@ -257,9 +261,12 @@ 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); + //static Value new_usize(uint64_t v); + //static Value new_isize(int64_t v); void create_allocation(); size_t size() const { return allocation ? allocation->size() : direct_data.size; } @@ -281,6 +288,8 @@ struct Value: void write_value(size_t ofs, Value v); void write_bytes(size_t ofs, const void* src, size_t count) override; + + //void write_ptr(size_t ofs, size_t ptr_ofs, RelocationPtr reloc); }; extern ::std::ostream& operator<<(::std::ostream& os, const Value& v); -- cgit v1.2.3 From d97d3a3e9fedb73c612fae542db28626a687ab22 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 19 May 2018 13:29:22 +0800 Subject: Standalone MIRI - Remove direct uses of TypeRef.wrappers --- tools/standalone_miri/hir_sim.cpp | 40 +++++- tools/standalone_miri/hir_sim.hpp | 30 ++++- tools/standalone_miri/main.cpp | 4 +- tools/standalone_miri/miri.cpp | 240 ++++++++++++++++------------------ tools/standalone_miri/module_tree.cpp | 18 +-- tools/standalone_miri/value.cpp | 37 +----- 6 files changed, 186 insertions(+), 183 deletions(-) (limited to 'tools/standalone_miri/module_tree.cpp') diff --git a/tools/standalone_miri/hir_sim.cpp b/tools/standalone_miri/hir_sim.cpp index 94f0d0e1..35f8f608 100644 --- a/tools/standalone_miri/hir_sim.cpp +++ b/tools/standalone_miri/hir_sim.cpp @@ -1,7 +1,12 @@ -// -// -// +/* + * mrustc Standalone MIRI + * - by John Hodge (Mutabah) + * + * value.cpp + * - Copy of the various HIR types from the compiler + */ #include +#include #include "hir_sim.hpp" #include "module_tree.hpp" @@ -140,7 +145,32 @@ HIR::TypeRef HIR::TypeRef::wrap(TypeWrapper::Ty ty, size_t size)&& rv.wrappers.insert(rv.wrappers.begin(), { ty, size }); return rv; } -const HIR::TypeRef* HIR::TypeRef::get_usized_type(size_t& running_inner_size) const +bool HIR::TypeRef::has_pointer() const +{ + // If ALL of the (potentially non) wrappers are Array, look deeper + // - Don't need to worry about unsized types here + if( ::std::all_of(this->wrappers.begin(), this->wrappers.end(), [](const auto& x){ return x.type == TypeWrapper::Ty::Array; }) ) + { + // TODO: Function pointers should be _pointers_ + if( this->inner_type == RawType::Function ) + { + return true; + } + // Check the inner type + if( this->inner_type == RawType::Composite ) + { + // Still not sure, check the inner for any pointers. + for(const auto& fld : this->composite_type->fields) + { + if( fld.second.has_pointer() ) + return true; + } + } + return false; + } + return true; +} +const HIR::TypeRef* HIR::TypeRef::get_unsized_type(size_t& running_inner_size) const { if( this->wrappers.empty() ) { @@ -153,7 +183,7 @@ const HIR::TypeRef* HIR::TypeRef::get_usized_type(size_t& running_inner_size) co return nullptr; running_inner_size = this->composite_type->fields.back().first; size_t tmp; - return this->composite_type->fields.back().second.get_usized_type(tmp); + return this->composite_type->fields.back().second.get_unsized_type(tmp); case RawType::TraitObject: case RawType::Str: return this; diff --git a/tools/standalone_miri/hir_sim.hpp b/tools/standalone_miri/hir_sim.hpp index 9f5ba59c..7730ac48 100644 --- a/tools/standalone_miri/hir_sim.hpp +++ b/tools/standalone_miri/hir_sim.hpp @@ -118,15 +118,41 @@ namespace HIR { } size_t get_size(size_t ofs=0) const; + + // Returns true if this (unsized) type is a wrapper around a slice + // - Fills `out_inner_size` with the size of the slice element bool has_slice_meta(size_t& out_inner_size) const; // The attached metadata is a count of elements - const TypeRef* get_usized_type(size_t& running_inner_size) const; + // Returns the base unsized type for this type (returning nullptr if there's no unsized field) + // - Fills `running_inner_size` with the offset to the unsized field + const TypeRef* get_unsized_type(size_t& running_inner_size) const; + // Returns the type of associated metadata for this (unsized) type (or `!` if not unsized) TypeRef get_meta_type() const; + // Get the inner type (one level of wrapping removed) TypeRef get_inner() const; + + // Add a wrapper over this type (moving) TypeRef wrap(TypeWrapper::Ty ty, size_t size)&&; + // Add a wrapper over this type (copying) TypeRef wrapped(TypeWrapper::Ty ty, size_t size) const { return TypeRef(*this).wrap(ty, size); } + // Get the wrapper at the provided offset (0 = outermost) + const TypeWrapper* get_wrapper(size_t ofs=0) const { + //assert(ofs <= this->wrappers.size()); + if( ofs < this->wrappers.size() ) { + return &this->wrappers[ofs]; + } + else { + return nullptr; + } + } + + // Returns true if the type contains any pointers + bool has_pointer() const; + // Get the type and offset of the specified field index TypeRef get_field(size_t idx, size_t& ofs) const; + // Get the offset and type of a field (recursing using `other_idx`) + size_t get_field_ofs(size_t idx, const ::std::vector& other_idx, TypeRef& ty) const; bool operator==(const RawType& x) const { if( this->wrappers.size() != 0 ) @@ -152,8 +178,6 @@ namespace HIR { return false; } - size_t get_field_ofs(size_t idx, const ::std::vector& other_idx, TypeRef& ty) const; - friend ::std::ostream& operator<<(::std::ostream& os, const TypeRef& x); }; diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index e3a8d22e..90b5eff3 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -62,9 +62,7 @@ int main(int argc, const char* argv[]) // Construct argc/argv values auto val_argc = Value::new_isize(1 + opts.args.size()); - ::HIR::TypeRef argv_ty { RawType::I8 }; - argv_ty.wrappers.push_back(TypeWrapper { TypeWrapper::Ty::Pointer, 0 }); - argv_ty.wrappers.push_back(TypeWrapper { TypeWrapper::Ty::Pointer, 0 }); + auto argv_ty = ::HIR::TypeRef(RawType::I8).wrap(TypeWrapper::Ty::Pointer, 0 ).wrap(TypeWrapper::Ty::Pointer, 0); auto val_argv = Value::new_pointer(argv_ty, 0, RelocationPtr::new_alloc(argv_alloc)); // Catch various exceptions from the interpreter diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index c0e7d15c..63be419c 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -175,7 +175,7 @@ public: static PrimitiveValueVirt from_value(const ::HIR::TypeRef& t, const ValueRef& v) { PrimitiveValueVirt rv; - LOG_ASSERT(t.wrappers.empty(), "PrimitiveValueVirt::from_value: " << t); + LOG_ASSERT(t.get_wrapper() == nullptr, "PrimitiveValueVirt::from_value: " << t); switch(t.inner_type) { case RawType::U32: @@ -281,15 +281,18 @@ struct MirHelpers auto idx = get_value_ref(*e.idx).read_usize(0); ::HIR::TypeRef array_ty; auto base_val = get_value_and_type(*e.val, array_ty); - if( array_ty.wrappers.empty() ) + const auto* wrapper = array_ty.get_wrapper(); + if( !wrapper ) + { LOG_ERROR("Indexing non-array/slice - " << array_ty); - if( array_ty.wrappers.front().type == TypeWrapper::Ty::Array ) + } + else if( wrapper->type == TypeWrapper::Ty::Array ) { ty = array_ty.get_inner(); base_val.m_offset += ty.get_size() * idx; return base_val; } - else if( array_ty.wrappers.front().type == TypeWrapper::Ty::Slice ) + else if( wrapper->type == TypeWrapper::Ty::Slice ) { LOG_TODO("Slice index"); } @@ -354,7 +357,7 @@ struct MirHelpers size_t slice_inner_size; if( ty.has_slice_meta(slice_inner_size) ) { - size = (ty.wrappers.empty() ? ty.get_size() : 0) + meta_val->read_usize(0) * slice_inner_size; + size = (ty.get_wrapper() == nullptr ? ty.get_size() : 0) + meta_val->read_usize(0) * slice_inner_size; } //else if( ty == RawType::TraitObject) { // // NOTE: Getting the size from the allocation is semi-valid, as you can't sub-slice trait objects @@ -468,8 +471,7 @@ struct MirHelpers LOG_TODO("Constant::Bytes"); } break; TU_ARM(c, StaticString, ce) { - ty = ::HIR::TypeRef(RawType::Str); - ty.wrappers.push_back(TypeWrapper { TypeWrapper::Ty::Borrow, 0 }); + ty = ::HIR::TypeRef(RawType::Str).wrap(TypeWrapper::Ty::Borrow, 0); Value val = Value(ty); val.write_ptr(0, 0, RelocationPtr::new_string(&ce)); val.write_usize(POINTER_SIZE, ce.size()); @@ -484,8 +486,7 @@ struct MirHelpers return Value::new_fnptr(ce); } if( const auto* s = this->thread.m_modtree.get_static_opt(ce) ) { - ty = s->ty; - ty.wrappers.insert(ty.wrappers.begin(), TypeWrapper { TypeWrapper::Ty::Borrow, 0 }); + ty = s->ty.wrapped(TypeWrapper::Ty::Borrow, 0); return Value::new_pointer(ty, 0, RelocationPtr::new_alloc(s->val.allocation)); } LOG_ERROR("Constant::ItemAddr - " << ce << " - not found"); @@ -602,10 +603,10 @@ bool InterpreterThread::step_one(Value& out_thread_result) LOG_DEBUG("- alloc=" << alloc); size_t ofs = src_base_value.m_offset; const auto meta = src_ty.get_meta_type(); - src_ty.wrappers.insert(src_ty.wrappers.begin(), TypeWrapper { TypeWrapper::Ty::Borrow, static_cast(re.type) }); + auto dst_ty = src_ty.wrapped(TypeWrapper::Ty::Borrow, static_cast(re.type)); // Create the pointer - new_val = Value(src_ty); + new_val = Value(dst_ty); new_val.write_ptr(0, ofs, ::std::move(alloc)); // - Add metadata if required if( meta != RawType::Unreachable ) @@ -626,26 +627,24 @@ bool InterpreterThread::step_one(Value& out_thread_result) // No-op cast new_val = src_value.read_value(0, re.type.get_size()); } - else if( !re.type.wrappers.empty() ) + else if( const auto* dst_w = re.type.get_wrapper() ) { // Destination can only be a raw pointer - if( re.type.wrappers.at(0).type != TypeWrapper::Ty::Pointer ) { - throw "ERROR"; + if( dst_w->type != TypeWrapper::Ty::Pointer ) { + LOG_ERROR("Attempting to cast to a type other than a raw pointer - " << re.type); } - if( !src_ty.wrappers.empty() ) + if( const auto* src_w = src_ty.get_wrapper() ) { // Source can be either - if( src_ty.wrappers.at(0).type != TypeWrapper::Ty::Pointer - && src_ty.wrappers.at(0).type != TypeWrapper::Ty::Borrow ) { - throw "ERROR"; + if( src_w->type != TypeWrapper::Ty::Pointer && src_w->type != TypeWrapper::Ty::Borrow ) { + LOG_ERROR("Attempting to cast to a pointer from a non-pointer - " << src_ty); } - if( src_ty.get_size() > re.type.get_size() ) { - // TODO: How to casting fat to thin? - //LOG_TODO("Handle casting fat to thin, " << src_ty << " -> " << re.type); - new_val = src_value.read_value(0, re.type.get_size()); + if( src_ty.get_size() < re.type.get_size() ) + { + LOG_ERROR("Casting to a fatter pointer, " << src_ty << " -> " << re.type); } - else + else { new_val = src_value.read_value(0, re.type.get_size()); } @@ -660,18 +659,15 @@ bool InterpreterThread::step_one(Value& out_thread_result) } else { - ::std::cerr << "ERROR: Trying to pointer (" << re.type <<" ) from invalid type (" << src_ty << ")\n"; - throw "ERROR"; + LOG_ERROR("Trying to cast to pointer (" << re.type <<" ) from invalid type (" << src_ty << ")\n"); } new_val = src_value.read_value(0, re.type.get_size()); } } - else if( !src_ty.wrappers.empty() ) + else if( const auto* src_w = src_ty.get_wrapper() ) { - // TODO: top wrapper MUST be a pointer - if( src_ty.wrappers.at(0).type != TypeWrapper::Ty::Pointer - && src_ty.wrappers.at(0).type != TypeWrapper::Ty::Borrow ) { - throw "ERROR"; + if( src_w->type != TypeWrapper::Ty::Pointer && src_w->type != TypeWrapper::Ty::Borrow ) { + LOG_ERROR("Attempting to cast to a non-pointer - " << src_ty); } // TODO: MUST be a thin pointer? @@ -802,7 +798,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) LOG_ASSERT(dt.variants[i].field_path.empty(), ""); } ::HIR::TypeRef tag_ty = dt.fields[0].second; - LOG_ASSERT(tag_ty.wrappers.empty(), ""); + LOG_ASSERT(tag_ty.get_wrapper() == nullptr, ""); switch(tag_ty.inner_type) { case RawType::USize: @@ -954,7 +950,33 @@ bool InterpreterThread::step_one(Value& out_thread_result) } LOG_DEBUG("res=" << res << ", " << reloc_l << " ? " << reloc_r); - if( ty_l.wrappers.empty() ) + if( const auto* w = ty_l.get_wrapper() ) + { + if( w->type == TypeWrapper::Ty::Pointer ) + { + // TODO: Technically only EQ/NE are valid. + + res = res != 0 ? res : Ops::do_compare(v_l.read_usize(0), v_r.read_usize(0)); + + // Compare fat metadata. + if( res == 0 && v_l.m_size > POINTER_SIZE ) + { + reloc_l = v_l.get_relocation(POINTER_SIZE); + reloc_r = v_r.get_relocation(POINTER_SIZE); + + if( res == 0 && reloc_l != reloc_r ) + { + res = (reloc_l < reloc_r ? -1 : 1); + } + res = res != 0 ? res : Ops::do_compare(v_l.read_usize(POINTER_SIZE), v_r.read_usize(POINTER_SIZE)); + } + } + else + { + LOG_TODO("BinOp comparisons - " << se.src << " w/ " << ty_l); + } + } + else { switch(ty_l.inner_type) { @@ -972,29 +994,6 @@ bool InterpreterThread::step_one(Value& out_thread_result) LOG_TODO("BinOp comparisons - " << se.src << " w/ " << ty_l); } } - else if( ty_l.wrappers.front().type == TypeWrapper::Ty::Pointer ) - { - // TODO: Technically only EQ/NE are valid. - - res = res != 0 ? res : Ops::do_compare(v_l.read_usize(0), v_r.read_usize(0)); - - // Compare fat metadata. - if( res == 0 && v_l.m_size > POINTER_SIZE ) - { - reloc_l = v_l.get_relocation(POINTER_SIZE); - reloc_r = v_r.get_relocation(POINTER_SIZE); - - if( res == 0 && reloc_l != reloc_r ) - { - res = (reloc_l < reloc_r ? -1 : 1); - } - res = res != 0 ? res : Ops::do_compare(v_l.read_usize(POINTER_SIZE), v_r.read_usize(POINTER_SIZE)); - } - } - else - { - LOG_TODO("BinOp comparisons - " << se.src << " w/ " << ty_l); - } bool res_bool; switch(re.op) { @@ -1013,8 +1012,8 @@ bool InterpreterThread::step_one(Value& out_thread_result) } break; case ::MIR::eBinOp::BIT_SHL: case ::MIR::eBinOp::BIT_SHR: { - LOG_ASSERT(ty_l.wrappers.empty(), "Bitwise operator on non-primitive - " << ty_l); - LOG_ASSERT(ty_r.wrappers.empty(), "Bitwise operator with non-primitive - " << ty_r); + LOG_ASSERT(ty_l.get_wrapper() == nullptr, "Bitwise operator on non-primitive - " << ty_l); + LOG_ASSERT(ty_r.get_wrapper() == nullptr, "Bitwise operator with non-primitive - " << ty_r); size_t max_bits = ty_r.get_size() * 8; uint8_t shift; auto check_cast = [&](auto v){ LOG_ASSERT(0 <= v && v <= max_bits, "Shift out of range - " << v); return static_cast(v); }; @@ -1051,7 +1050,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) case ::MIR::eBinOp::BIT_OR: case ::MIR::eBinOp::BIT_XOR: LOG_ASSERT(ty_l == ty_r, "BinOp type mismatch - " << ty_l << " != " << ty_r); - LOG_ASSERT(ty_l.wrappers.empty(), "Bitwise operator on non-primitive - " << ty_l); + LOG_ASSERT(ty_l.get_wrapper() == nullptr, "Bitwise operator on non-primitive - " << ty_l); new_val = Value(ty_l); switch(ty_l.inner_type) { @@ -1104,7 +1103,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) TU_ARM(se.src, UniOp, re) { ::HIR::TypeRef ty; auto v = state.get_value_and_type(re.val, ty); - LOG_ASSERT(ty.wrappers.empty(), "UniOp on wrapped type - " << ty); + LOG_ASSERT(ty.get_wrapper() == nullptr, "UniOp on wrapped type - " << ty); new_val = Value(ty); switch(re.op) { @@ -1238,7 +1237,6 @@ bool InterpreterThread::step_one(Value& out_thread_result) const auto& data_ty = this->m_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) @@ -1250,7 +1248,6 @@ bool InterpreterThread::step_one(Value& out_thread_result) 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; @@ -1279,7 +1276,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) } } break; } - LOG_DEBUG("- " << new_val); + LOG_DEBUG("- new_val=" << new_val); state.write_lvalue(se.dst, ::std::move(new_val)); } break; case ::MIR::Statement::TAG_Asm: @@ -1352,8 +1349,8 @@ bool InterpreterThread::step_one(Value& out_thread_result) TU_ARM(bb.terminator, Switch, te) { ::HIR::TypeRef ty; auto v = state.get_value_and_type(te.val, ty); - LOG_ASSERT(ty.wrappers.size() == 0, "" << ty); - LOG_ASSERT(ty.inner_type == RawType::Composite, "" << ty); + LOG_ASSERT(ty.get_wrapper() == nullptr, "Matching on wrapped value - " << ty); + LOG_ASSERT(ty.inner_type == RawType::Composite, "Matching on non-coposite - " << ty); // TODO: Convert the variant list into something that makes it easier to switch on. size_t found_target = SIZE_MAX; @@ -1578,8 +1575,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c auto size = args.at(0).read_usize(0); auto align = args.at(1).read_usize(0); LOG_DEBUG("__rust_allocate(size=" << size << ", align=" << align << ")"); - ::HIR::TypeRef rty { RawType::Unit }; - rty.wrappers.push_back({ TypeWrapper::Ty::Pointer, 0 }); + auto rty = ::HIR::TypeRef(RawType::Unit).wrap( TypeWrapper::Ty::Pointer, 0 ); // TODO: Use the alignment when making an allocation? rv = Value::new_pointer(rty, 0, RelocationPtr::new_alloc(Allocation::new_alloc(size))); @@ -2051,14 +2047,14 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con // Get unsized type somehow. // - _HAS_ to be the last type, so that makes it easier size_t fixed_size = 0; - if( const auto* ity = ty.get_usized_type(fixed_size) ) + if( const auto* ity = ty.get_unsized_type(fixed_size) ) { const auto meta_ty = ty.get_meta_type(); LOG_DEBUG("size_of_val - " << ty << " ity=" << *ity << " meta_ty=" << meta_ty << " fixed_size=" << fixed_size); size_t flex_size = 0; - if( !ity->wrappers.empty() ) + if( const auto* w = ity->get_wrapper() ) { - LOG_ASSERT(ity->wrappers[0].type == TypeWrapper::Ty::Slice, ""); + LOG_ASSERT(w->type == TypeWrapper::Ty::Slice, "size_of_val on wrapped type that isn't a slice - " << *ity); size_t item_size = ity->get_inner().get_size(); size_t item_count = val.read_usize(POINTER_SIZE); flex_size = item_count * item_size; @@ -2088,40 +2084,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con { auto& val = args.at(0); const auto& ty = ty_params.tys.at(0); - if( !ty.wrappers.empty() ) - { - size_t item_count = 0; - switch(ty.wrappers[0].type) - { - case TypeWrapper::Ty::Slice: - case TypeWrapper::Ty::Array: - item_count = (ty.wrappers[0].type == TypeWrapper::Ty::Slice ? val.read_usize(POINTER_SIZE) : ty.wrappers[0].size); - break; - case TypeWrapper::Ty::Pointer: - break; - case TypeWrapper::Ty::Borrow: - // TODO: Only &move has a destructor - break; - } - LOG_ASSERT(ty.wrappers[0].type == TypeWrapper::Ty::Slice, "drop_in_place should only exist for slices - " << ty); - const auto& ity = ty.get_inner(); - size_t item_size = ity.get_size(); - - auto ptr = val.read_value(0, POINTER_SIZE); - for(size_t i = 0; i < item_count; i ++) - { - // TODO: Nested calls? - if( !drop_value(ptr, ity) ) - { - LOG_DEBUG("Handle multiple queued calls"); - } - ptr.write_usize(0, ptr.read_usize(0) + item_size); - } - } - else - { - return drop_value(val, ty); - } + return drop_value(val, ty); } // ---------------------------------------------------------------- // Checked arithmatic @@ -2249,12 +2212,55 @@ bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_ if( ofs != 0 || !alloc || !alloc.is_alloc() ) { LOG_ERROR("Attempting to shallow drop with invalid pointer (no relocation or non-zero offset) - " << box_ptr_vr); } - + LOG_DEBUG("drop_value SHALLOW deallocate " << alloc); alloc.alloc().mark_as_freed(); return true; } - if( ty.wrappers.empty() ) + if( const auto* w = ty.get_wrapper() ) + { + switch( w->type ) + { + case TypeWrapper::Ty::Borrow: + if( w->size == static_cast(::HIR::BorrowType::Move) ) + { + LOG_TODO("Drop - " << ty << " - dereference and go to inner"); + // TODO: Clear validity on the entire inner value. + //auto iptr = ptr.read_value(0, ty.get_size()); + //drop_value(iptr, ty.get_inner()); + } + else + { + // No destructor + } + break; + case TypeWrapper::Ty::Pointer: + // No destructor + break; + case TypeWrapper::Ty::Slice: { + // - Get thin pointer and count + auto ofs = ptr.read_usize(0); + auto ptr_reloc = ptr.get_relocation(0); + auto count = ptr.read_usize(POINTER_SIZE); + + auto ity = ty.get_inner(); + auto pty = ity.wrapped(TypeWrapper::Ty::Borrow, static_cast(::HIR::BorrowType::Move)); + for(uint64_t i = 0; i < count; i ++) + { + auto ptr = Value::new_pointer(pty, ofs, ptr_reloc); + if( !drop_value(ptr, ity) ) { + LOG_TODO("Handle closure looping when dropping a slice"); + } + ofs += ity.get_size(); + } + } break; + // TODO: Arrays? + default: + LOG_TODO("Drop - " << ty << " - array?"); + break; + } + } + else { if( ty.inner_type == RawType::Composite ) { @@ -2279,29 +2285,5 @@ bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_ // No destructor } } - else - { - switch( ty.wrappers[0].type ) - { - case TypeWrapper::Ty::Borrow: - if( ty.wrappers[0].size == static_cast(::HIR::BorrowType::Move) ) - { - LOG_TODO("Drop - " << ty << " - dereference and go to inner"); - // TODO: Clear validity on the entire inner value. - } - else - { - // No destructor - } - break; - case TypeWrapper::Ty::Pointer: - // No destructor - break; - // TODO: Arrays - default: - LOG_TODO("Drop - " << ty << " - array?"); - break; - } - } return true; } diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index cb6f943d..db5fd495 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -266,7 +266,7 @@ bool Parser::parse_one() //const auto* tag_ty = &rv.fields.at(base_idx).second; //for(auto idx : other_idx) //{ - // assert(tag_ty->wrappers.size() == 0); + // assert(tag_ty->get_wrapper() == nullptr); // assert(tag_ty->inner_type == RawType::Composite); // LOG_TODO(lex << "Calculate tag offset with nested tag - " << idx << " ty=" << *tag_ty); //} @@ -1130,14 +1130,14 @@ RawType Parser::parse_core_type() { size_t size = lex.next().integer(); lex.consume(); - rv.wrappers.insert( rv.wrappers.begin(), { TypeWrapper::Ty::Array, size }); + lex.check_consume(']'); + return ::std::move(rv).wrap( TypeWrapper::Ty::Array, size ); } else { - rv.wrappers.insert( rv.wrappers.begin(), { TypeWrapper::Ty::Slice, 0 }); + lex.check_consume(']'); + return ::std::move(rv).wrap( TypeWrapper::Ty::Slice, 0 ); } - lex.check_consume(']'); - return rv; } else if( lex.consume_if('!') ) { @@ -1152,9 +1152,7 @@ RawType Parser::parse_core_type() bt = ::HIR::BorrowType::Unique; else ; // keep as shared - auto rv = parse_type(); - rv.wrappers.insert( rv.wrappers.begin(), { TypeWrapper::Ty::Borrow, static_cast(bt) }); - return rv; + return parse_type().wrap( TypeWrapper::Ty::Borrow, static_cast(bt) ); } else if( lex.consume_if('*') ) { @@ -1167,9 +1165,7 @@ RawType Parser::parse_core_type() ; // keep as shared else throw "ERROR"; - auto rv = parse_type(); - rv.wrappers.insert( rv.wrappers.begin(), { TypeWrapper::Ty::Pointer, static_cast(bt) }); - return rv; + return parse_type().wrap( TypeWrapper::Ty::Pointer, static_cast(bt) ); } else if( lex.next() == "::" ) { diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index c1098d1d..cf378077 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -545,38 +545,12 @@ Value::Value() 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->direct_data.data) ) { - struct H - { - static bool has_pointer(const ::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 ) - { - return false; - } - // Still not sure, check the inner for any pointers. - for(const auto& fld : ty.composite_type->fields) - { - if( H::has_pointer(fld.second) ) - return true; - } - return false; - } - return true; - } - }; - if( ! H::has_pointer(ty) ) + // AND the type doesn't contain a pointer (of any kind) + if( ! ty.has_pointer() ) { // Will fit in a inline allocation, nice. //LOG_TRACE("No pointers in " << ty << ", storing inline"); @@ -586,7 +560,6 @@ Value::Value(::HIR::TypeRef ty) return ; } } -#endif // Fallback: Make a new allocation //LOG_TRACE(" Creating allocation for " << ty); @@ -626,8 +599,8 @@ Value Value::new_ffiptr(FFIPointer ffi) return rv; } Value Value::new_pointer(::HIR::TypeRef ty, uint64_t v, RelocationPtr r) { - assert(!ty.wrappers.empty()); - assert(ty.wrappers[0].type == TypeWrapper::Ty::Borrow || ty.wrappers[0].type == TypeWrapper::Ty::Pointer); + assert(ty.get_wrapper()); + assert(ty.get_wrapper()->type == TypeWrapper::Ty::Borrow || ty.get_wrapper()->type == TypeWrapper::Ty::Pointer); Value rv(ty); rv.write_usize(0, v); rv.allocation->relocations.push_back(Relocation { 0, /*POINTER_SIZE,*/ ::std::move(r) }); -- cgit v1.2.3 From ada4bdefc7da9c81e0006553f218efe56a4349ce Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 3 Jun 2018 13:06:12 +0800 Subject: Standalone MIRI - Fix parse errors from mrustc changes, add recursion limit --- test_smiri.sh | 1 + tools/standalone_miri/debug.cpp | 3 ++- tools/standalone_miri/debug.hpp | 2 +- tools/standalone_miri/lex.cpp | 25 +++++++++++++++++++++++-- tools/standalone_miri/lex.hpp | 1 + tools/standalone_miri/main.cpp | 23 ++++++++++++++++++++++- tools/standalone_miri/miri.cpp | 22 ++++++++++++++++++---- tools/standalone_miri/module_tree.cpp | 18 +++++++++++++++--- 8 files changed, 83 insertions(+), 12 deletions(-) (limited to 'tools/standalone_miri/module_tree.cpp') diff --git a/test_smiri.sh b/test_smiri.sh index 0dbad3fa..a275420a 100755 --- a/test_smiri.sh +++ b/test_smiri.sh @@ -2,6 +2,7 @@ set -e cd $(dirname $0) make -f minicargo.mk MMIR=1 LIBS +make -C tools/standalone_miri echo "--- mrustc -o output-mmir/hello" ./bin/mrustc rustc-1.19.0-src/src/test/run-pass/hello.rs -O -C codegen-type=monomir -o output-mmir/hello -L output-mmir/ > output-mmir/hello_dbg.txt echo "--- standalone_miri output-mmir/hello.mir" diff --git a/tools/standalone_miri/debug.cpp b/tools/standalone_miri/debug.cpp index f0476df7..c49df960 100644 --- a/tools/standalone_miri/debug.cpp +++ b/tools/standalone_miri/debug.cpp @@ -18,8 +18,9 @@ DebugSink::DebugSink(::std::ostream& inner): DebugSink::~DebugSink() { m_inner << "\n"; + m_inner.flush(); } -bool DebugSink::set_output_file(const ::std::string& s) +void DebugSink::set_output_file(const ::std::string& s) { s_out_file.reset(new ::std::ofstream(s)); } diff --git a/tools/standalone_miri/debug.hpp b/tools/standalone_miri/debug.hpp index 6b136ccb..b3b0d76f 100644 --- a/tools/standalone_miri/debug.hpp +++ b/tools/standalone_miri/debug.hpp @@ -33,7 +33,7 @@ public: template ::std::ostream& operator<<(const T& v) { return m_inner << v; } - static bool set_output_file(const ::std::string& s); + static void set_output_file(const ::std::string& s); static bool enabled(const char* fcn_name); static DebugSink get(const char* fcn_name, const char* file, unsigned line, DebugLevel lvl); // TODO: Add a way to insert an annotation before/after an abort/warning/... that indicates what input location caused it. diff --git a/tools/standalone_miri/lex.cpp b/tools/standalone_miri/lex.cpp index 7cfe1a78..8fc77f7a 100644 --- a/tools/standalone_miri/lex.cpp +++ b/tools/standalone_miri/lex.cpp @@ -11,11 +11,11 @@ bool Token::operator==(TokenClass tc) const } bool Token::operator==(char c) const { - return this->strval.size() == 1 && this->strval[0] == c; + return (this->type == TokenClass::Ident || this->type == TokenClass::Symbol) && this->strval.size() == 1 && this->strval[0] == c; } bool Token::operator==(const char* s) const { - return this->strval == s; + return (this->type == TokenClass::Ident || this->type == TokenClass::Symbol) && this->strval == s; } uint64_t Token::integer() const @@ -56,6 +56,9 @@ double Token::real() const case TokenClass::ByteString: os << "b\"" << x.strval << "\""; break; + case TokenClass::Lifetime: + os << "'" << x.strval << "\""; + break; } return os; } @@ -95,6 +98,7 @@ Token Lexer::consume() auto rv = ::std::move(m_cur); advance(); + //::std::cout << *this << "Lexer::consume " << rv << " -> " << m_cur << ::std::endl; return rv; } @@ -349,6 +353,23 @@ void Lexer::advance() auto val = this->parse_string(); m_cur = Token { TokenClass::String, ::std::move(val) }; } + else if( ch == '\'') + { + ::std::string val; + ch = m_if.get(); + while( ch == '_' || ::std::isalnum(ch) ) + { + val += ch; + ch = m_if.get(); + } + m_if.unget(); + if( val == "" ) + { + ::std::cerr << *this << "Empty lifetime name"; + throw "ERROR"; + } + m_cur = Token { TokenClass::Lifetime, ::std::move(val) }; + } else { switch(ch) diff --git a/tools/standalone_miri/lex.hpp b/tools/standalone_miri/lex.hpp index 95130111..cc1429f7 100644 --- a/tools/standalone_miri/lex.hpp +++ b/tools/standalone_miri/lex.hpp @@ -14,6 +14,7 @@ enum class TokenClass Real, String, ByteString, + Lifetime, }; struct Token diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index 90b5eff3..deed08be 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -48,7 +48,28 @@ int main(int argc, const char* argv[]) // Load HIR tree auto tree = ModuleTree {}; - tree.load_file(opts.infile); + try + { + tree.load_file(opts.infile); + } + catch(const DebugExceptionTodo& /*e*/) + { + ::std::cerr << "TODO Hit" << ::std::endl; + if(opts.logfile != "") + { + ::std::cerr << "- See '" << opts.logfile << "' for details" << ::std::endl; + } + return 1; + } + catch(const DebugExceptionError& /*e*/) + { + ::std::cerr << "Error encountered" << ::std::endl; + if(opts.logfile != "") + { + ::std::cerr << "- See '" << opts.logfile << "' for details" << ::std::endl; + } + return 1; + } // Create argc/argv based on input arguments auto argv_alloc = Allocation::new_alloc((1 + opts.args.size()) * POINTER_SIZE); diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 5f9c095f..f4179b5d 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -540,11 +540,19 @@ InterpreterThread::~InterpreterThread() for(size_t i = 0; i < m_stack.size(); i++) { const auto& frame = m_stack[m_stack.size() - 1 - i]; - ::std::cout << "#" << i << ": " << frame.fcn.my_path << " BB" << frame.bb_idx << "/"; - if( frame.stmt_idx == frame.fcn.m_mir.blocks.at(frame.bb_idx).statements.size() ) - ::std::cout << "TERM"; + ::std::cout << "#" << i << ": "; + if( frame.cb ) + { + ::std::cout << "WRAPPER"; + } else - ::std::cout << frame.stmt_idx; + { + ::std::cout << frame.fcn.my_path << " BB" << frame.bb_idx << "/"; + if( frame.stmt_idx == frame.fcn.m_mir.blocks.at(frame.bb_idx).statements.size() ) + ::std::cout << "TERM"; + else + ::std::cout << frame.stmt_idx; + } ::std::cout << ::std::endl; } } @@ -565,6 +573,12 @@ bool InterpreterThread::step_one(Value& out_thread_result) TRACE_FUNCTION_R(cur_frame.fcn.my_path, ""); const auto& bb = cur_frame.fcn.m_mir.blocks.at( cur_frame.bb_idx ); + const size_t MAX_STACK_DEPTH = 40; + if( this->m_stack.size() > MAX_STACK_DEPTH ) + { + LOG_ERROR("Maximum stack depth of " << MAX_STACK_DEPTH << " exceeded"); + } + MirHelpers state { *this, cur_frame }; if( cur_frame.stmt_idx < bb.statements.size() ) diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index db5fd495..8beba018 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -56,7 +56,7 @@ void ModuleTree::load_file(const ::std::string& path) bool Parser::parse_one() { //TRACE_FUNCTION_F(""); - if( lex.next() == "" ) // EOF? + if( lex.next() == TokenClass::Eof ) { return false; } @@ -1145,6 +1145,11 @@ RawType Parser::parse_core_type() } else if( lex.consume_if('&') ) { + if( lex.next() == TokenClass::Lifetime ) + { + // TODO: Handle lifetime names (require them?) + lex.consume(); + } auto bt = ::HIR::BorrowType::Shared; if( lex.consume_if("move") ) bt = ::HIR::BorrowType::Move; @@ -1240,8 +1245,15 @@ RawType Parser::parse_core_type() ::std::vector<::HIR::GenericPath> markers; while(lex.consume_if('+')) { - // TODO: Detect/parse lifetimes? - markers.push_back(parse_genericpath()); + if( lex.next() == TokenClass::Lifetime ) + { + // TODO: Include lifetimes in output? + lex.consume(); + } + else + { + markers.push_back(parse_genericpath()); + } } lex.consume_if(')'); -- cgit v1.2.3